1 #include <mbgl/style/expression/coalesce.hpp>
2 #include <mbgl/style/expression/check_subtype.hpp>
3 
4 namespace mbgl {
5 namespace style {
6 namespace expression {
7 
evaluate(const EvaluationContext & params) const8 EvaluationResult Coalesce::evaluate(const EvaluationContext& params) const {
9     EvaluationResult result = Null;
10     for (const auto& arg : args) {
11         result = arg->evaluate(params);
12         if (!result || *result != Null) break;
13     }
14     return result;
15 }
16 
eachChild(const std::function<void (const Expression &)> & visit) const17 void Coalesce::eachChild(const std::function<void(const Expression&)>& visit) const {
18     for (const std::unique_ptr<Expression>& arg : args) {
19         visit(*arg);
20     }
21 }
22 
operator ==(const Expression & e) const23 bool Coalesce::operator==(const Expression& e) const {
24     if (e.getKind() == Kind::Coalesce) {
25         auto rhs = static_cast<const Coalesce*>(&e);
26         return Expression::childrenEqual(args, rhs->args);
27     }
28     return false;
29 }
30 
possibleOutputs() const31 std::vector<optional<Value>> Coalesce::possibleOutputs() const {
32     std::vector<optional<Value>> result;
33     for (const auto& arg : args) {
34         for (auto& output : arg->possibleOutputs()) {
35             result.push_back(std::move(output));
36         }
37     }
38     return result;
39 }
40 
41 using namespace mbgl::style::conversion;
parse(const Convertible & value,ParsingContext & ctx)42 ParseResult Coalesce::parse(const Convertible& value, ParsingContext& ctx) {
43     assert(isArray(value));
44     auto length = arrayLength(value);
45     if (length < 2) {
46         ctx.error("Expected at least one argument.");
47         return ParseResult();
48     }
49 
50     optional<type::Type> outputType;
51     optional<type::Type> expectedType = ctx.getExpected();
52     if (expectedType && *expectedType != type::Value) {
53         outputType = expectedType;
54     }
55 
56     Coalesce::Args args;
57     args.reserve(length - 1);
58     for (std::size_t i = 1; i < length; i++) {
59         auto parsed = ctx.parse(arrayMember(value, i), i, outputType, ParsingContext::omitTypeAnnotations);
60         if (!parsed) {
61             return parsed;
62         }
63         if (!outputType) {
64             outputType = (*parsed)->getType();
65         }
66         args.push_back(std::move(*parsed));
67     }
68     assert(outputType);
69 
70     // Above, we parse arguments without inferred type annotation so that
71     // they don't produce a runtime error for `null` input, which would
72     // preempt the desired null-coalescing behavior.
73     // Thus, if any of our arguments would have needed an annotation, we
74     // need to wrap the enclosing coalesce expression with it instead.
75     bool needsAnnotation = expectedType &&
76         std::any_of(args.begin(), args.end(), [&] (const auto& arg) {
77             return type::checkSubtype(*expectedType, arg->getType());
78         });
79 
80     return ParseResult(std::make_unique<Coalesce>(needsAnnotation ? type::Value : *outputType, std::move(args)));
81 }
82 
83 } // namespace expression
84 } // namespace style
85 } // namespace mbgl
86