#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 " + std::to_string(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) )); } } // namespace expression } // namespace style } // namespace mbgl