1 #include <mbgl/style/expression/array_assertion.hpp>
2 #include <mbgl/style/expression/check_subtype.hpp>
3 #include <mbgl/util/string.hpp>
4
5 namespace mbgl {
6 namespace style {
7 namespace expression {
8
evaluate(const EvaluationContext & params) const9 EvaluationResult ArrayAssertion::evaluate(const EvaluationContext& params) const {
10 auto result = input->evaluate(params);
11 if (!result) {
12 return result.error();
13 }
14 type::Type expected = getType();
15 type::Type actual = typeOf(*result);
16 if (checkSubtype(expected, actual)) {
17 return EvaluationError {
18 "Expected value to be of type " + toString(expected) +
19 ", but found " + toString(actual) + " instead."
20 };
21 }
22 return *result;
23 }
24
eachChild(const std::function<void (const Expression &)> & visit) const25 void ArrayAssertion::eachChild(const std::function<void(const Expression&)>& visit) const {
26 visit(*input);
27 }
28
29 using namespace mbgl::style::conversion;
parse(const Convertible & value,ParsingContext & ctx)30 ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext& ctx) {
31
32 static std::unordered_map<std::string, type::Type> itemTypes {
33 {"string", type::String},
34 {"number", type::Number},
35 {"boolean", type::Boolean}
36 };
37
38 auto length = arrayLength(value);
39 if (length < 2 || length > 4) {
40 ctx.error("Expected 1, 2, or 3 arguments, but found " + util::toString(length - 1) + " instead.");
41 return ParseResult();
42 }
43
44 optional<type::Type> itemType;
45 optional<std::size_t> N;
46 if (length > 2) {
47 optional<std::string> itemTypeName = toString(arrayMember(value, 1));
48 auto it = itemTypeName ? itemTypes.find(*itemTypeName) : itemTypes.end();
49 if (it == itemTypes.end()) {
50 ctx.error(
51 R"(The item type argument of "array" must be one of string, number, boolean)",
52 1
53 );
54 return ParseResult();
55 }
56 itemType = it->second;
57 } else {
58 itemType = {type::Value};
59 }
60
61 if (length > 3) {
62 auto n = toNumber(arrayMember(value, 2));
63 if (!n || *n != std::floor(*n)) {
64 ctx.error(
65 R"(The length argument to "array" must be a positive integer literal.)",
66 2
67 );
68 return ParseResult();
69 }
70 N = optional<std::size_t>(*n);
71 }
72
73 auto input = ctx.parse(arrayMember(value, length - 1), length - 1, {type::Value});
74 if (!input) {
75 return input;
76 }
77
78 return ParseResult(std::make_unique<ArrayAssertion>(
79 type::Array(*itemType, N),
80 std::move(*input)
81 ));
82 }
83
serialize() const84 mbgl::Value ArrayAssertion::serialize() const {
85 std::vector<mbgl::Value> serialized;
86 serialized.emplace_back(getOperator());
87
88
89 const auto array = getType().get<type::Array>();
90 if (array.itemType.is<type::StringType>()
91 || array.itemType.is<type::NumberType>()
92 || array.itemType.is<type::BooleanType>()) {
93 serialized.emplace_back(type::toString(array.itemType));
94 if (array.N) {
95 serialized.emplace_back(uint64_t(*array.N));
96 }
97 }
98
99 serialized.emplace_back(input->serialize());
100 return serialized;
101 }
102
103 } // namespace expression
104 } // namespace style
105 } // namespace mbgl
106