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
This commit is contained in:
@@ -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
|
||||
|
||||
68
include/mbgl/style/expression/comparison.hpp
Normal file
68
include/mbgl/style/expression/comparison.hpp
Normal file
@@ -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
|
||||
@@ -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>);
|
||||
|
||||
@@ -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
|
||||
@@ -133,7 +133,7 @@ enum class Kind : int32_t {
|
||||
Case,
|
||||
Any,
|
||||
All,
|
||||
Equals,
|
||||
Comparison,
|
||||
};
|
||||
|
||||
class Expression {
|
||||
|
||||
Submodule mapbox-gl-js updated: dc43a09a6e...47e637c398
275
src/mbgl/style/expression/comparison.cpp
Normal file
275
src/mbgl/style/expression/comparison.cpp
Normal file
@@ -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
|
||||
@@ -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> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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},
|
||||
|
||||
Reference in New Issue
Block a user