///
/// \code
/// Grammar for the expressions supported:
-/// <Expression> := <Literal> | <MatcherExpression>
+/// <Expression> := <Literal> | <NamedValue> | <MatcherExpression>
/// <Literal> := <StringLiteral> | <Unsigned>
/// <StringLiteral> := "quoted string"
/// <Unsigned> := [0-9]+
-/// <MatcherExpression> := <MatcherName>(<ArgumentList>) |
-/// <MatcherName>(<ArgumentList>).bind(<StringLiteral>)
-/// <MatcherName> := [a-zA-Z]+
+/// <NamedValue> := <Identifier>
+/// <MatcherExpression> := <Identifier>(<ArgumentList>) |
+/// <Identifier>(<ArgumentList>).bind(<StringLiteral>)
+/// <Identifier> := [a-zA-Z]+
/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList>
/// \endcode
///
public:
virtual ~Sema();
+ /// \brief Lookup a value by name.
+ ///
+ /// This can be used in the Sema layer to declare known constants or to
+ /// allow to split an expression in pieces.
+ ///
+ /// \param Name The name of the value to lookup.
+ ///
+ /// \return The named value. It could be any type that VariantValue
+ /// supports. A 'nothing' value means that the name is not recognized.
+ virtual VariantValue getNamedValue(StringRef Name) {
+ return VariantValue();
+ }
+
/// \brief Process a matcher expression.
///
/// All the arguments passed here have already been processed.
Diagnostics *Error) = 0;
};
+ /// \brief Sema implementation that uses the matcher registry to process the
+ /// tokens.
+ class RegistrySema : public Parser::Sema {
+ public:
+ virtual ~RegistrySema();
+ llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
+ const SourceRange &NameRange,
+ Diagnostics *Error) override;
+ VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) override;
+ };
+
/// \brief Parse a matcher expression, creating matchers from the registry.
///
/// This overload creates matchers calling directly into the registry. If the
/// \brief Clones the provided matchers.
///
/// They should be the result of a polymorphic matcher.
- static VariantMatcher PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
+ static VariantMatcher
+ PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
/// \brief Creates a 'variadic' operator matcher.
///
VariantValue(const std::string &String);
VariantValue(const VariantMatcher &Matchers);
+ /// \brief Returns true iff this is an empty value.
+ bool isNothing() const { return Type == VT_Nothing; }
+
/// \brief Unsigned value functions.
bool isUnsigned() const;
unsigned getUnsigned() const;
*Value = Tokenizer->consumeNextToken().Value;
return true;
- case TokenInfo::TK_Ident:
+ case TokenInfo::TK_Ident: {
+ // Identifier could be a name known by Sema as a named value.
+ const VariantValue NamedValue =
+ S->getNamedValue(Tokenizer->peekNextToken().Text);
+ if (!NamedValue.isNothing()) {
+ Tokenizer->consumeNextToken(); // Actually consume it.
+ *Value = NamedValue;
+ return true;
+ }
+ // Fallback to full matcher parsing.
return parseMatcherExpressionImpl(Value);
+ }
case TokenInfo::TK_CodeCompletion:
addExpressionCompletions();
Diagnostics *Error)
: Tokenizer(Tokenizer), S(S), Error(Error) {}
-class RegistrySema : public Parser::Sema {
-public:
- virtual ~RegistrySema() {}
- llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
- const SourceRange &NameRange,
- Diagnostics *Error) {
- return Registry::lookupMatcherCtor(MatcherName, NameRange, Error);
- }
- VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
- const SourceRange &NameRange,
- StringRef BindID,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
- if (BindID.empty()) {
- return Registry::constructMatcher(Ctor, NameRange, Args, Error);
- } else {
- return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
- Error);
- }
+Parser::RegistrySema::~RegistrySema() {}
+
+llvm::Optional<MatcherCtor> Parser::RegistrySema::lookupMatcherCtor(
+ StringRef MatcherName, const SourceRange &NameRange, Diagnostics *Error) {
+ return Registry::lookupMatcherCtor(MatcherName, NameRange, Error);
+}
+
+VariantMatcher Parser::RegistrySema::actOnMatcherExpression(
+ MatcherCtor Ctor, const SourceRange &NameRange, StringRef BindID,
+ ArrayRef<ParserValue> Args, Diagnostics *Error) {
+ if (BindID.empty()) {
+ return Registry::constructMatcher(Ctor, NameRange, Args, Error);
+ } else {
+ return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
+ Error);
}
-};
+}
bool Parser::parseExpression(StringRef Code, VariantValue *Value,
Diagnostics *Error) {
EXPECT_TRUE(matches("void f(int a, int x);", M));
EXPECT_FALSE(matches("void f(int x, int a);", M));
+ // Test named values.
+ struct NamedSema : public Parser::RegistrySema {
+ public:
+ virtual VariantValue getNamedValue(StringRef Name) {
+ if (Name == "nameX")
+ return std::string("x");
+ if (Name == "param0")
+ return VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
+ return VariantValue();
+ }
+ };
+ NamedSema Sema;
+ llvm::Optional<DynTypedMatcher> HasParameterWithNamedValues(
+ Parser::parseMatcherExpression(
+ "functionDecl(param0, hasParameter(1, hasName(nameX)))", &Sema,
+ &Error));
+ EXPECT_EQ("", Error.toStringFull());
+ M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>();
+
+ EXPECT_TRUE(matches("void f(int a, int x);", M));
+ EXPECT_FALSE(matches("void f(int x, int a);", M));
+
+
EXPECT_TRUE(!Parser::parseMatcherExpression(
"hasInitializer(\n binaryOperator(hasLHS(\"A\")))",
&Error).hasValue());
EXPECT_TRUE(Value.isUnsigned());
EXPECT_EQ(kUnsigned, Value.getUnsigned());
+ EXPECT_FALSE(Value.isNothing());
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());
}
EXPECT_EQ(kString, Value.getString());
EXPECT_EQ("String", Value.getTypeAsString());
+ EXPECT_FALSE(Value.isNothing());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
}
TEST(VariantValueTest, DynTypedMatcher) {
VariantValue Value = VariantMatcher::SingleMatcher(stmt());
+ EXPECT_FALSE(Value.isNothing());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
VariantValue Value = std::string("A");
EXPECT_TRUE(Value.isString());
EXPECT_EQ("A", Value.getString());
+ EXPECT_FALSE(Value.isNothing());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
EXPECT_EQ("String", Value.getTypeAsString());
Value = VariantMatcher::SingleMatcher(recordDecl());
+ EXPECT_FALSE(Value.isNothing());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_TRUE(Value.isMatcher());
Value = 17;
EXPECT_TRUE(Value.isUnsigned());
EXPECT_EQ(17U, Value.getUnsigned());
+ EXPECT_FALSE(Value.isNothing());
EXPECT_FALSE(Value.isMatcher());
EXPECT_FALSE(Value.isString());
Value = VariantValue();
+ EXPECT_TRUE(Value.isNothing());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());