/// \code
/// Grammar for the expressions supported:
/// <Expression> := <Literal> | <NamedValue> | <MatcherExpression>
-/// <Literal> := <StringLiteral> | <Unsigned>
+/// <Literal> := <StringLiteral> | <Boolean> | <Unsigned>
/// <StringLiteral> := "quoted string"
+/// <Boolean> := true | false
/// <Unsigned> := [0-9]+
/// <NamedValue> := <Identifier>
/// <MatcherExpression> := <Identifier>(<ArgumentList>) |
public:
enum Kind {
AK_Matcher,
+ AK_Boolean,
AK_Unsigned,
AK_String
};
/// copy/assignment.
///
/// Supported types:
+/// - \c bool
/// - \c unsigned
/// - \c llvm::StringRef
/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
VariantValue &operator=(const VariantValue &Other);
/// \brief Specific constructors for each supported type.
+ VariantValue(bool Boolean);
VariantValue(unsigned Unsigned);
VariantValue(StringRef String);
VariantValue(const VariantMatcher &Matchers);
+ /// \brief Constructs an \c unsigned value (disambiguation from bool).
+ VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {}
+
/// \brief Returns true iff this is not an empty value.
explicit operator bool() const { return hasValue(); }
bool hasValue() const { return Type != VT_Nothing; }
+ /// \brief Boolean value functions.
+ bool isBoolean() const;
+ bool getBoolean() const;
+ void setBoolean(bool Boolean);
+
/// \brief Unsigned value functions.
bool isUnsigned() const;
unsigned getUnsigned() const;
/// \brief All supported value types.
enum ValueType {
VT_Nothing,
+ VT_Boolean,
VT_Unsigned,
VT_String,
VT_Matcher
/// \brief All supported value types.
union AllValues {
unsigned Unsigned;
+ bool Boolean;
std::string *String;
VariantMatcher *Matcher;
};
}
};
+template <> struct ArgTypeTraits<bool> {
+ static bool is(const VariantValue &Value) { return Value.isBoolean(); }
+ static bool get(const VariantValue &Value) {
+ return Value.getBoolean();
+ }
+ static ArgKind getKind() {
+ return ArgKind(ArgKind::AK_Boolean);
+ }
+};
+
template <> struct ArgTypeTraits<unsigned> {
static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
static unsigned get(const VariantValue &Value) {
break;
++TokenLength;
}
- Result.Kind = TokenInfo::TK_Ident;
- Result.Text = Code.substr(0, TokenLength);
+ if (TokenLength == 4 && Code.startswith("true")) {
+ Result.Kind = TokenInfo::TK_Literal;
+ Result.Value = true;
+ } else if (TokenLength == 5 && Code.startswith("false")) {
+ Result.Kind = TokenInfo::TK_Literal;
+ Result.Value = false;
+ } else {
+ Result.Kind = TokenInfo::TK_Ident;
+ Result.Text = Code.substr(0, TokenLength);
+ }
Code = Code.drop_front(TokenLength);
} else {
Result.Kind = TokenInfo::TK_InvalidChar;
switch (getArgKind()) {
case AK_Matcher:
return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
+ case AK_Boolean:
+ return "boolean";
case AK_Unsigned:
return "unsigned";
case AK_String:
*this = Other;
}
+VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) {
+ setBoolean(Boolean);
+}
+
VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
setUnsigned(Unsigned);
}
if (this == &Other) return *this;
reset();
switch (Other.Type) {
+ case VT_Boolean:
+ setBoolean(Other.getBoolean());
+ break;
case VT_Unsigned:
setUnsigned(Other.getUnsigned());
break;
delete Value.Matcher;
break;
// Cases that do nothing.
+ case VT_Boolean:
case VT_Unsigned:
case VT_Nothing:
break;
Type = VT_Nothing;
}
+bool VariantValue::isBoolean() const {
+ return Type == VT_Boolean;
+}
+
+bool VariantValue::getBoolean() const {
+ assert(isBoolean());
+ return Value.Boolean;
+}
+
+void VariantValue::setBoolean(bool NewValue) {
+ reset();
+ Type = VT_Boolean;
+ Value.Boolean = NewValue;
+}
+
bool VariantValue::isUnsigned() const {
return Type == VT_Unsigned;
}
bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {
switch (Kind.getArgKind()) {
+ case ArgKind::AK_Boolean:
+ if (!isBoolean())
+ return false;
+ *Specificity = 1;
+ return true;
+
case ArgKind::AK_Unsigned:
if (!isUnsigned())
return false;
switch (Type) {
case VT_String: return "String";
case VT_Matcher: return getMatcher().getTypeAsString();
+ case VT_Boolean: return "Boolean";
case VT_Unsigned: return "Unsigned";
case VT_Nothing: return "Nothing";
}
ExpectedMatchersTy ExpectedMatchers;
};
+TEST(ParserTest, ParseBoolean) {
+ MockSema Sema;
+ Sema.parse("true");
+ Sema.parse("false");
+ EXPECT_EQ(2U, Sema.Values.size());
+ EXPECT_EQ(true, Sema.Values[0].getBoolean());
+ EXPECT_EQ(false, Sema.Values[1].getBoolean());
+}
+
TEST(ParserTest, ParseUnsigned) {
MockSema Sema;
Sema.parse("0");
EXPECT_TRUE(Value.isString());
EXPECT_EQ("A", Value.getString());
EXPECT_TRUE(Value.hasValue());
+ EXPECT_FALSE(Value.isBoolean());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
EXPECT_EQ("String", Value.getTypeAsString());
Value = VariantMatcher::SingleMatcher(recordDecl());
EXPECT_TRUE(Value.hasValue());
+ EXPECT_FALSE(Value.isBoolean());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_TRUE(Value.isMatcher());
EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
+ Value = true;
+ EXPECT_TRUE(Value.isBoolean());
+ EXPECT_EQ(true, Value.getBoolean());
+ EXPECT_TRUE(Value.hasValue());
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isString());
+
Value = 17;
EXPECT_TRUE(Value.isUnsigned());
EXPECT_EQ(17U, Value.getUnsigned());
+ EXPECT_FALSE(Value.isBoolean());
EXPECT_TRUE(Value.hasValue());
EXPECT_FALSE(Value.isMatcher());
EXPECT_FALSE(Value.isString());
Value = VariantValue();
EXPECT_FALSE(Value.hasValue());
+ EXPECT_FALSE(Value.isBoolean());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());