1 #include <mbgl/style/expression/collator.hpp>
2 #include <mbgl/style/expression/equals.hpp>
3
4 namespace mbgl {
5 namespace style {
6 namespace expression {
7
isComparableType(const type::Type & type)8 static bool isComparableType(const type::Type& type) {
9 return type == type::String ||
10 type == type::Number ||
11 type == type::Boolean ||
12 type == type::Null;
13 }
14
Equals(std::unique_ptr<Expression> lhs_,std::unique_ptr<Expression> rhs_,optional<std::unique_ptr<Expression>> collator_,bool negate_)15 Equals::Equals(std::unique_ptr<Expression> lhs_, std::unique_ptr<Expression> rhs_, optional<std::unique_ptr<Expression>> collator_, bool negate_)
16 : Expression(Kind::Equals, type::Boolean),
17 lhs(std::move(lhs_)),
18 rhs(std::move(rhs_)),
19 collator(std::move(collator_)),
20 negate(negate_) {
21 assert(isComparableType(lhs->getType()) || isComparableType(rhs->getType()));
22 assert(lhs->getType() == rhs->getType() || lhs->getType() == type::Value || rhs->getType() == type::Value);
23 }
24
evaluate(const EvaluationContext & params) const25 EvaluationResult Equals::evaluate(const EvaluationContext& params) const {
26 EvaluationResult lhsResult = lhs->evaluate(params);
27 if (!lhsResult) return lhsResult;
28
29 EvaluationResult rhsResult = rhs->evaluate(params);
30 if (!rhsResult) return lhsResult;
31
32 bool result;
33
34 if (collator) {
35 auto collatorResult = (*collator)->evaluate(params);
36 const Collator& c = collatorResult->get<Collator>();
37 result = c.compare(lhsResult->get<std::string>(), rhsResult->get<std::string>()) == 0;
38 } else {
39 result = *lhsResult == *rhsResult;
40 }
41 if (negate) {
42 result = !result;
43 }
44 return result;
45 }
46
eachChild(const std::function<void (const Expression &)> & visit) const47 void Equals::eachChild(const std::function<void(const Expression&)>& visit) const {
48 visit(*lhs);
49 visit(*rhs);
50 if (collator) {
51 visit(**collator);
52 }
53 }
54
operator ==(const Expression & e) const55 bool Equals::operator==(const Expression& e) const {
56 if (e.getKind() == Kind::Equals) {
57 auto eq = static_cast<const Equals*>(&e);
58 return eq->negate == negate && *eq->lhs == *lhs && *eq->rhs == *rhs;
59 }
60 return false;
61 }
62
possibleOutputs() const63 std::vector<optional<Value>> Equals::possibleOutputs() const {
64 return {{ true }, { false }};
65 }
66
67 using namespace mbgl::style::conversion;
parse(const Convertible & value,ParsingContext & ctx)68 ParseResult Equals::parse(const Convertible& value, ParsingContext& ctx) {
69 std::size_t length = arrayLength(value);
70
71 if (length != 3 && length != 4) {
72 ctx.error("Expected two or three arguments.");
73 return ParseResult();
74 }
75
76 bool negate = toString(arrayMember(value, 0)) == std::string("!=");
77
78 ParseResult lhs = ctx.parse(arrayMember(value, 1), 1, {type::Value});
79 if (!lhs) return ParseResult();
80
81 ParseResult rhs = ctx.parse(arrayMember(value, 2), 2, {type::Value});
82 if (!rhs) return ParseResult();
83
84 type::Type lhsType = (*lhs)->getType();
85 type::Type rhsType = (*rhs)->getType();
86
87 if (!isComparableType(lhsType) && !isComparableType(rhsType)) {
88 ctx.error("Expected at least one argument to be a string, number, boolean, or null, but found (" +
89 toString(lhsType) + ", " + toString(rhsType) + ") instead.");
90 return ParseResult();
91 }
92
93 if (lhsType != rhsType && lhsType != type::Value && rhsType != type::Value) {
94 ctx.error("Cannot compare " + toString(lhsType) + " and " + toString(rhsType) + ".");
95 return ParseResult();
96 }
97
98 ParseResult collatorParseResult;
99 if (length == 4) {
100 if (lhsType != type::String && rhsType != type::String) {
101 ctx.error("Cannot use collator to compare non-string types.");
102 return ParseResult();
103 }
104 collatorParseResult = ctx.parse(arrayMember(value, 3), 3, {type::Collator});
105 if (!collatorParseResult) return ParseResult();
106 }
107
108 return ParseResult(std::make_unique<Equals>(std::move(*lhs), std::move(*rhs), std::move(collatorParseResult), negate));
109 }
110
111 } // namespace expression
112 } // namespace style
113 } // namespace mbgl
114