1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
#include <string>
#include <mbgl/style/expression/check_subtype.hpp>
namespace mbgl {
namespace style {
namespace expression {
namespace type {
std::string errorMessage(const Type& expected, const Type& t) {
return {"Expected " + toString(expected) + " but found " + toString(t) + " instead."};
}
optional<std::string> checkSubtype(const Type& expected, const Type& t) {
if (t.is<ErrorType>()) return {};
optional<std::string> result = expected.match(
[&] (const Array& expectedArray) -> optional<std::string> {
if (!t.is<Array>()) {
return {errorMessage(expected, t)};
}
const auto& actualArray = t.get<Array>();
if (!actualArray.N || *actualArray.N != 0 || actualArray.itemType != type::Value) {
const auto err = checkSubtype(expectedArray.itemType, actualArray.itemType);
if (err) {
return { errorMessage(expected, t) };
}
}
if (expectedArray.N && expectedArray.N != actualArray.N) {
return { errorMessage(expected, t) };
}
return {};
},
[&] (const ValueType&) -> optional<std::string> {
if (t.is<ValueType>()) return {};
const Type members[] = {
Null,
Boolean,
Number,
String,
Object,
Color,
Formatted,
Array(Value)
};
for (const auto& member : members) {
const auto err = checkSubtype(member, t);
if (!err) {
return {};
}
}
return { errorMessage(expected, t) };
},
[&] (const auto&) -> optional<std::string> {
if (expected != t) {
return { errorMessage(expected, t) };
}
return {};
}
);
return result;
}
} // namespace type
} // namespace expression
} // namespace style
} // namespace mbgl
|