Support parsing and testing unimplemented expressions (#957)

Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
This commit is contained in:
Geoff Romer
2021-11-30 12:29:15 -08:00
committed by GitHub
co-authored by Jon Meow
parent be0c1e9da6
commit dc5e62fc7a
23 changed files with 463 additions and 147 deletions
+1
View File
@@ -44,6 +44,7 @@ cc_library(
],
hdrs = ["ast_test_matchers.h"],
deps = [
":ast",
":ast_node",
":declaration",
":expression",
+3
View File
@@ -45,6 +45,9 @@ class AstNode {
auto operator=(AstNode&&) -> AstNode& = delete;
virtual ~AstNode() = 0;
virtual void Print(llvm::raw_ostream& out) const = 0;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
// Returns an enumerator specifying the concrete type of this node.
//
// Abstract subclasses of AstNode will provide their own `kind()` method
+1
View File
@@ -50,5 +50,6 @@ abstract class Expression : AstNode;
class TypeTypeLiteral : Expression;
class IdentifierExpression : Expression;
class IntrinsicExpression : Expression;
class UnimplementedExpression : Expression;
abstract class Member : AstNode;
class FieldMember : Member, NamedEntity;
+30 -21
View File
@@ -25,15 +25,13 @@ namespace Carbon {
// Matches a Block node whose .statements() match `matcher`.
inline auto BlockContentsAre(
::testing::Matcher<llvm::ArrayRef<Nonnull<const Statement*>>> matcher)
-> TestingInternal::BlockContentsMatcher {
::testing::Matcher<llvm::ArrayRef<Nonnull<const Statement*>>> matcher) {
return TestingInternal::BlockContentsMatcher(std::move(matcher));
}
// Matches a literal with the given value.
// TODO: add overload for string literals
inline auto MatchesLiteral(int value)
-> TestingInternal::MatchesIntLiteralMatcher {
inline auto MatchesLiteral(int value) {
return TestingInternal::MatchesIntLiteralMatcher(value);
}
@@ -41,55 +39,48 @@ inline auto MatchesLiteral(int value)
// operands that match `lhs` and `rhs` (respectively). The name of the function
// indicates what value of `.op()` they match.
inline auto MatchesMul(::testing::Matcher<AstNode> lhs,
::testing::Matcher<AstNode> rhs)
-> TestingInternal::BinaryOperatorExpressionMatcher {
::testing::Matcher<AstNode> rhs) {
return TestingInternal::BinaryOperatorExpressionMatcher(
Operator::Mul, std::move(lhs), std::move(rhs));
}
inline auto MatchesAdd(::testing::Matcher<AstNode> lhs,
::testing::Matcher<AstNode> rhs)
-> TestingInternal::BinaryOperatorExpressionMatcher {
::testing::Matcher<AstNode> rhs) {
return TestingInternal::BinaryOperatorExpressionMatcher(
Operator::Add, std::move(lhs), std::move(rhs));
}
inline auto MatchesAnd(::testing::Matcher<AstNode> lhs,
::testing::Matcher<AstNode> rhs)
-> TestingInternal::BinaryOperatorExpressionMatcher {
::testing::Matcher<AstNode> rhs) {
return TestingInternal::BinaryOperatorExpressionMatcher(
Operator::And, std::move(lhs), std::move(rhs));
}
inline auto MatchesEq(::testing::Matcher<AstNode> lhs,
::testing::Matcher<AstNode> rhs)
-> TestingInternal::BinaryOperatorExpressionMatcher {
::testing::Matcher<AstNode> rhs) {
return TestingInternal::BinaryOperatorExpressionMatcher(
Operator::Eq, std::move(lhs), std::move(rhs));
}
inline auto MatchesOr(::testing::Matcher<AstNode> lhs,
::testing::Matcher<AstNode> rhs)
-> TestingInternal::BinaryOperatorExpressionMatcher {
::testing::Matcher<AstNode> rhs) {
return TestingInternal::BinaryOperatorExpressionMatcher(
Operator::Or, std::move(lhs), std::move(rhs));
}
inline auto MatchesSub(::testing::Matcher<AstNode> lhs,
::testing::Matcher<AstNode> rhs)
-> TestingInternal::BinaryOperatorExpressionMatcher {
::testing::Matcher<AstNode> rhs) {
return TestingInternal::BinaryOperatorExpressionMatcher(
Operator::Sub, std::move(lhs), std::move(rhs));
}
// Matches a return statement with no operand.
inline auto MatchesEmptyReturn() -> TestingInternal::MatchesReturnMatcher {
inline auto MatchesEmptyReturn() {
return TestingInternal::MatchesReturnMatcher();
}
// Matches a return statement with an explicit operand that matches `matcher`.
inline auto MatchesReturn(::testing::Matcher<AstNode> matcher)
-> TestingInternal::MatchesReturnMatcher {
inline auto MatchesReturn(::testing::Matcher<AstNode> matcher) {
return TestingInternal::MatchesReturnMatcher(matcher);
}
@@ -113,11 +104,29 @@ inline auto MatchesReturn(::testing::Matcher<AstNode> matcher)
// TODO: Add method for matching only if the declaration has no body.
// TODO: Add methods for matching parameters, deduced parameters,
// and return term.
inline auto MatchesFunctionDeclaration()
-> TestingInternal::MatchesFunctionDeclarationMatcher {
inline auto MatchesFunctionDeclaration() {
return TestingInternal::MatchesFunctionDeclarationMatcher();
}
// Matches an UnimplementedExpression with the given label, whose children
// match `children_matcher`.
inline auto MatchesUnimplementedExpression(
std::string label,
::testing::Matcher<llvm::ArrayRef<Nonnull<const AstNode*>>>
children_matcher) {
return TestingInternal::MatchesUnimplementedExpressionMatcher(
std::move(label), std::move(children_matcher));
}
// Matches an `AST` whose declarations match the given matcher. Unlike other
// matchers in this file, this matcher does not match pointers.
inline auto ASTDeclarations(
::testing::Matcher<std::vector<Nonnull<Declaration*>>>
declarations_matcher) {
return TestingInternal::ASTDeclarationsMatcher(
std::move(declarations_matcher));
}
} // namespace Carbon
#endif // EXECUTABLE_SEMANTICS_AST_AST_TEST_MATCHERS_H_
@@ -10,7 +10,9 @@
namespace Carbon {
namespace TestingInternal {
auto BlockContentsMatcher::MatchAndExplain(
AstNodeMatcherBase::~AstNodeMatcherBase() = default;
auto BlockContentsMatcher::MatchAndExplainImpl(
Nonnull<const AstNode*> node, ::testing::MatchResultListener* out) const
-> bool {
const auto* block = llvm::dyn_cast<Block>(node);
@@ -22,7 +24,7 @@ auto BlockContentsMatcher::MatchAndExplain(
return matcher_.MatchAndExplain(block->statements(), out);
}
auto MatchesIntLiteralMatcher::MatchAndExplain(
auto MatchesIntLiteralMatcher::MatchAndExplainImpl(
const AstNode* node, ::testing::MatchResultListener* listener) const
-> bool {
const auto* literal = llvm::dyn_cast<IntLiteral>(node);
@@ -35,7 +37,7 @@ auto MatchesIntLiteralMatcher::MatchAndExplain(
return matched;
}
auto BinaryOperatorExpressionMatcher::MatchAndExplain(
auto BinaryOperatorExpressionMatcher::MatchAndExplainImpl(
Nonnull<const AstNode*> node, ::testing::MatchResultListener* out) const
-> bool {
const auto* op = llvm::dyn_cast<PrimitiveOperatorExpression>(node);
@@ -70,7 +72,7 @@ void BinaryOperatorExpressionMatcher::DescribeToImpl(std::ostream* out,
rhs_.DescribeTo(out);
}
auto MatchesReturnMatcher::MatchAndExplain(
auto MatchesReturnMatcher::MatchAndExplainImpl(
const AstNode* node, ::testing::MatchResultListener* listener) const
-> bool {
const auto* ret = llvm::dyn_cast<Return>(node);
@@ -135,7 +137,7 @@ class RawListenerOstream : public llvm::raw_ostream {
};
} // namespace
auto MatchesFunctionDeclarationMatcher::MatchAndExplain(
auto MatchesFunctionDeclarationMatcher::MatchAndExplainImpl(
const AstNode* node, ::testing::MatchResultListener* listener) const
-> bool {
RawListenerOstream out(listener);
@@ -185,5 +187,28 @@ void MatchesFunctionDeclarationMatcher::DescribeToImpl(std::ostream* out,
}
}
auto MatchesUnimplementedExpressionMatcher::MatchAndExplainImpl(
const AstNode* node, ::testing::MatchResultListener* listener) const
-> bool {
const auto* unimplemented = llvm::dyn_cast<UnimplementedExpression>(node);
if (unimplemented == nullptr) {
*listener << "is not an UnimplementedExpression";
return false;
}
if (unimplemented->label() != label_) {
*listener << "is not labeled " << label_;
return false;
}
*listener << "is an unimplemented " << label_ << " node whose children ";
return children_matcher_.MatchAndExplain(unimplemented->children(), listener);
}
void MatchesUnimplementedExpressionMatcher::DescribeToImpl(std::ostream* out,
bool negated) const {
*out << "is " << (negated ? "not " : "") << "an unimplemented " << label_
<< " node whose children ";
children_matcher_.DescribeTo(out);
}
} // namespace TestingInternal
} // namespace Carbon
@@ -12,6 +12,7 @@
#include <ostream>
#include "executable_semantics/ast/ast.h"
#include "executable_semantics/ast/ast_node.h"
#include "executable_semantics/ast/declaration.h"
#include "executable_semantics/ast/expression.h"
@@ -21,46 +22,15 @@
namespace Carbon {
namespace TestingInternal {
// Matches a Block based on its contents.
class BlockContentsMatcher {
// Abstract GoogleMock matcher which matches AstNodes, and is agnostic to
// whether they are passed by pointer or reference. Derived classes specify what
// kinds of AstNodes they match by overriding DescribeToImpl and
// MatchAndExplainImpl.
class AstNodeMatcherBase {
public:
using is_gtest_matcher = void;
// Constructs a matcher which matches a Block node whose .statements() matches
// `matcher`.
explicit BlockContentsMatcher(
::testing::Matcher<llvm::ArrayRef<Nonnull<const Statement*>>> matcher)
: matcher_(std::move(matcher)) {}
void DescribeTo(std::ostream* out) const {
*out << "is a Block whose statements collection ";
matcher_.DescribeTo(out);
}
void DescribeNegationTo(std::ostream* out) const {
*out << "is not a Block whose statements collection ";
matcher_.DescribeTo(out);
}
auto MatchAndExplain(const AstNode& node,
::testing::MatchResultListener* out) const -> bool {
return MatchAndExplain(&node, out);
}
auto MatchAndExplain(Nonnull<const AstNode*> node,
::testing::MatchResultListener* out) const -> bool;
private:
testing::Matcher<llvm::ArrayRef<Nonnull<const Statement*>>> matcher_;
};
// Matches an IntLiteral.
class MatchesIntLiteralMatcher {
public:
using is_gtest_matcher = void;
// Constructs a matcher which matches an IntLiteral whose value() is `value`.
explicit MatchesIntLiteralMatcher(int value) : value_(value) {}
virtual ~AstNodeMatcherBase();
void DescribeTo(std::ostream* out) const {
DescribeToImpl(out, /*negated=*/false);
@@ -71,26 +41,72 @@ class MatchesIntLiteralMatcher {
}
auto MatchAndExplain(const AstNode& node,
::testing::MatchResultListener* listener) const -> bool {
return MatchAndExplain(&node, listener);
::testing::MatchResultListener* out) const -> bool {
return MatchAndExplainImpl(&node, out);
}
auto MatchAndExplain(const AstNode* node,
::testing::MatchResultListener* listener) const -> bool;
auto MatchAndExplain(Nonnull<const AstNode*> node,
::testing::MatchResultListener* out) const -> bool {
return MatchAndExplainImpl(node, out);
}
private:
void DescribeToImpl(std::ostream* out, bool negated) const {
// The implementation of this method must satisfy the contract of
// `DescribeTo(out)` (as specified by GoogleMock) if `negated` is false,
// or the contract of `DescribeNegationTo(out)` if `negated` is true.
virtual void DescribeToImpl(std::ostream* out, bool negated) const = 0;
// The implementation of this method must satisfy the contract of
// `MatchAndExplain(node, out)`, as specified by GoogleMock.
virtual auto MatchAndExplainImpl(Nonnull<const AstNode*> node,
::testing::MatchResultListener* out) const
-> bool = 0;
};
// Matches a Block based on its contents.
class BlockContentsMatcher : public AstNodeMatcherBase {
public:
// Constructs a matcher which matches a Block node whose .statements() matches
// `matcher`.
explicit BlockContentsMatcher(
::testing::Matcher<llvm::ArrayRef<Nonnull<const Statement*>>> matcher)
: matcher_(std::move(matcher)) {}
private:
void DescribeToImpl(std::ostream* out, bool negated) const override {
*out << "is " << (negated ? "not " : "")
<< "a Block whose statements collection ";
matcher_.DescribeTo(out);
}
auto MatchAndExplainImpl(Nonnull<const AstNode*> node,
::testing::MatchResultListener* out) const
-> bool override;
testing::Matcher<llvm::ArrayRef<Nonnull<const Statement*>>> matcher_;
};
// Matches an IntLiteral.
class MatchesIntLiteralMatcher : public AstNodeMatcherBase {
public:
// Constructs a matcher which matches an IntLiteral whose value() is `value`.
explicit MatchesIntLiteralMatcher(int value) : value_(value) {}
private:
void DescribeToImpl(std::ostream* out, bool negated) const override {
*out << "is " << (negated ? "not " : "") << "a literal " << value_;
}
auto MatchAndExplainImpl(const AstNode* node,
::testing::MatchResultListener* listener) const
-> bool override;
int value_;
};
// Matches a PrimitiveOperatorExpression that has two operands.
class BinaryOperatorExpressionMatcher {
class BinaryOperatorExpressionMatcher : public AstNodeMatcherBase {
public:
using is_gtest_matcher = void;
// Constructs a matcher which matches a PrimitiveOperatorExpression whose
// operator is `op`, and which has two operands that match `lhs` and `rhs`
// respectively.
@@ -99,24 +115,12 @@ class BinaryOperatorExpressionMatcher {
::testing::Matcher<AstNode> rhs)
: op_(op), lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
void DescribeTo(std::ostream* out) const {
DescribeToImpl(out, /*negated=*/false);
}
void DescribeNegationTo(std::ostream* out) const {
DescribeToImpl(out, /*negated=*/true);
}
auto MatchAndExplain(const AstNode& node,
::testing::MatchResultListener* out) const -> bool {
return MatchAndExplain(&node, out);
}
auto MatchAndExplain(Nonnull<const AstNode*> node,
::testing::MatchResultListener* out) const -> bool;
private:
void DescribeToImpl(std::ostream* out, bool negated) const;
void DescribeToImpl(std::ostream* out, bool negated) const override;
auto MatchAndExplainImpl(Nonnull<const AstNode*> node,
::testing::MatchResultListener* out) const
-> bool override;
Operator op_;
::testing::Matcher<AstNode> lhs_;
@@ -124,10 +128,8 @@ class BinaryOperatorExpressionMatcher {
};
// Matches a Return node.
class MatchesReturnMatcher {
class MatchesReturnMatcher : public AstNodeMatcherBase {
public:
using is_gtest_matcher = void;
// Constructs a matcher which matches a Return statement that has no operand.
explicit MatchesReturnMatcher() = default;
@@ -136,34 +138,20 @@ class MatchesReturnMatcher {
explicit MatchesReturnMatcher(::testing::Matcher<AstNode> matcher)
: matcher_(std::move(matcher)) {}
void DescribeTo(std::ostream* out) const {
DescribeToImpl(out, /*negated=*/false);
}
void DescribeNegationTo(std::ostream* out) const {
DescribeToImpl(out, /*negated=*/true);
}
auto MatchAndExplain(const AstNode& node,
::testing::MatchResultListener* listener) const -> bool {
return MatchAndExplain(&node, listener);
}
auto MatchAndExplain(const AstNode* node,
::testing::MatchResultListener* listener) const -> bool;
private:
void DescribeToImpl(std::ostream* out, bool negated) const;
void DescribeToImpl(std::ostream* out, bool negated) const override;
auto MatchAndExplainImpl(const AstNode* node,
::testing::MatchResultListener* listener) const
-> bool override;
std::optional<::testing::Matcher<AstNode>> matcher_;
};
// Matches a FunctionDeclaration. See documentation for
// MatchesFunctionDeclaration in ast_test_matchers.h.
class MatchesFunctionDeclarationMatcher {
class MatchesFunctionDeclarationMatcher : public AstNodeMatcherBase {
public:
using is_gtest_matcher = void;
MatchesFunctionDeclarationMatcher() = default;
auto WithName(::testing::Matcher<std::string> name_matcher)
@@ -178,29 +166,71 @@ class MatchesFunctionDeclarationMatcher {
return *this;
}
void DescribeTo(std::ostream* out) const {
DescribeToImpl(out, /*negated=*/false);
}
void DescribeNegationTo(std::ostream* out) const {
DescribeToImpl(out, /*negated=*/true);
}
auto MatchAndExplain(const AstNode& node,
::testing::MatchResultListener* listener) const -> bool {
return MatchAndExplain(&node, listener);
}
auto MatchAndExplain(const AstNode* node,
::testing::MatchResultListener* listener) const -> bool;
private:
void DescribeToImpl(std::ostream* out, bool negated) const;
void DescribeToImpl(std::ostream* out, bool negated) const override;
auto MatchAndExplainImpl(const AstNode* node,
::testing::MatchResultListener* listener) const
-> bool override;
std::optional<::testing::Matcher<std::string>> name_matcher_;
std::optional<::testing::Matcher<AstNode>> body_matcher_;
};
// Matches an UnimplementedExpression.
class MatchesUnimplementedExpressionMatcher : public AstNodeMatcherBase {
public:
// Constructs a matcher which matches an UnimplementedExpression that has the
// given label, and whose children match children_matcher.
MatchesUnimplementedExpressionMatcher(
std::string label,
::testing::Matcher<llvm::ArrayRef<Nonnull<const AstNode*>>>
children_matcher)
: label_(std::move(label)),
children_matcher_(std::move(children_matcher)) {}
private:
void DescribeToImpl(std::ostream* out, bool negated) const override;
auto MatchAndExplainImpl(Nonnull<const AstNode*> node,
::testing::MatchResultListener* listener) const
-> bool override;
std::string label_;
::testing::Matcher<llvm::ArrayRef<Nonnull<const AstNode*>>> children_matcher_;
};
// Matches an `AST`.
class ASTDeclarationsMatcher {
public:
using is_gtest_matcher = void;
// Constructs a matcher which matches an `AST` whose `declarations` member
// matches `declarations_matcher`
explicit ASTDeclarationsMatcher(
::testing::Matcher<std::vector<Nonnull<Declaration*>>>
declarations_matcher)
: declarations_matcher_(std::move(declarations_matcher)) {}
void DescribeTo(std::ostream* out) const {
*out << "AST declarations ";
declarations_matcher_.DescribeTo(out);
}
void DescribeNegationTo(std::ostream* out) const {
*out << "AST declarations ";
declarations_matcher_.DescribeNegationTo(out);
}
auto MatchAndExplain(const AST& ast,
::testing::MatchResultListener* listener) const -> bool {
*listener << "whose declarations ";
return declarations_matcher_.MatchAndExplain(ast.declarations, listener);
}
private:
::testing::Matcher<std::vector<Nonnull<Declaration*>>> declarations_matcher_;
};
} // namespace TestingInternal
} // namespace Carbon
@@ -17,6 +17,7 @@ namespace Carbon {
namespace {
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::IsEmpty;
using ::testing::Not;
@@ -124,5 +125,38 @@ TEST(MatchesFunctionDeclarationTest, BasicUsage) {
EXPECT_THAT(body, Not(MatchesFunctionDeclaration()));
}
TEST(MatchesUnimplementedExpressionTest, BasicUsage) {
IntLiteral two(DummyLoc, 2);
IntLiteral three(DummyLoc, 3);
UnimplementedExpression unimplemented(DummyLoc, "DummyLabel", &two, &three);
EXPECT_THAT(unimplemented, MatchesUnimplementedExpression(
"DummyLabel", ElementsAre(MatchesLiteral(2),
MatchesLiteral(3))));
EXPECT_THAT(
&unimplemented,
MatchesUnimplementedExpression(
"DummyLabel", ElementsAre(MatchesLiteral(2), MatchesLiteral(3))));
EXPECT_THAT(
unimplemented,
Not(MatchesUnimplementedExpression(
"WrongLabel", ElementsAre(MatchesLiteral(2), MatchesLiteral(3)))));
EXPECT_THAT(unimplemented,
Not(MatchesUnimplementedExpression("DummyLabel", IsEmpty())));
EXPECT_THAT(two,
Not(MatchesUnimplementedExpression("DummyLabel", IsEmpty())));
}
TEST(ASTDeclarationsTest, BasicUsage) {
TuplePattern params(DummyLoc, {});
Block body(DummyLoc, {});
FunctionDeclaration decl(DummyLoc, "Foo", {}, &params,
ReturnTerm::Omitted(DummyLoc), &body);
AST ast = {.declarations = {&decl}};
EXPECT_THAT(ast, ASTDeclarations(ElementsAre(MatchesFunctionDeclaration())));
EXPECT_THAT(ast, Not(ASTDeclarations(IsEmpty())));
}
} // namespace
} // namespace Carbon
+12 -8
View File
@@ -4,6 +4,7 @@
#include "executable_semantics/ast/declaration.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
namespace Carbon {
@@ -32,7 +33,7 @@ void Declaration::Print(llvm::raw_ostream& out) const {
const auto& choice = cast<ChoiceDeclaration>(*this);
out << "choice " << choice.name() << " {\n";
for (Nonnull<const AlternativeSignature*> alt : choice.alternatives()) {
out << "alt " << alt->name() << " " << alt->signature() << ";\n";
out << *alt << ";\n";
}
out << "}\n";
break;
@@ -46,6 +47,10 @@ void Declaration::Print(llvm::raw_ostream& out) const {
}
}
void GenericBinding::Print(llvm::raw_ostream& out) const {
out << name() << ":! " << type();
}
void ReturnTerm::Print(llvm::raw_ostream& out) const {
switch (kind_) {
case ReturnKind::Omitted:
@@ -63,14 +68,9 @@ void FunctionDeclaration::PrintDepth(int depth, llvm::raw_ostream& out) const {
out << "fn " << name_ << " ";
if (!deduced_parameters_.empty()) {
out << "[";
unsigned int i = 0;
llvm::ListSeparator sep;
for (Nonnull<const GenericBinding*> deduced : deduced_parameters_) {
if (i != 0) {
out << ", ";
}
out << deduced->name() << ":! ";
deduced->type().Print(out);
++i;
out << sep << *deduced;
}
out << "]";
}
@@ -84,4 +84,8 @@ void FunctionDeclaration::PrintDepth(int depth, llvm::raw_ostream& out) const {
}
}
void AlternativeSignature::Print(llvm::raw_ostream& out) const {
out << "alt " << name() << " " << signature();
}
} // namespace Carbon
+5 -2
View File
@@ -38,8 +38,7 @@ class Declaration : public virtual AstNode, public NamedEntity {
Declaration(const Member&) = delete;
auto operator=(const Member&) -> Declaration& = delete;
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
void Print(llvm::raw_ostream& out) const override;
static auto classof(const AstNode* node) -> bool {
return InheritsFromDeclaration(node->kind());
@@ -84,6 +83,8 @@ struct GenericBinding : public virtual AstNode, public NamedEntity {
name_(std::move(name)),
type_(type) {}
void Print(llvm::raw_ostream& out) const override;
static auto classof(const AstNode* node) -> bool {
return InheritsFromGenericBinding(node->kind());
}
@@ -253,6 +254,8 @@ class AlternativeSignature : public virtual AstNode, public NamedEntity {
name_(std::move(name)),
signature_(signature) {}
void Print(llvm::raw_ostream& out) const override;
static auto classof(const AstNode* node) -> bool {
return InheritsFromAlternativeSignature(node->kind());
}
+11
View File
@@ -184,6 +184,17 @@ void Expression::Print(llvm::raw_ostream& out) const {
out << "print";
}
out << ")";
break;
case ExpressionKind::UnimplementedExpression: {
const auto& unimplemented = cast<UnimplementedExpression>(*this);
out << "UnimplementedExpression<" << unimplemented.label() << ">(";
llvm::ListSeparator sep;
for (Nonnull<const AstNode*> child : unimplemented.children()) {
out << sep << *child;
}
out << ")";
break;
}
}
}
+40 -2
View File
@@ -36,8 +36,7 @@ class Expression : public virtual AstNode {
~Expression() override = 0;
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
void Print(llvm::raw_ostream& out) const override;
static auto classof(const AstNode* node) {
return InheritsFromExpression(node->kind());
@@ -451,6 +450,45 @@ class IntrinsicExpression : public Expression {
Nonnull<TupleLiteral*> args_;
};
// An expression whose semantics have not been implemented. This can be used
// as a placeholder during development, in order to implement and test parsing
// of a new expression syntax without having to implement its semantics.
class UnimplementedExpression : public Expression {
public:
// Constructs an UnimplementedExpression with the given label and the given
// children, which must all be convertible to Nonnull<AstNode*>. The label
// should correspond roughly to the name of the class that will eventually
// replace this usage of UnimplementedExpression.
template <typename... Children>
UnimplementedExpression(SourceLocation source_loc, std::string label,
Children... children)
: AstNode(AstNodeKind::UnimplementedExpression, source_loc),
label_(std::move(label)) {
AddChildren(children...);
}
static auto classof(const AstNode* node) -> bool {
return InheritsFromUnimplementedExpression(node->kind());
}
auto label() const -> std::string_view { return label_; }
auto children() const -> llvm::ArrayRef<Nonnull<const AstNode*>> {
return children_;
}
private:
void AddChildren() {}
template <typename... Children>
void AddChildren(Nonnull<AstNode*> child, Children... children) {
children_.push_back(child);
AddChildren(children...);
}
std::string label_;
std::vector<Nonnull<AstNode*>> children_;
};
// Converts paren_contents to an Expression, interpreting the parentheses as
// grouping if their contents permit that interpretation, or as forming a
// tuple otherwise.
+1 -2
View File
@@ -30,8 +30,7 @@ class Member : public virtual AstNode, public NamedEntity {
Member(const Member&) = delete;
auto operator=(const Member&) -> Member& = delete;
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
void Print(llvm::raw_ostream& out) const override;
static auto classof(const AstNode* node) -> bool {
return InheritsFromMember(node->kind());
+1 -2
View File
@@ -36,8 +36,7 @@ class Pattern : public virtual AstNode {
~Pattern() override = 0;
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
void Print(llvm::raw_ostream& out) const override;
static auto classof(const AstNode* node) -> bool {
return InheritsFromPattern(node->kind());
+1 -2
View File
@@ -25,9 +25,8 @@ class Statement : public virtual AstNode {
public:
~Statement() override = 0;
void Print(llvm::raw_ostream& out) const { PrintDepth(-1, out); }
void Print(llvm::raw_ostream& out) const override { 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());