1 #include <mbgl/style/expression/find_zoom_curve.hpp>
2 #include <mbgl/style/expression/compound_expression.hpp>
3 #include <mbgl/style/expression/let.hpp>
4 #include <mbgl/style/expression/coalesce.hpp>
5 #include <mbgl/style/expression/is_constant.hpp>
6 
7 #include <mbgl/util/variant.hpp>
8 #include <mbgl/util/optional.hpp>
9 
10 namespace mbgl {
11 namespace style {
12 namespace expression {
13 
findZoomCurve(const expression::Expression * e)14 optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCurve(const expression::Expression* e) {
15     optional<variant<const Interpolate*, const Step*, ParsingError>> result;
16 
17     switch (e->getKind()) {
18     case Kind::Let: {
19         auto let = static_cast<const Let*>(e);
20         result = findZoomCurve(let->getResult());
21         break;
22     }
23     case Kind::Coalesce: {
24         auto coalesce = static_cast<const Coalesce*>(e);
25         std::size_t length = coalesce->getLength();
26         for (std::size_t i = 0; i < length; i++) {
27             result = findZoomCurve(coalesce->getChild(i));
28             if (result) {
29                 break;
30             }
31         }
32         break;
33     }
34     case Kind::Interpolate: {
35         auto curve = static_cast<const Interpolate*>(e);
36         if (curve->getInput()->getKind() == Kind::CompoundExpression) {
37             auto z = static_cast<CompoundExpressionBase*>(curve->getInput().get());
38             if (z && z->getName() == "zoom") {
39                 result = {curve};
40             }
41         }
42         break;
43     }
44     case Kind::Step: {
45         auto step = static_cast<const Step*>(e);
46         if (step->getInput()->getKind() == Kind::CompoundExpression) {
47             auto z = static_cast<CompoundExpressionBase*>(step->getInput().get());
48             if (z && z->getName() == "zoom") {
49                 result = {step};
50             }
51         }
52         break;
53     }
54     default:
55         break;
56     }
57 
58     if (result && result->is<ParsingError>()) {
59         return result;
60     }
61 
62     e->eachChild([&](const Expression& child) {
63         optional<variant<const Interpolate*, const Step*, ParsingError>> childResult(findZoomCurve(&child));
64         if (childResult) {
65             if (childResult->is<ParsingError>()) {
66                 result = childResult;
67             } else if (!result && childResult) {
68                 result = {ParsingError {
69                     R"("zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.)", ""
70                 }};
71             } else if (result && childResult && result != childResult) {
72                 result = {ParsingError {
73                     R"(Only one zoom-based "step" or "interpolate" subexpression may be used in an expression.)", ""
74                 }};
75             }
76         }
77     });
78 
79     return result;
80 }
81 
findZoomCurveChecked(const expression::Expression * e)82 variant<std::nullptr_t, const Interpolate*, const Step*> findZoomCurveChecked(const expression::Expression* e) {
83     if (isZoomConstant(*e)) {
84         return nullptr;
85     }
86     return findZoomCurve(e)->match(
87         [](const ParsingError&) -> variant<std::nullptr_t, const Interpolate*, const Step*> {
88             assert(false);
89             return nullptr;
90         },
91         [](auto zoomCurve) -> variant<std::nullptr_t, const Interpolate*, const Step*> {
92             return zoomCurve;
93         }
94     );
95 }
96 
97 } // namespace expression
98 } // namespace style
99 } // namespace mbgl
100