summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnand Thakker <anandthakker@users.noreply.github.com>2018-08-02 13:48:47 -0400
committerGitHub <noreply@github.com>2018-08-02 13:48:47 -0400
commitd25e1a1e7f313efd78aa76c76e4fed5f4d792d8a (patch)
treefb3e191cf79c09e14e3bf41e1d3212a74175f985
parent952c4131e6a46fd0fab2208379dc340fb02924e3 (diff)
downloadqtlocation-mapboxgl-d25e1a1e7f313efd78aa76c76e4fed5f4d792d8a.tar.gz
Relax typing for comparison operators (#12537)
* Relax typing for comparison operators Ports https://github.com/mapbox/mapbox-gl-js/pull/6961 * Review comments * Lint fixes
-rw-r--r--cmake/core-files.cmake4
-rw-r--r--include/mbgl/style/expression/comparison.hpp68
-rw-r--r--include/mbgl/style/expression/dsl.hpp1
-rw-r--r--include/mbgl/style/expression/equals.hpp35
-rw-r--r--include/mbgl/style/expression/expression.hpp2
m---------mapbox-gl-js0
-rw-r--r--src/mbgl/style/expression/comparison.cpp275
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp13
-rw-r--r--src/mbgl/style/expression/dsl.cpp20
-rw-r--r--src/mbgl/style/expression/equals.cpp113
-rw-r--r--src/mbgl/style/expression/parsing_context.cpp10
11 files changed, 366 insertions, 175 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index 44aff682fc..addacc174d 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -455,9 +455,9 @@ set(MBGL_CORE_FILES
include/mbgl/style/expression/coercion.hpp
include/mbgl/style/expression/collator.hpp
include/mbgl/style/expression/collator_expression.hpp
+ include/mbgl/style/expression/comparison.hpp
include/mbgl/style/expression/compound_expression.hpp
include/mbgl/style/expression/dsl.hpp
- include/mbgl/style/expression/equals.hpp
include/mbgl/style/expression/error.hpp
include/mbgl/style/expression/expression.hpp
include/mbgl/style/expression/find_zoom_curve.hpp
@@ -483,9 +483,9 @@ set(MBGL_CORE_FILES
src/mbgl/style/expression/coalesce.cpp
src/mbgl/style/expression/coercion.cpp
src/mbgl/style/expression/collator_expression.cpp
+ src/mbgl/style/expression/comparison.cpp
src/mbgl/style/expression/compound_expression.cpp
src/mbgl/style/expression/dsl.cpp
- src/mbgl/style/expression/equals.cpp
src/mbgl/style/expression/expression.cpp
src/mbgl/style/expression/find_zoom_curve.cpp
src/mbgl/style/expression/get_covering_stops.cpp
diff --git a/include/mbgl/style/expression/comparison.hpp b/include/mbgl/style/expression/comparison.hpp
new file mode 100644
index 0000000000..cf64f5cd34
--- /dev/null
+++ b/include/mbgl/style/expression/comparison.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <mbgl/style/expression/collator_expression.hpp>
+#include <mbgl/style/expression/expression.hpp>
+#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion.hpp>
+
+#include <memory>
+
+namespace mbgl {
+namespace style {
+namespace expression {
+
+ParseResult parseComparison(const mbgl::style::conversion::Convertible&, ParsingContext&);
+
+class BasicComparison : public Expression {
+public:
+ using CompareFunctionType = bool (*) (Value, Value);
+
+ BasicComparison(
+ std::string op,
+ std::unique_ptr<Expression> lhs,
+ std::unique_ptr<Expression> rhs);
+
+ void eachChild(const std::function<void(const Expression&)>& visit) const override;
+ bool operator==(const Expression&) const override;
+ EvaluationResult evaluate(const EvaluationContext&) const override;
+ std::vector<optional<Value>> possibleOutputs() const override;
+ std::string getOperator() const override;
+
+private:
+ std::string op;
+ CompareFunctionType compare;
+ std::unique_ptr<Expression> lhs;
+ std::unique_ptr<Expression> rhs;
+ bool needsRuntimeTypeCheck;
+};
+
+class CollatorComparison : public Expression {
+public:
+ using CompareFunctionType = bool (*) (std::string, std::string, Collator);
+
+ CollatorComparison(
+ std::string op,
+ std::unique_ptr<Expression> lhs,
+ std::unique_ptr<Expression> rhs,
+ std::unique_ptr<Expression> collator);
+
+ void eachChild(const std::function<void(const Expression&)>& visit) const override;
+ bool operator==(const Expression&) const override;
+ EvaluationResult evaluate(const EvaluationContext&) const override;
+ std::vector<optional<Value>> possibleOutputs() const override;
+ std::string getOperator() const override;
+
+private:
+ std::string op;
+ CompareFunctionType compare;
+ std::unique_ptr<Expression> lhs;
+ std::unique_ptr<Expression> rhs;
+ std::unique_ptr<Expression> collator;
+ bool needsRuntimeTypeCheck;
+};
+
+
+
+} // namespace expression
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/expression/dsl.hpp b/include/mbgl/style/expression/dsl.hpp
index e9de20de18..a4483a6fe6 100644
--- a/include/mbgl/style/expression/dsl.hpp
+++ b/include/mbgl/style/expression/dsl.hpp
@@ -31,6 +31,7 @@ std::unique_ptr<Expression> literal(Value value);
std::unique_ptr<Expression> literal(std::initializer_list<double> value);
std::unique_ptr<Expression> literal(std::initializer_list<const char *> value);
+std::unique_ptr<Expression> assertion(type::Type, std::unique_ptr<Expression>);
std::unique_ptr<Expression> number(std::unique_ptr<Expression>);
std::unique_ptr<Expression> string(std::unique_ptr<Expression>);
std::unique_ptr<Expression> boolean(std::unique_ptr<Expression>);
diff --git a/include/mbgl/style/expression/equals.hpp b/include/mbgl/style/expression/equals.hpp
deleted file mode 100644
index 1e8bf7acef..0000000000
--- a/include/mbgl/style/expression/equals.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-#include <mbgl/style/expression/collator_expression.hpp>
-#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/expression/parsing_context.hpp>
-#include <mbgl/style/conversion.hpp>
-
-#include <memory>
-
-namespace mbgl {
-namespace style {
-namespace expression {
-
-class Equals : public Expression {
-public:
- Equals(std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs, optional<std::unique_ptr<Expression>> collator, bool negate);
-
- static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&);
-
- void eachChild(const std::function<void(const Expression&)>& visit) const override;
- bool operator==(const Expression&) const override;
- EvaluationResult evaluate(const EvaluationContext&) const override;
- std::vector<optional<Value>> possibleOutputs() const override;
-
- std::string getOperator() const override { return negate ? "!=" : "=="; }
-private:
- std::unique_ptr<Expression> lhs;
- std::unique_ptr<Expression> rhs;
- optional<std::unique_ptr<Expression>> collator;
- bool negate;
-};
-
-} // namespace expression
-} // namespace style
-} // namespace mbgl
diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp
index 8301f1572c..26124f6463 100644
--- a/include/mbgl/style/expression/expression.hpp
+++ b/include/mbgl/style/expression/expression.hpp
@@ -133,7 +133,7 @@ enum class Kind : int32_t {
Case,
Any,
All,
- Equals,
+ Comparison,
};
class Expression {
diff --git a/mapbox-gl-js b/mapbox-gl-js
-Subproject dc43a09a6e84d7d97af33455594adf7f25dc961
+Subproject 47e637c3984a5121589bd17b51c6605f223aaea
diff --git a/src/mbgl/style/expression/comparison.cpp b/src/mbgl/style/expression/comparison.cpp
new file mode 100644
index 0000000000..6179c3ce88
--- /dev/null
+++ b/src/mbgl/style/expression/comparison.cpp
@@ -0,0 +1,275 @@
+#include <mbgl/style/expression/collator.hpp>
+#include <mbgl/style/expression/comparison.hpp>
+#include <mbgl/style/expression/dsl.hpp>
+
+namespace mbgl {
+namespace style {
+namespace expression {
+
+static bool isComparableType(const std::string& op, const type::Type& type) {
+ if (op == "==" || op == "!=") {
+ return type == type::String ||
+ type == type::Number ||
+ type == type::Boolean ||
+ type == type::Null ||
+ type == type::Value;
+ } else {
+ return type == type::String ||
+ type == type::Number ||
+ type == type::Value;
+ }
+}
+
+bool eq(Value a, Value b) { return a == b; }
+bool neq(Value a, Value b) { return a != b; }
+bool lt(Value lhs, Value rhs) {
+ return lhs.match(
+ [&](const std::string& a) { return a < rhs.get<std::string>(); },
+ [&](double a) { return a < rhs.get<double>(); },
+ [&](const auto&) { assert(false); return false; }
+ );
+}
+bool gt(Value lhs, Value rhs) {
+ return lhs.match(
+ [&](const std::string& a) { return a > rhs.get<std::string>(); },
+ [&](double a) { return a > rhs.get<double>(); },
+ [&](const auto&) { assert(false); return false; }
+ );
+}
+bool lteq(Value lhs, Value rhs) {
+ return lhs.match(
+ [&](const std::string& a) { return a <= rhs.get<std::string>(); },
+ [&](double a) { return a <= rhs.get<double>(); },
+ [&](const auto&) { assert(false); return false; }
+ );
+}
+bool gteq(Value lhs, Value rhs) {
+ return lhs.match(
+ [&](const std::string& a) { return a >= rhs.get<std::string>(); },
+ [&](double a) { return a >= rhs.get<double>(); },
+ [&](const auto&) { assert(false); return false; }
+ );
+}
+
+bool eqCollate(std::string a, std::string b, Collator c) { return c.compare(a, b) == 0; }
+bool neqCollate(std::string a, std::string b, Collator c) { return !eqCollate(a, b, c); }
+bool ltCollate(std::string a, std::string b, Collator c) { return c.compare(a, b) < 0; }
+bool gtCollate(std::string a, std::string b, Collator c) { return c.compare(a, b) > 0; }
+bool lteqCollate(std::string a, std::string b, Collator c) { return c.compare(a, b) <= 0; }
+bool gteqCollate(std::string a, std::string b, Collator c) { return c.compare(a, b) >= 0; }
+
+static BasicComparison::CompareFunctionType getBasicCompareFunction(const std::string& op) {
+ if (op == "==") return eq;
+ else if (op == "!=") return neq;
+ else if (op == ">") return gt;
+ else if (op == "<") return lt;
+ else if (op == ">=") return gteq;
+ else if (op == "<=") return lteq;
+ assert(false);
+ return nullptr;
+}
+
+static CollatorComparison::CompareFunctionType getCollatorComparisonFunction(const std::string& op) {
+ if (op == "==") return eqCollate;
+ else if (op == "!=") return neqCollate;
+ else if (op == ">") return gtCollate;
+ else if (op == "<") return ltCollate;
+ else if (op == ">=") return gteqCollate;
+ else if (op == "<=") return lteqCollate;
+ assert(false);
+ return nullptr;
+
+}
+
+
+BasicComparison::BasicComparison(
+ std::string op_,
+ std::unique_ptr<Expression> lhs_,
+ std::unique_ptr<Expression> rhs_)
+ : Expression(Kind::Comparison, type::Boolean),
+ op(std::move(op_)),
+ compare(getBasicCompareFunction(op)),
+ lhs(std::move(lhs_)),
+ rhs(std::move(rhs_)) {
+ assert(isComparableType(op, lhs->getType()) && isComparableType(op, rhs->getType()));
+ assert(lhs->getType() == rhs->getType() || lhs->getType() == type::Value || rhs->getType() == type::Value);
+
+ needsRuntimeTypeCheck = (op != "==" && op != "!=") &&
+ (lhs->getType() == type::Value || rhs->getType() == type::Value);
+}
+
+EvaluationResult BasicComparison::evaluate(const EvaluationContext& params) const {
+ EvaluationResult lhsResult = lhs->evaluate(params);
+ if (!lhsResult) return lhsResult;
+
+ EvaluationResult rhsResult = rhs->evaluate(params);
+ if (!rhsResult) return rhsResult;
+
+ if (needsRuntimeTypeCheck) {
+ type::Type lhsType = typeOf(*lhsResult);
+ type::Type rhsType = typeOf(*rhsResult);
+ // check that type is string or number, and equal
+ if (lhsType != rhsType || !(lhsType == type::String || lhsType == type::Number)) {
+ return EvaluationError {
+ R"(Expected arguments for ")" + op + R"(")" +
+ " to be (string, string) or (number, number), but found (" + toString(lhsType) + ", " +
+ toString(rhsType) + ") instead."
+ };
+ }
+ }
+
+ return compare(*lhsResult, *rhsResult);
+}
+
+void BasicComparison::eachChild(const std::function<void(const Expression&)>& visit) const {
+ visit(*lhs);
+ visit(*rhs);
+}
+
+std::string BasicComparison::getOperator() const { return op; }
+
+bool BasicComparison::operator==(const Expression& e) const {
+ if (e.getKind() == Kind::Comparison) {
+ auto comp = static_cast<const BasicComparison*>(&e);
+ return comp->op == op &&
+ *comp->lhs == *lhs &&
+ *comp->rhs == *rhs;
+ }
+ return false;
+}
+
+std::vector<optional<Value>> BasicComparison::possibleOutputs() const {
+ return {{ true }, { false }};
+}
+
+CollatorComparison::CollatorComparison(
+ std::string op_,
+ std::unique_ptr<Expression> lhs_,
+ std::unique_ptr<Expression> rhs_,
+ std::unique_ptr<Expression> collator_)
+ : Expression(Kind::Comparison, type::Boolean),
+ op(op_),
+ compare(getCollatorComparisonFunction(op)),
+ lhs(std::move(lhs_)),
+ rhs(std::move(rhs_)),
+ collator(std::move(collator_)) {
+ assert(isComparableType(op, lhs->getType()) && isComparableType(op, rhs->getType()));
+ assert(lhs->getType() == rhs->getType() || lhs->getType() == type::Value || rhs->getType() == type::Value);
+
+ needsRuntimeTypeCheck = (op == "==" || op == "!=") &&
+ (lhs->getType() == type::Value || rhs->getType() == type::Value);
+}
+
+EvaluationResult CollatorComparison::evaluate(const EvaluationContext& params) const {
+ EvaluationResult lhsResult = lhs->evaluate(params);
+ if (!lhsResult) return lhsResult;
+
+ EvaluationResult rhsResult = rhs->evaluate(params);
+ if (!rhsResult) return lhsResult;
+
+ if (needsRuntimeTypeCheck) {
+ if (typeOf(*lhsResult) != type::String || typeOf(*rhsResult) != type::String) {
+ return getBasicCompareFunction(op)(*lhsResult, *rhsResult);
+ }
+ }
+
+ auto collatorResult = collator->evaluate(params);
+ if (!collatorResult) return collatorResult;
+
+ const Collator& c = collatorResult->get<Collator>();
+ return compare(lhsResult->get<std::string>(), rhsResult->get<std::string>(), c);
+}
+
+void CollatorComparison::eachChild(const std::function<void(const Expression&)>& visit) const {
+ visit(*lhs);
+ visit(*rhs);
+ visit(*collator);
+}
+
+std::string CollatorComparison::getOperator() const { return op; }
+
+bool CollatorComparison::operator==(const Expression& e) const {
+ if (e.getKind() == Kind::Comparison) {
+ auto comp = static_cast<const CollatorComparison*>(&e);
+ return comp->op == op &&
+ *comp->collator == *collator &&
+ *comp->lhs == *lhs &&
+ *comp->rhs == *rhs;
+ }
+ return false;
+}
+
+std::vector<optional<Value>> CollatorComparison::possibleOutputs() const {
+ return {{ true }, { false }};
+}
+
+using namespace mbgl::style::conversion;
+ParseResult parseComparison(const Convertible& value, ParsingContext& ctx) {
+ std::size_t length = arrayLength(value);
+
+ if (length != 3 && length != 4) {
+ ctx.error("Expected two or three arguments.");
+ return ParseResult();
+ }
+
+ std::string op = *toString(arrayMember(value, 0));
+
+ assert(getBasicCompareFunction(op));
+
+ ParseResult lhs = ctx.parse(arrayMember(value, 1), 1, {type::Value});
+ if (!lhs) return ParseResult();
+ type::Type lhsType = (*lhs)->getType();
+ if (!isComparableType(op, lhsType)) {
+ ctx.error(R"(")" + op + R"(" comparisons are not supported for type ')" + toString(lhsType) + "'.", 1);
+ return ParseResult();
+ }
+
+ ParseResult rhs = ctx.parse(arrayMember(value, 2), 2, {type::Value});
+ if (!rhs) return ParseResult();
+ type::Type rhsType = (*rhs)->getType();
+ if (!isComparableType(op, rhsType)) {
+ ctx.error(R"(")" + op + R"(" comparisons are not supported for type ')" + toString(rhsType) + "'.", 2);
+ return ParseResult();
+ }
+
+ if (
+ lhsType != rhsType &&
+ lhsType != type::Value &&
+ rhsType != type::Value
+ ) {
+ ctx.error("Cannot compare types '" + toString(lhsType) + "' and '" + toString(rhsType) + "'.");
+ return ParseResult();
+ }
+
+ if (op != "==" && op != "!=") {
+ // typing rules specific to less/greater than operators
+ if (lhsType == type::Value && rhsType != type::Value) {
+ // (value, T)
+ lhs = dsl::assertion(rhsType, std::move(*lhs));
+ } else if (lhsType != type::Value && rhsType == type::Value) {
+ // (T, value)
+ rhs = dsl::assertion(lhsType, std::move(*rhs));
+ }
+ }
+
+ if (length == 4) {
+ if (
+ lhsType != type::String &&
+ rhsType != type::String &&
+ lhsType != type::Value &&
+ rhsType != type::Value
+ ) {
+ ctx.error("Cannot use collator to compare non-string types.");
+ return ParseResult();
+ }
+ ParseResult collatorParseResult = ctx.parse(arrayMember(value, 3), 3, {type::Collator});
+ if (!collatorParseResult) return ParseResult();
+ return ParseResult(std::make_unique<CollatorComparison>(op, std::move(*lhs), std::move(*rhs), std::move(*collatorParseResult)));
+ }
+
+ return ParseResult(std::make_unique<BasicComparison>(op, std::move(*lhs), std::move(*rhs)));
+}
+
+} // namespace expression
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index bbb57e19ab..53ce91f0b7 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -485,19 +485,6 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("ceil", [](double x) -> Result<double> { return std::ceil(x); });
define("abs", [](double x) -> Result<double> { return std::abs(x); });
- define(">", [](double lhs, double rhs) -> Result<bool> { return lhs > rhs; });
- define(">", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs > rhs; });
- define(">", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) > 0; });
- define(">=", [](double lhs, double rhs) -> Result<bool> { return lhs >= rhs; });
- define(">=",[](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs >= rhs; });
- define(">=", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) >= 0; });
- define("<", [](double lhs, double rhs) -> Result<bool> { return lhs < rhs; });
- define("<", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs < rhs; });
- define("<", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) < 0; });
- define("<=", [](double lhs, double rhs) -> Result<bool> { return lhs <= rhs; });
- define("<=", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs <= rhs; });
- define("<=", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) <= 0; });
-
define("!", [](bool e) -> Result<bool> { return !e; });
define("is-supported-script", [](const std::string& x) -> Result<bool> {
diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp
index a851d82e16..cdada583a2 100644
--- a/src/mbgl/style/expression/dsl.cpp
+++ b/src/mbgl/style/expression/dsl.cpp
@@ -3,7 +3,7 @@
#include <mbgl/style/expression/literal.hpp>
#include <mbgl/style/expression/assertion.hpp>
#include <mbgl/style/expression/coercion.hpp>
-#include <mbgl/style/expression/equals.hpp>
+#include <mbgl/style/expression/comparison.hpp>
#include <mbgl/style/expression/step.hpp>
#include <mbgl/style/expression/interpolate.hpp>
#include <mbgl/style/expression/compound_expression.hpp>
@@ -53,16 +53,20 @@ std::unique_ptr<Expression> literal(std::initializer_list<const char *> value) {
return literal(values);
}
+std::unique_ptr<Expression> assertion(type::Type type, std::unique_ptr<Expression> value) {
+ return std::make_unique<Assertion>(type, vec(std::move(value)));
+}
+
std::unique_ptr<Expression> number(std::unique_ptr<Expression> value) {
- return std::make_unique<Assertion>(type::Number, vec(std::move(value)));
+ return assertion(type::Number, std::move(value));
}
std::unique_ptr<Expression> string(std::unique_ptr<Expression> value) {
- return std::make_unique<Assertion>(type::String, vec(std::move(value)));
+ return assertion(type::String, std::move(value));
}
std::unique_ptr<Expression> boolean(std::unique_ptr<Expression> value) {
- return std::make_unique<Assertion>(type::Boolean, vec(std::move(value)));
+ return assertion(type::Boolean, std::move(value));
}
std::unique_ptr<Expression> toColor(std::unique_ptr<Expression> value) {
@@ -91,22 +95,22 @@ std::unique_ptr<Expression> zoom() {
std::unique_ptr<Expression> eq(std::unique_ptr<Expression> lhs,
std::unique_ptr<Expression> rhs) {
- return std::make_unique<Equals>(std::move(lhs), std::move(rhs), nullopt, false);
+ return std::make_unique<BasicComparison>("==", std::move(lhs), std::move(rhs));
}
std::unique_ptr<Expression> ne(std::unique_ptr<Expression> lhs,
std::unique_ptr<Expression> rhs) {
- return std::make_unique<Equals>(std::move(lhs), std::move(rhs), nullopt, true);
+ return std::make_unique<BasicComparison>("!=", std::move(lhs), std::move(rhs));
}
std::unique_ptr<Expression> gt(std::unique_ptr<Expression> lhs,
std::unique_ptr<Expression> rhs) {
- return compound(">", std::move(lhs), std::move(rhs));
+ return std::make_unique<BasicComparison>(">", std::move(lhs), std::move(rhs));
}
std::unique_ptr<Expression> lt(std::unique_ptr<Expression> lhs,
std::unique_ptr<Expression> rhs) {
- return compound("<", std::move(lhs), std::move(rhs));
+ return std::make_unique<BasicComparison>("<", std::move(lhs), std::move(rhs));
}
std::unique_ptr<Expression> step(std::unique_ptr<Expression> input,
diff --git a/src/mbgl/style/expression/equals.cpp b/src/mbgl/style/expression/equals.cpp
deleted file mode 100644
index 73e2baf71b..0000000000
--- a/src/mbgl/style/expression/equals.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <mbgl/style/expression/collator.hpp>
-#include <mbgl/style/expression/equals.hpp>
-
-namespace mbgl {
-namespace style {
-namespace expression {
-
-static bool isComparableType(const type::Type& type) {
- return type == type::String ||
- type == type::Number ||
- type == type::Boolean ||
- type == type::Null;
-}
-
-Equals::Equals(std::unique_ptr<Expression> lhs_, std::unique_ptr<Expression> rhs_, optional<std::unique_ptr<Expression>> collator_, bool negate_)
- : Expression(Kind::Equals, type::Boolean),
- lhs(std::move(lhs_)),
- rhs(std::move(rhs_)),
- collator(std::move(collator_)),
- negate(negate_) {
- assert(isComparableType(lhs->getType()) || isComparableType(rhs->getType()));
- assert(lhs->getType() == rhs->getType() || lhs->getType() == type::Value || rhs->getType() == type::Value);
-}
-
-EvaluationResult Equals::evaluate(const EvaluationContext& params) const {
- EvaluationResult lhsResult = lhs->evaluate(params);
- if (!lhsResult) return lhsResult;
-
- EvaluationResult rhsResult = rhs->evaluate(params);
- if (!rhsResult) return lhsResult;
-
- bool result;
-
- if (collator) {
- auto collatorResult = (*collator)->evaluate(params);
- const Collator& c = collatorResult->get<Collator>();
- result = c.compare(lhsResult->get<std::string>(), rhsResult->get<std::string>()) == 0;
- } else {
- result = *lhsResult == *rhsResult;
- }
- if (negate) {
- result = !result;
- }
- return result;
-}
-
-void Equals::eachChild(const std::function<void(const Expression&)>& visit) const {
- visit(*lhs);
- visit(*rhs);
- if (collator) {
- visit(**collator);
- }
-}
-
-bool Equals::operator==(const Expression& e) const {
- if (e.getKind() == Kind::Equals) {
- auto eq = static_cast<const Equals*>(&e);
- return eq->negate == negate && *eq->lhs == *lhs && *eq->rhs == *rhs;
- }
- return false;
-}
-
-std::vector<optional<Value>> Equals::possibleOutputs() const {
- return {{ true }, { false }};
-}
-
-using namespace mbgl::style::conversion;
-ParseResult Equals::parse(const Convertible& value, ParsingContext& ctx) {
- std::size_t length = arrayLength(value);
-
- if (length != 3 && length != 4) {
- ctx.error("Expected two or three arguments.");
- return ParseResult();
- }
-
- bool negate = toString(arrayMember(value, 0)) == std::string("!=");
-
- ParseResult lhs = ctx.parse(arrayMember(value, 1), 1, {type::Value});
- if (!lhs) return ParseResult();
-
- ParseResult rhs = ctx.parse(arrayMember(value, 2), 2, {type::Value});
- if (!rhs) return ParseResult();
-
- type::Type lhsType = (*lhs)->getType();
- type::Type rhsType = (*rhs)->getType();
-
- if (!isComparableType(lhsType) && !isComparableType(rhsType)) {
- ctx.error("Expected at least one argument to be a string, number, boolean, or null, but found (" +
- toString(lhsType) + ", " + toString(rhsType) + ") instead.");
- return ParseResult();
- }
-
- if (lhsType != rhsType && lhsType != type::Value && rhsType != type::Value) {
- ctx.error("Cannot compare " + toString(lhsType) + " and " + toString(rhsType) + ".");
- return ParseResult();
- }
-
- ParseResult collatorParseResult;
- if (length == 4) {
- if (lhsType != type::String && rhsType != type::String) {
- ctx.error("Cannot use collator to compare non-string types.");
- return ParseResult();
- }
- collatorParseResult = ctx.parse(arrayMember(value, 3), 3, {type::Collator});
- if (!collatorParseResult) return ParseResult();
- }
-
- return ParseResult(std::make_unique<Equals>(std::move(*lhs), std::move(*rhs), std::move(collatorParseResult), negate));
-}
-
-} // namespace expression
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp
index 979eb58236..b3f6b1acee 100644
--- a/src/mbgl/style/expression/parsing_context.cpp
+++ b/src/mbgl/style/expression/parsing_context.cpp
@@ -13,7 +13,7 @@
#include <mbgl/style/expression/coalesce.hpp>
#include <mbgl/style/expression/coercion.hpp>
#include <mbgl/style/expression/compound_expression.hpp>
-#include <mbgl/style/expression/equals.hpp>
+#include <mbgl/style/expression/comparison.hpp>
#include <mbgl/style/expression/interpolate.hpp>
#include <mbgl/style/expression/length.hpp>
#include <mbgl/style/expression/let.hpp>
@@ -95,8 +95,12 @@ ParseResult ParsingContext::parse(const Convertible& value, std::size_t index_,
const ExpressionRegistry& getExpressionRegistry() {
static ExpressionRegistry registry {{
- {"==", Equals::parse},
- {"!=", Equals::parse},
+ {"==", parseComparison},
+ {"!=", parseComparison},
+ {">", parseComparison},
+ {"<", parseComparison},
+ {">=", parseComparison},
+ {"<=", parseComparison},
{"all", All::parse},
{"any", Any::parse},
{"array", ArrayAssertion::parse},