1 | #pragma once |
2 | |
3 | #include <mbgl/util/optional.hpp> |
4 | #include <mbgl/util/variant.hpp> |
5 | #include <mbgl/util/color.hpp> |
6 | #include <mbgl/style/expression/type.hpp> |
7 | #include <mbgl/style/expression/value.hpp> |
8 | #include <mbgl/style/expression/parsing_context.hpp> |
9 | |
10 | #include <array> |
11 | #include <vector> |
12 | #include <memory> |
13 | |
14 | namespace mbgl { |
15 | |
16 | class GeometryTileFeature; |
17 | |
18 | namespace style { |
19 | namespace expression { |
20 | |
21 | class EvaluationError { |
22 | public: |
23 | std::string message; |
24 | }; |
25 | |
26 | class EvaluationContext { |
27 | public: |
28 | EvaluationContext(float zoom_) : zoom(zoom_), feature(nullptr) {} |
29 | EvaluationContext(GeometryTileFeature const * feature_) : zoom(optional<float>()), feature(feature_) {} |
30 | EvaluationContext(float zoom_, GeometryTileFeature const * feature_) : |
31 | zoom(zoom_), feature(feature_) |
32 | {} |
33 | EvaluationContext(optional<float> zoom_, GeometryTileFeature const * feature_, optional<double> heatmapDensity_) : |
34 | zoom(std::move(zoom_)), feature(feature_), heatmapDensity(std::move(heatmapDensity_)) |
35 | {} |
36 | |
37 | optional<float> zoom; |
38 | GeometryTileFeature const * feature; |
39 | optional<double> heatmapDensity; |
40 | }; |
41 | |
42 | template <typename T> |
43 | class Result : private variant<EvaluationError, T> { |
44 | public: |
45 | using variant<EvaluationError, T>::variant; |
46 | using Value = T; |
47 | |
48 | Result() = default; |
49 | |
50 | explicit operator bool () const { |
51 | return this->template is<T>(); |
52 | } |
53 | |
54 | // optional does some type trait magic for this one, so this might |
55 | // be problematic as is. |
56 | const T* operator->() const { |
57 | assert(this->template is<T>()); |
58 | return std::addressof(this->template get<T>()); |
59 | } |
60 | |
61 | T* operator->() { |
62 | assert(this->template is<T>()); |
63 | return std::addressof(this->template get<T>()); |
64 | } |
65 | |
66 | T& operator*() { |
67 | assert(this->template is<T>()); |
68 | return this->template get<T>(); |
69 | } |
70 | |
71 | const T& operator*() const { |
72 | assert(this->template is<T>()); |
73 | return this->template get<T>(); |
74 | } |
75 | |
76 | const EvaluationError& error() const { |
77 | assert(this->template is<EvaluationError>()); |
78 | return this->template get<EvaluationError>(); |
79 | } |
80 | }; |
81 | |
82 | class EvaluationResult : public Result<Value> { |
83 | public: |
84 | using Result::Result; // NOLINT |
85 | |
86 | EvaluationResult() = default; |
87 | |
88 | EvaluationResult(const std::array<double, 4>& arr) : |
89 | Result(toExpressionValue(value: arr)) |
90 | {} |
91 | |
92 | // used only for the special (private) "error" expression |
93 | EvaluationResult(const type::ErrorType&) { |
94 | assert(false); |
95 | } |
96 | }; |
97 | |
98 | /* |
99 | Expression is an abstract class that serves as an interface and base class |
100 | for particular expression implementations. |
101 | |
102 | CompoundExpression implements the majority of expressions in the spec by |
103 | inferring the argument and output from a simple function (const T0& arg0, |
104 | const T1& arg1, ...) -> Result<U> where T0, T1, ..., U are member types of |
105 | mbgl::style::expression::Value. |
106 | |
107 | The other Expression subclasses (Let, Curve, Match, etc.) exist in order to |
108 | implement expressions that need specialized parsing, type checking, or |
109 | evaluation logic that can't be handled by CompoundExpression's inference |
110 | mechanism. |
111 | |
112 | Each Expression subclass also provides a static |
113 | ParseResult ExpressionClass::parse(const V&, ParsingContext), |
114 | which handles parsing a style-spec JSON representation of the expression. |
115 | */ |
116 | |
117 | enum class Kind : int32_t { |
118 | Coalesce, |
119 | CompoundExpression, |
120 | Literal, |
121 | ArrayAssertion, |
122 | At, |
123 | Interpolate, |
124 | Assertion, |
125 | Length, |
126 | Step, |
127 | Let, |
128 | Var, |
129 | CollatorExpression, |
130 | Coercion, |
131 | Match, |
132 | Error, |
133 | Case, |
134 | Any, |
135 | All, |
136 | Equals, |
137 | }; |
138 | |
139 | class Expression { |
140 | public: |
141 | Expression(Kind kind_, type::Type type_) : kind(kind_), type(std::move(type_)) {} |
142 | virtual ~Expression() = default; |
143 | |
144 | virtual EvaluationResult evaluate(const EvaluationContext& params) const = 0; |
145 | virtual void eachChild(const std::function<void(const Expression&)>&) const = 0; |
146 | virtual bool operator==(const Expression&) const = 0; |
147 | bool operator!=(const Expression& rhs) const { |
148 | return !operator==(rhs); |
149 | } |
150 | |
151 | Kind getKind() const { return kind; }; |
152 | type::Type getType() const { return type; }; |
153 | |
154 | EvaluationResult evaluate(optional<float> zoom, const Feature& feature, optional<double> heatmapDensity) const; |
155 | |
156 | /** |
157 | * Statically analyze the expression, attempting to enumerate possible outputs. Returns |
158 | * an array of values plus the sentinel null optional value, used to indicate that the |
159 | * complete set of outputs is statically undecidable. |
160 | */ |
161 | virtual std::vector<optional<Value>> possibleOutputs() const = 0; |
162 | |
163 | virtual mbgl::Value serialize() const { |
164 | std::vector<mbgl::Value> serialized; |
165 | serialized.emplace_back(args: getOperator()); |
166 | eachChild([&](const Expression &child) { |
167 | serialized.emplace_back(args: child.serialize()); |
168 | }); |
169 | return serialized; |
170 | }; |
171 | |
172 | virtual std::string getOperator() const = 0; |
173 | |
174 | protected: |
175 | template <typename T> |
176 | static bool childrenEqual(const T& lhs, const T& rhs) { |
177 | if (lhs.size() != rhs.size()) return false; |
178 | for (auto leftChild = lhs.begin(), rightChild = rhs.begin(); |
179 | leftChild != lhs.end(); |
180 | leftChild++, rightChild++) |
181 | { |
182 | if (!Expression::childEqual(*leftChild, *rightChild)) return false; |
183 | } |
184 | return true; |
185 | } |
186 | |
187 | static bool childEqual(const std::unique_ptr<Expression>& lhs, const std::unique_ptr<Expression>& rhs) { |
188 | return *lhs == *rhs; |
189 | } |
190 | |
191 | template <typename T> |
192 | static bool childEqual(const std::pair<T, std::unique_ptr<Expression>>& lhs, |
193 | const std::pair<T, std::unique_ptr<Expression>>& rhs) { |
194 | return lhs.first == rhs.first && *(lhs.second) == *(rhs.second); |
195 | } |
196 | |
197 | template <typename T> |
198 | static bool childEqual(const std::pair<T, std::shared_ptr<Expression>>& lhs, |
199 | const std::pair<T, std::shared_ptr<Expression>>& rhs) { |
200 | return lhs.first == rhs.first && *(lhs.second) == *(rhs.second); |
201 | } |
202 | |
203 | static bool childEqual(const std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>& lhs, |
204 | const std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>& rhs) { |
205 | return *(lhs.first) == *(rhs.first) && *(lhs.second) == *(rhs.second); |
206 | } |
207 | |
208 | private: |
209 | Kind kind; |
210 | type::Type type; |
211 | }; |
212 | |
213 | } // namespace expression |
214 | } // namespace style |
215 | } // namespace mbgl |
216 | |