From 2c48b5a292f315feb1aa53a3a61b629bfe5f4a05 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 11 Sep 2018 12:48:07 -0700 Subject: [core] Implement array assertion fallback behavior This was added in gl-js in #7095. --- cmake/core-files.txt | 2 - include/mbgl/style/expression/array_assertion.hpp | 47 ---------- include/mbgl/style/expression/assertion.hpp | 1 + include/mbgl/style/expression/expression.hpp | 1 - src/mbgl/style/conversion/function.cpp | 4 +- src/mbgl/style/expression/array_assertion.cpp | 106 ---------------------- src/mbgl/style/expression/assertion.cpp | 79 ++++++++++++++-- src/mbgl/style/expression/parsing_context.cpp | 12 +-- 8 files changed, 78 insertions(+), 174 deletions(-) delete mode 100644 include/mbgl/style/expression/array_assertion.hpp delete mode 100644 src/mbgl/style/expression/array_assertion.cpp diff --git a/cmake/core-files.txt b/cmake/core-files.txt index 6361540eb3..2db2d5bf87 100644 --- a/cmake/core-files.txt +++ b/cmake/core-files.txt @@ -450,7 +450,6 @@ src/mbgl/style/conversion/tileset.cpp src/mbgl/style/conversion/transition_options.cpp # style/expression -include/mbgl/style/expression/array_assertion.hpp include/mbgl/style/expression/assertion.hpp include/mbgl/style/expression/at.hpp include/mbgl/style/expression/boolean_operator.hpp @@ -479,7 +478,6 @@ include/mbgl/style/expression/parsing_context.hpp include/mbgl/style/expression/step.hpp include/mbgl/style/expression/type.hpp include/mbgl/style/expression/value.hpp -src/mbgl/style/expression/array_assertion.cpp src/mbgl/style/expression/assertion.cpp src/mbgl/style/expression/at.cpp src/mbgl/style/expression/boolean_operator.cpp diff --git a/include/mbgl/style/expression/array_assertion.hpp b/include/mbgl/style/expression/array_assertion.hpp deleted file mode 100644 index 0c0912b73e..0000000000 --- a/include/mbgl/style/expression/array_assertion.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include - -namespace mbgl { -namespace style { -namespace expression { - -class ArrayAssertion : public Expression { -public: - ArrayAssertion(type::Array type_, std::unique_ptr input_) : - Expression(Kind::ArrayAssertion, type_), - input(std::move(input_)) - {} - - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); - - EvaluationResult evaluate(const EvaluationContext& params) const override; - void eachChild(const std::function& visit) const override; - - bool operator==(const Expression& e) const override { - if (e.getKind() == Kind::ArrayAssertion) { - auto rhs = static_cast(&e); - return getType() == rhs->getType() && *input == *(rhs->input); - } - return false; - } - - std::vector> possibleOutputs() const override { - return input->possibleOutputs(); - } - - mbgl::Value serialize() const override; - std::string getOperator() const override { return "array"; } - -private: - std::unique_ptr input; -}; - -} // namespace expression -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp index 239cdf2ea6..0dec89dac9 100644 --- a/include/mbgl/style/expression/assertion.hpp +++ b/include/mbgl/style/expression/assertion.hpp @@ -24,6 +24,7 @@ public: std::vector> possibleOutputs() const override; + mbgl::Value serialize() const override; std::string getOperator() const override; private: diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index bfd1e08ee7..ce02c4114b 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -118,7 +118,6 @@ enum class Kind : int32_t { Coalesce, CompoundExpression, Literal, - ArrayAssertion, At, Interpolate, Assertion, diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp index 2ce2f4eafd..7cc599be1d 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -679,8 +678,7 @@ optional> convertFunctionToExpression(type::Type typ return toColor(get(literal(*property))); }, [&] (const type::Array& array) -> optional> { - return std::unique_ptr( - std::make_unique(array, get(literal(*property)))); + return assertion(array, get(literal(*property))); }, [&] (const auto&) -> optional> { assert(false); // No properties use this type. diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp deleted file mode 100644 index 9df586bdc3..0000000000 --- a/src/mbgl/style/expression/array_assertion.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#include -#include - -namespace mbgl { -namespace style { -namespace expression { - -EvaluationResult ArrayAssertion::evaluate(const EvaluationContext& params) const { - auto result = input->evaluate(params); - if (!result) { - return result.error(); - } - type::Type expected = getType(); - type::Type actual = typeOf(*result); - if (checkSubtype(expected, actual)) { - return EvaluationError { - "Expected value to be of type " + toString(expected) + - ", but found " + toString(actual) + " instead." - }; - } - return *result; -} - -void ArrayAssertion::eachChild(const std::function& visit) const { - visit(*input); -} - -using namespace mbgl::style::conversion; -ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext& ctx) { - - static std::unordered_map itemTypes { - {"string", type::String}, - {"number", type::Number}, - {"boolean", type::Boolean} - }; - - auto length = arrayLength(value); - if (length < 2 || length > 4) { - ctx.error("Expected 1, 2, or 3 arguments, but found " + util::toString(length - 1) + " instead."); - return ParseResult(); - } - - optional itemType; - optional N; - if (length > 2) { - optional itemTypeName = toString(arrayMember(value, 1)); - auto it = itemTypeName ? itemTypes.find(*itemTypeName) : itemTypes.end(); - if (it == itemTypes.end()) { - ctx.error( - R"(The item type argument of "array" must be one of string, number, boolean)", - 1 - ); - return ParseResult(); - } - itemType = it->second; - } else { - itemType = {type::Value}; - } - - if (length > 3) { - auto n = toNumber(arrayMember(value, 2)); - if (!n || *n != std::floor(*n)) { - ctx.error( - R"(The length argument to "array" must be a positive integer literal.)", - 2 - ); - return ParseResult(); - } - N = optional(*n); - } - - auto input = ctx.parse(arrayMember(value, length - 1), length - 1, {type::Value}); - if (!input) { - return input; - } - - return ParseResult(std::make_unique( - type::Array(*itemType, N), - std::move(*input) - )); -} - -mbgl::Value ArrayAssertion::serialize() const { - std::vector serialized; - serialized.emplace_back(getOperator()); - - - const auto array = getType().get(); - if (array.itemType.is() - || array.itemType.is() - || array.itemType.is()) { - serialized.emplace_back(type::toString(array.itemType)); - if (array.N) { - serialized.emplace_back(uint64_t(*array.N)); - } - } - - serialized.emplace_back(input->serialize()); - return serialized; -} - -} // namespace expression -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 7e93003ac3..8e5a8b555d 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -30,22 +30,64 @@ ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(); } - auto it = types.find(*toString(arrayMember(value, 0))); - assert(it != types.end()); - + std::size_t i = 1; + type::Type type; + + std::string name = *toString(arrayMember(value, 0)); + if (name == "array") { + optional itemType; + if (length > 2) { + optional itemTypeName = toString(arrayMember(value, 1)); + auto it = itemTypeName ? types.find(*itemTypeName) : types.end(); + if (it == types.end() || it->second == type::Object) { + ctx.error( + R"(The item type argument of "array" must be one of string, number, boolean)", + 1 + ); + return ParseResult(); + } + itemType = it->second; + i++; + } else { + itemType = {type::Value}; + } + + optional N; + if (length > 3) { + auto m = arrayMember(value, 2); + optional n = toNumber(m); + if (!isUndefined(m) && + (!n || *n < 0 || *n != std::floor(*n))) { + ctx.error( + R"(The length argument to "array" must be a positive integer literal.)", + 2 + ); + return ParseResult(); + } + if (n) { + N = optional(*n); + } + i++; + } + + type = type::Array(*itemType, N); + } else { + type = types.at(name); + } + std::vector> parsed; parsed.reserve(length - 1); - for (std::size_t i = 1; i < length; i++) { + for (; i < length; i++) { ParseResult input = ctx.parse(arrayMember(value, i), i, {type::Value}); if (!input) return ParseResult(); parsed.push_back(std::move(*input)); } - return ParseResult(std::make_unique(it->second, std::move(parsed))); + return ParseResult(std::make_unique(type, std::move(parsed))); } std::string Assertion::getOperator() const { - return type::toString(getType()); + return getType().is() ? "array" : type::toString(getType()); } EvaluationResult Assertion::evaluate(const EvaluationContext& params) const { @@ -90,6 +132,31 @@ std::vector> Assertion::possibleOutputs() const { return result; } +mbgl::Value Assertion::serialize() const { + std::vector serialized; + serialized.emplace_back(getOperator()); + + if (getType().is()) { + const auto array = getType().get(); + if (array.itemType.is() + || array.itemType.is() + || array.itemType.is()) { + serialized.emplace_back(type::toString(array.itemType)); + if (array.N) { + serialized.emplace_back(uint64_t(*array.N)); + } else if (inputs.size() > 1) { + serialized.emplace_back(mbgl::NullValue()); + } + } + } + + for (const auto& input : inputs) { + serialized.emplace_back(input->serialize()); + } + + return serialized; +} + } // 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 3fe50aa1e4..29d04d96a2 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -46,8 +45,7 @@ bool isConstant(const Expression& expression) { } bool isTypeAnnotation = expression.getKind() == Kind::Coercion || - expression.getKind() == Kind::Assertion || - expression.getKind() == Kind::ArrayAssertion; + expression.getKind() == Kind::Assertion; bool childrenConstant = true; expression.eachChild([&](const Expression& child) { @@ -105,7 +103,7 @@ const ExpressionRegistry& getExpressionRegistry() { {"<=", parseComparison}, {"all", All::parse}, {"any", Any::parse}, - {"array", ArrayAssertion::parse}, + {"array", Assertion::parse}, {"at", At::parse}, {"boolean", Assertion::parse}, {"case", Case::parse}, @@ -171,14 +169,10 @@ ParseResult ParsingContext::parse(const Convertible& value, TypeAnnotationOption if (expected) { const type::Type actual = (*parsed)->getType(); - if ((*expected == type::String || *expected == type::Number || *expected == type::Boolean || *expected == type::Object) && actual == type::Value) { + if ((*expected == type::String || *expected == type::Number || *expected == type::Boolean || *expected == type::Object || expected->is()) && actual == type::Value) { if (typeAnnotationOption == includeTypeAnnotations) { parsed = { std::make_unique(*expected, array(std::move(*parsed))) }; } - } else if (expected->is() && actual == type::Value) { - if (typeAnnotationOption == includeTypeAnnotations) { - parsed = { std::make_unique(expected->get(), std::move(*parsed)) }; - } } else if (*expected == type::Color && (actual == type::Value || actual == type::String)) { if (typeAnnotationOption == includeTypeAnnotations) { parsed = { std::make_unique(*expected, array(std::move(*parsed))) }; -- cgit v1.2.1