mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 14:41:06 +01:00
Support parsing and testing unimplemented expressions (#957)
Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
Jon Meow
parent
be0c1e9da6
commit
dc5e62fc7a
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user