1 #include <boost/algorithm/string/join.hpp>
2 #include <mbgl/style/expression/collator.hpp>
3 #include <mbgl/style/expression/compound_expression.hpp>
4 #include <mbgl/style/expression/check_subtype.hpp>
5 #include <mbgl/style/expression/util.hpp>
6 #include <mbgl/tile/geometry_tile_data.hpp>
7 #include <mbgl/math/log2.hpp>
8 #include <mbgl/util/i18n.hpp>
9 #include <mbgl/util/ignore.hpp>
10 #include <mbgl/util/string.hpp>
11 #include <mbgl/util/platform.hpp>
12 #include <cmath>
13
14 namespace mbgl {
15 namespace style {
16 namespace expression {
17
18 namespace detail {
19
20 /*
21 The Signature<Fn> structs are wrappers around an "evaluate()" function whose
22 purpose is to extract the necessary Type data from the evaluate function's
23 type. There are three key (partial) specializations:
24
25 Signature<R (Params...)>:
26 Wraps a simple evaluate function (const T0&, const T1&, ...) -> Result<U>
27
28 Signature<R (const Varargs<T>&)>:
29 Wraps an evaluate function that takes an arbitrary number of arguments (via
30 a Varargs<T>, which is just an alias for std::vector).
31
32 Signature<R (const EvaluationContext&, Params...)>:
33 Wraps an evaluate function that needs to access the expression evaluation
34 parameters in addition to its subexpressions, i.e.,
35 (const EvaluationParams&, const T0&, const T1&, ...) -> Result<U>. Needed
36 for expressions like ["zoom"], ["get", key], etc.
37
38 In each of the above evaluate signatures, T0, T1, etc. are the types of
39 the successfully evaluated subexpressions.
40 */
41 template <class, class Enable = void>
42 struct Signature;
43
44 // Simple evaluate function (const T0&, const T1&, ...) -> Result<U>
45 template <class R, class... Params>
46 struct Signature<R (Params...)> : SignatureBase {
47 using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>;
48
Signaturembgl::style::expression::detail::Signature49 Signature(R (*evaluate_)(Params...), std::string name_) :
50 SignatureBase(
51 valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
52 std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...},
53 std::move(name_)
54 ),
55 evaluate(evaluate_) {}
56
applymbgl::style::expression::detail::Signature57 EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
58 return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{});
59 }
60
makeExpressionmbgl::style::expression::detail::Signature61 std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
62 typename Signature::Args argsArray;
63 std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin());
64 return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray));
65 }
66
67 R (*evaluate)(Params...);
68 private:
69 template <std::size_t ...I>
applyImplmbgl::style::expression::detail::Signature70 EvaluationResult applyImpl(const EvaluationContext& evaluationParameters, const Args& args, std::index_sequence<I...>) const {
71 const std::array<EvaluationResult, sizeof...(I)> evaluated = {{std::get<I>(args)->evaluate(evaluationParameters)...}};
72 for (const auto& arg : evaluated) {
73 if(!arg) return arg.error();
74 }
75 const R value = evaluate(*fromExpressionValue<std::decay_t<Params>>(*(evaluated[I]))...);
76 if (!value) return value.error();
77 return *value;
78 }
79 };
80
81 // Varargs evaluate function (const Varargs<T>&) -> Result<U>
82 template <class R, typename T>
83 struct Signature<R (const Varargs<T>&)> : SignatureBase {
84 using Args = std::vector<std::unique_ptr<Expression>>;
85
Signaturembgl::style::expression::detail::Signature86 Signature(R (*evaluate_)(const Varargs<T>&), std::string name_) :
87 SignatureBase(
88 valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
89 VarargsType { valueTypeToExpressionType<T>() },
90 std::move(name_)
91 ),
92 evaluate(evaluate_)
93 {}
94
makeExpressionmbgl::style::expression::detail::Signature95 std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
96 return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args));
97 };
98
applymbgl::style::expression::detail::Signature99 EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
100 Varargs<T> evaluated;
101 evaluated.reserve(args.size());
102 for (const auto& arg : args) {
103 const EvaluationResult evaluatedArg = arg->evaluate(evaluationParameters);
104 if(!evaluatedArg) return evaluatedArg.error();
105 evaluated.push_back(*fromExpressionValue<std::decay_t<T>>(*evaluatedArg));
106 }
107 const R value = evaluate(evaluated);
108 if (!value) return value.error();
109 return *value;
110 }
111
112 R (*evaluate)(const Varargs<T>&);
113 };
114
115 // Evaluate function needing parameter access,
116 // (const EvaluationParams&, const T0&, const T1&, ...) -> Result<U>
117 template <class R, class... Params>
118 struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase {
119 using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>;
120
Signaturembgl::style::expression::detail::Signature121 Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) :
122 SignatureBase(
123 valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
124 std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...},
125 std::move(name_)
126 ),
127 evaluate(evaluate_)
128 {}
129
makeExpressionmbgl::style::expression::detail::Signature130 std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
131 typename Signature::Args argsArray;
132 std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin());
133 return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray));
134 }
135
applymbgl::style::expression::detail::Signature136 EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
137 return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{});
138 }
139
140 private:
141 template <std::size_t ...I>
applyImplmbgl::style::expression::detail::Signature142 EvaluationResult applyImpl(const EvaluationContext& evaluationParameters, const Args& args, std::index_sequence<I...>) const {
143 const std::array<EvaluationResult, sizeof...(I)> evaluated = {{std::get<I>(args)->evaluate(evaluationParameters)...}};
144 for (const auto& arg : evaluated) {
145 if(!arg) return arg.error();
146 }
147 // TODO: assert correct runtime type of each arg value
148 const R value = evaluate(evaluationParameters, *fromExpressionValue<std::decay_t<Params>>(*(evaluated[I]))...);
149 if (!value) return value.error();
150 return *value;
151 }
152
153 R (*evaluate)(const EvaluationContext&, Params...);
154 };
155
156 // Evaluate function needing EvaluationContext and Varargs
157 // (const EvaluationContext&, const Varargs<T>&) -> Result<U>
158 template <class R, typename T>
159 struct Signature<R (const EvaluationContext&, const Varargs<T>&)> : SignatureBase {
160 using Args = std::vector<std::unique_ptr<Expression>>;
161
Signaturembgl::style::expression::detail::Signature162 Signature(R (*evaluate_)(const EvaluationContext&, const Varargs<T>&), std::string name_) :
163 SignatureBase(
164 valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
165 VarargsType { valueTypeToExpressionType<T>() },
166 std::move(name_)
167 ),
168 evaluate(evaluate_)
169 {}
170
makeExpressionmbgl::style::expression::detail::Signature171 std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
172 return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args));
173 };
174
applymbgl::style::expression::detail::Signature175 EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
176 Varargs<T> evaluated;
177 evaluated.reserve(args.size());
178 for (const auto& arg : args) {
179 const EvaluationResult evaluatedArg = arg->evaluate(evaluationParameters);
180 if(!evaluatedArg) return evaluatedArg.error();
181 evaluated.push_back(*fromExpressionValue<std::decay_t<T>>(*evaluatedArg));
182 }
183 const R value = evaluate(evaluationParameters, evaluated);
184 if (!value) return value.error();
185 return *value;
186 }
187
188 R (*evaluate)(const EvaluationContext&, const Varargs<T>&);
189 };
190
191 // Machinery to pull out function types from class methods, lambdas, etc.
192 template <class R, class... Params>
193 struct Signature<R (*)(Params...)>
194 : Signature<R (Params...)>
195 { using Signature<R (Params...)>::Signature; };
196
197 template <class T, class R, class... Params>
198 struct Signature<R (T::*)(Params...) const>
199 : Signature<R (Params...)>
200 { using Signature<R (Params...)>::Signature; };
201
202 template <class T, class R, class... Params>
203 struct Signature<R (T::*)(Params...)>
204 : Signature<R (Params...)>
205 { using Signature<R (Params...)>::Signature; };
206
207 template <class Lambda>
208 struct Signature<Lambda, std::enable_if_t<std::is_class<Lambda>::value>>
209 : Signature<decltype(&Lambda::operator())>
210 { using Signature<decltype(&Lambda::operator())>::Signature; };
211
212 } // namespace detail
213
214 using Definition = CompoundExpressionRegistry::Definition;
215
216 template <typename Fn>
makeSignature(Fn evaluateFunction,std::string name)217 static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction, std::string name) {
218 return std::make_unique<detail::Signature<Fn>>(evaluateFunction, std::move(name));
219 }
220
featureIdAsExpressionValue(EvaluationContext params)221 Value featureIdAsExpressionValue(EvaluationContext params) {
222 assert(params.feature);
223 auto id = params.feature->getID();
224 if (!id) return Null;
225 return id->match([](const auto& idid) {
226 return toExpressionValue(mbgl::Value(idid));
227 });
228 };
229
featurePropertyAsExpressionValue(EvaluationContext params,const std::string & key)230 optional<Value> featurePropertyAsExpressionValue(EvaluationContext params, const std::string& key) {
231 assert(params.feature);
232 auto property = params.feature->getValue(key);
233 return property ? toExpressionValue(*property) : optional<Value>();
234 };
235
featureTypeAsString(FeatureType type)236 optional<std::string> featureTypeAsString(FeatureType type) {
237 switch(type) {
238 case FeatureType::Point:
239 return optional<std::string>("Point");
240 case FeatureType::LineString:
241 return optional<std::string>("LineString");
242 case FeatureType::Polygon:
243 return optional<std::string>("Polygon");
244 case FeatureType::Unknown:
245 return optional<std::string>("Unknown");
246 default:
247 return {};
248 }
249 };
250
featurePropertyAsDouble(EvaluationContext params,const std::string & key)251 optional<double> featurePropertyAsDouble(EvaluationContext params, const std::string& key) {
252 assert(params.feature);
253 auto property = params.feature->getValue(key);
254 if (!property) return {};
255 return property->match(
256 [](double value) { return value; },
257 [](uint64_t value) { return optional<double>(static_cast<double>(value)); },
258 [](int64_t value) { return optional<double>(static_cast<double>(value)); },
259 [](auto) { return optional<double>(); }
260 );
261 };
262
featurePropertyAsString(EvaluationContext params,const std::string & key)263 optional<std::string> featurePropertyAsString(EvaluationContext params, const std::string& key) {
264 assert(params.feature);
265 auto property = params.feature->getValue(key);
266 if (!property) return {};
267 return property->match(
268 [](std::string value) { return value; },
269 [](auto) { return optional<std::string>(); }
270 );
271 };
272
featureIdAsDouble(EvaluationContext params)273 optional<double> featureIdAsDouble(EvaluationContext params) {
274 assert(params.feature);
275 auto id = params.feature->getID();
276 if (!id) return optional<double>();
277 return id->match(
278 [](double value) { return value; },
279 [](uint64_t value) { return optional<double>(static_cast<double>(value)); },
280 [](int64_t value) { return optional<double>(static_cast<double>(value)); },
281 [](auto) { return optional<double>(); }
282 );
283 };
284
featureIdAsString(EvaluationContext params)285 optional<std::string> featureIdAsString(EvaluationContext params) {
286 assert(params.feature);
287 auto id = params.feature->getID();
288 if (!id) return optional<std::string>();
289 return id->match(
290 [](std::string value) { return value; },
291 [](auto) { return optional<std::string>(); }
292 );
293 };
294
initializeDefinitions()295 std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() {
296 std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions;
297 auto define = [&](std::string name, auto fn) {
298 definitions[name].push_back(makeSignature(fn, name));
299 };
300
301 define("e", []() -> Result<double> { return 2.718281828459045; });
302 define("pi", []() -> Result<double> { return 3.141592653589793; });
303 define("ln2", []() -> Result<double> { return 0.6931471805599453; });
304
305 define("typeof", [](const Value& v) -> Result<std::string> { return toString(typeOf(v)); });
306
307 define("to-string", [](const Value& value) -> Result<std::string> {
308 return value.match(
309 [](const NullValue&) -> Result<std::string> { return std::string(); },
310 [](const Color& c) -> Result<std::string> { return c.stringify(); }, // avoid quoting
311 [](const std::string& s) -> Result<std::string> { return s; }, // avoid quoting
312 [](const auto& v) -> Result<std::string> { return stringify(v); }
313 );
314 });
315
316 define("to-boolean", [](const Value& v) -> Result<bool> {
317 return v.match(
318 [&] (double f) { return static_cast<bool>(f); },
319 [&] (const std::string& s) { return s.length() > 0; },
320 [&] (bool b) { return b; },
321 [&] (const NullValue&) { return false; },
322 [&] (const auto&) { return true; }
323 );
324 });
325 define("to-rgba", [](const Color& color) -> Result<std::array<double, 4>> {
326 return color.toArray();
327 });
328
329 define("rgba", rgba);
330 define("rgb", [](double r, double g, double b) { return rgba(r, g, b, 1.0f); });
331
332 define("zoom", [](const EvaluationContext& params) -> Result<double> {
333 if (!params.zoom) {
334 return EvaluationError {
335 "The 'zoom' expression is unavailable in the current evaluation context."
336 };
337 }
338 return *(params.zoom);
339 });
340
341 define("heatmap-density", [](const EvaluationContext& params) -> Result<double> {
342 if (!params.heatmapDensity) {
343 return EvaluationError {
344 "The 'heatmap-density' expression is unavailable in the current evaluation context."
345 };
346 }
347 return *(params.heatmapDensity);
348 });
349
350 define("has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> {
351 if (!params.feature) {
352 return EvaluationError {
353 "Feature data is unavailable in the current evaluation context."
354 };
355 }
356
357 return params.feature->getValue(key) ? true : false;
358 });
359 define("has", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<bool> {
360 return object.find(key) != object.end();
361 });
362
363 define("get", [](const EvaluationContext& params, const std::string& key) -> Result<Value> {
364 if (!params.feature) {
365 return EvaluationError {
366 "Feature data is unavailable in the current evaluation context."
367 };
368 }
369
370 auto propertyValue = params.feature->getValue(key);
371 if (!propertyValue) {
372 return Null;
373 }
374 return Value(toExpressionValue(*propertyValue));
375 });
376 define("get", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<Value> {
377 if (object.find(key) == object.end()) {
378 return Null;
379 }
380 return object.at(key);
381 });
382
383 define("properties", [](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> {
384 if (!params.feature) {
385 return EvaluationError {
386 "Feature data is unavailable in the current evaluation context."
387 };
388 }
389 std::unordered_map<std::string, Value> result;
390 const PropertyMap properties = params.feature->getProperties();
391 for (const auto& entry : properties) {
392 result[entry.first] = toExpressionValue(entry.second);
393 }
394 return result;
395 });
396
397 define("geometry-type", [](const EvaluationContext& params) -> Result<std::string> {
398 if (!params.feature) {
399 return EvaluationError {
400 "Feature data is unavailable in the current evaluation context."
401 };
402 }
403
404 auto type = params.feature->getType();
405 if (type == FeatureType::Point) {
406 return "Point";
407 } else if (type == FeatureType::LineString) {
408 return "LineString";
409 } else if (type == FeatureType::Polygon) {
410 return "Polygon";
411 } else {
412 return "Unknown";
413 }
414 });
415
416 define("id", [](const EvaluationContext& params) -> Result<Value> {
417 if (!params.feature) {
418 return EvaluationError {
419 "Feature data is unavailable in the current evaluation context."
420 };
421 }
422
423 auto id = params.feature->getID();
424 if (!id) {
425 return Null;
426 }
427 return id->match(
428 [](const auto& idValue) {
429 return toExpressionValue(mbgl::Value(idValue));
430 }
431 );
432 });
433
434 define("+", [](const Varargs<double>& args) -> Result<double> {
435 double sum = 0.0f;
436 for (auto arg : args) {
437 sum += arg;
438 }
439 return sum;
440 });
441 define("-", [](double a, double b) -> Result<double> { return a - b; });
442 define("-", [](double a) -> Result<double> { return -a; });
443 define("*", [](const Varargs<double>& args) -> Result<double> {
444 double prod = 1.0f;
445 for (auto arg : args) {
446 prod *= arg;
447 }
448 return prod;
449 });
450 define("/", [](double a, double b) -> Result<double> { return a / b; });
451 define("%", [](double a, double b) -> Result<double> { return fmod(a, b); });
452 define("^", [](double a, double b) -> Result<double> { return pow(a, b); });
453 define("sqrt", [](double x) -> Result<double> { return sqrt(x); });
454 define("log10", [](double x) -> Result<double> { return log10(x); });
455 define("ln", [](double x) -> Result<double> { return log(x); });
456 define("log2", [](double x) -> Result<double> { return log2(x); });
457 define("sin", [](double x) -> Result<double> { return sin(x); });
458 define("cos", [](double x) -> Result<double> { return cos(x); });
459 define("tan", [](double x) -> Result<double> { return tan(x); });
460 define("asin", [](double x) -> Result<double> { return asin(x); });
461 define("acos", [](double x) -> Result<double> { return acos(x); });
462 define("atan", [](double x) -> Result<double> { return atan(x); });
463
464 define("min", [](const Varargs<double>& args) -> Result<double> {
465 double result = std::numeric_limits<double>::infinity();
466 for (double arg : args) {
467 result = fmin(arg, result);
468 }
469 return result;
470 });
471 define("max", [](const Varargs<double>& args) -> Result<double> {
472 double result = -std::numeric_limits<double>::infinity();
473 for (double arg : args) {
474 result = fmax(arg, result);
475 }
476 return result;
477 });
478
479 define("round", [](double x) -> Result<double> { return ::round(x); });
480 define("floor", [](double x) -> Result<double> { return std::floor(x); });
481 define("ceil", [](double x) -> Result<double> { return std::ceil(x); });
482 define("abs", [](double x) -> Result<double> { return std::abs(x); });
483
484 define(">", [](double lhs, double rhs) -> Result<bool> { return lhs > rhs; });
485 define(">", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs > rhs; });
486 define(">", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) > 0; });
487 define(">=", [](double lhs, double rhs) -> Result<bool> { return lhs >= rhs; });
488 define(">=",[](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs >= rhs; });
489 define(">=", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) >= 0; });
490 define("<", [](double lhs, double rhs) -> Result<bool> { return lhs < rhs; });
491 define("<", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs < rhs; });
492 define("<", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) < 0; });
493 define("<=", [](double lhs, double rhs) -> Result<bool> { return lhs <= rhs; });
494 define("<=", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs <= rhs; });
495 define("<=", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) <= 0; });
496
497 define("!", [](bool e) -> Result<bool> { return !e; });
498
499 define("is-supported-script", [](const std::string& x) -> Result<bool> {
500 return util::i18n::isStringInSupportedScript(x);
501 });
502
503 define("upcase", [](const std::string& input) -> Result<std::string> {
504 return platform::uppercase(input);
505 });
506 define("downcase", [](const std::string& input) -> Result<std::string> {
507 return platform::lowercase(input);
508 });
509 define("concat", [](const Varargs<std::string>& args) -> Result<std::string> {
510 std::string s;
511 for (const std::string& arg : args) {
512 s += arg;
513 }
514 return s;
515 });
516 define("resolved-locale", [](const Collator& collator) -> Result<std::string> {
517 return collator.resolvedLocale();
518 });
519
520 define("error", [](const std::string& input) -> Result<type::ErrorType> {
521 return EvaluationError { input };
522 });
523
524 // Legacy Filters
525 define("filter-==", [](const EvaluationContext& params, const std::string& key, const Value &lhs) -> Result<bool> {
526 const auto rhs = featurePropertyAsExpressionValue(params, key);
527 return rhs ? lhs == *rhs : false;
528 });
529
530 define("filter-id-==", [](const EvaluationContext& params, const Value &lhs) -> Result<bool> {
531 return lhs == featureIdAsExpressionValue(params);
532 });
533
534 define("filter-type-==", [](const EvaluationContext& params, const std::string &lhs) -> Result<bool> {
535 if (!params.feature) return false;
536 return featureTypeAsString(params.feature->getType()) == lhs;
537 });
538
539 define("filter-<", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
540 auto rhs = featurePropertyAsDouble(params, key);
541 return rhs ? rhs < lhs : false;
542 });
543
544 define("filter-<", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
545 auto rhs = featurePropertyAsString(params, key);
546 return rhs ? rhs < lhs : false;
547 });
548
549 define("filter-id-<", [](const EvaluationContext& params, double lhs) -> Result<bool> {
550 auto rhs = featureIdAsDouble(params);
551 return rhs ? rhs < lhs : false;
552 });
553
554 define("filter-id-<", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
555 auto rhs = featureIdAsString(params);
556 return rhs ? rhs < lhs : false;
557 });
558
559 define("filter->", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
560 auto rhs = featurePropertyAsDouble(params, key);
561 return rhs ? rhs > lhs : false;
562 });
563
564 define("filter->", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
565 auto rhs = featurePropertyAsString(params, key);
566 return rhs ? rhs > lhs : false;
567 });
568
569 define("filter-id->", [](const EvaluationContext& params, double lhs) -> Result<bool> {
570 auto rhs = featureIdAsDouble(params);
571 return rhs ? rhs > lhs : false;
572 });
573
574 define("filter-id->", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
575 auto rhs = featureIdAsString(params);
576 return rhs ? rhs > lhs : false;
577 });
578
579 define("filter-<=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
580 auto rhs = featurePropertyAsDouble(params, key);
581 return rhs ? rhs <= lhs : false;
582 });
583
584 define("filter-<=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
585 auto rhs = featurePropertyAsString(params, key);
586 return rhs ? rhs <= lhs : false;
587 });
588
589 define("filter-id-<=", [](const EvaluationContext& params, double lhs) -> Result<bool> {
590 auto rhs = featureIdAsDouble(params);
591 return rhs ? rhs <= lhs : false;
592 });
593
594 define("filter-id-<=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
595 auto rhs = featureIdAsString(params);
596 return rhs ? rhs <= lhs : false;
597 });
598
599 define("filter->=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
600 auto rhs = featurePropertyAsDouble(params, key);
601 return rhs ? rhs >= lhs : false;
602 });
603
604 define("filter->=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
605 auto rhs = featurePropertyAsString(params, key);
606 return rhs ? rhs >= lhs : false;
607 });
608
609 define("filter-id->=", [](const EvaluationContext& params, double lhs) -> Result<bool> {
610 auto rhs = featureIdAsDouble(params);
611 return rhs ? rhs >= lhs : false;
612 });
613
614 define("filter-id->=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
615 auto rhs = featureIdAsString(params);
616 return rhs ? rhs >= lhs : false;
617 });
618
619 define("filter-has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> {
620 assert(params.feature);
621 return bool(params.feature->getValue(key));
622 });
623
624 define("filter-has-id", [](const EvaluationContext& params) -> Result<bool> {
625 assert(params.feature);
626 return bool(params.feature->getID());
627 });
628
629 define("filter-type-in", [](const EvaluationContext& params, const Varargs<std::string>& types) -> Result<bool> {
630 assert(params.feature);
631 optional<std::string> type = featureTypeAsString(params.feature->getType());
632 return std::find(types.begin(), types.end(), type) != types.end();
633 });
634
635 define("filter-id-in", [](const EvaluationContext& params, const Varargs<Value>& ids) -> Result<bool> {
636 auto id = featureIdAsExpressionValue(params);
637 return std::find(ids.begin(), ids.end(), id) != ids.end();
638 });
639
640 define("filter-in", [](const EvaluationContext& params, const Varargs<Value>& varargs) -> Result<bool> {
641 if (varargs.size() < 2) return false;
642 assert(varargs[0].is<std::string>());
643 auto value = featurePropertyAsExpressionValue(params, varargs[0].get<std::string>());
644 return value ? std::find(varargs.begin() + 1, varargs.end(), *value) != varargs.end() : false;
645 });
646
647 return definitions;
648 }
649
650 std::unordered_map<std::string, Definition> CompoundExpressionRegistry::definitions = initializeDefinitions();
651
652 using namespace mbgl::style::conversion;
653
createCompoundExpression(const Definition & definition,std::vector<std::unique_ptr<Expression>> args,ParsingContext & ctx)654 static ParseResult createCompoundExpression(const Definition& definition,
655 std::vector<std::unique_ptr<Expression>> args,
656 ParsingContext& ctx)
657 {
658 ParsingContext signatureContext(ctx.getKey());
659
660 for (const std::unique_ptr<detail::SignatureBase>& signature : definition) {
661 signatureContext.clearErrors();
662
663 if (signature->params.is<std::vector<type::Type>>()) {
664 const std::vector<type::Type>& params = signature->params.get<std::vector<type::Type>>();
665 if (params.size() != args.size()) {
666 signatureContext.error(
667 "Expected " + util::toString(params.size()) +
668 " arguments, but found " + util::toString(args.size()) + " instead."
669 );
670 continue;
671 }
672
673 for (std::size_t i = 0; i < args.size(); i++) {
674 const std::unique_ptr<Expression>& arg = args[i];
675 optional<std::string> err = type::checkSubtype(params.at(i), arg->getType());
676 if (err) {
677 signatureContext.error(*err, i + 1);
678 }
679 }
680 } else if (signature->params.is<VarargsType>()) {
681 const type::Type& paramType = signature->params.get<VarargsType>().type;
682 for (std::size_t i = 0; i < args.size(); i++) {
683 const std::unique_ptr<Expression>& arg = args[i];
684 optional<std::string> err = type::checkSubtype(paramType, arg->getType());
685 if (err) {
686 signatureContext.error(*err, i + 1);
687 }
688 }
689 }
690
691 if (signatureContext.getErrors().size() == 0) {
692 return ParseResult(signature->makeExpression(std::move(args)));
693 }
694 }
695
696 if (definition.size() == 1) {
697 ctx.appendErrors(std::move(signatureContext));
698 } else {
699 std::vector<std::string> availableOverloads; // Only used if there are no overloads with matching number of args
700 std::vector<std::string> overloads;
701 for (const auto& signature : definition) {
702 signature->params.match(
703 [&](const VarargsType& varargs) {
704 std::string overload = "(" + toString(varargs.type) + ")";
705 overloads.push_back(overload);
706 },
707 [&](const std::vector<type::Type>& params) {
708 std::string overload = "(";
709 bool first = true;
710 for (const type::Type& param : params) {
711 if (!first) overload += ", ";
712 overload += toString(param);
713 first = false;
714 }
715 overload += ")";
716 if (params.size() == args.size()) {
717 overloads.push_back(overload);
718 } else {
719 availableOverloads.push_back(overload);
720 }
721 }
722 );
723
724 }
725 std::string signatures = overloads.empty() ?
726 boost::algorithm::join(availableOverloads, " | ") :
727 boost::algorithm::join(overloads, " | ");
728 std::string actualTypes;
729 for (const auto& arg : args) {
730 if (actualTypes.size() > 0) {
731 actualTypes += ", ";
732 }
733 actualTypes += toString(arg->getType());
734 }
735 ctx.error("Expected arguments of type " + signatures + ", but found (" + actualTypes + ") instead.");
736 }
737
738 return ParseResult();
739 }
740
parseCompoundExpression(const std::string name,const Convertible & value,ParsingContext & ctx)741 ParseResult parseCompoundExpression(const std::string name, const Convertible& value, ParsingContext& ctx) {
742 assert(isArray(value) && arrayLength(value) > 0);
743
744 auto it = CompoundExpressionRegistry::definitions.find(name);
745 if (it == CompoundExpressionRegistry::definitions.end()) {
746 ctx.error(
747 R"(Unknown expression ")" + name + R"(". If you wanted a literal array, use ["literal", [...]].)",
748 0
749 );
750 return ParseResult();
751 }
752 const CompoundExpressionRegistry::Definition& definition = it->second;
753
754 auto length = arrayLength(value);
755
756 // Check if we have a single signature with the correct number of
757 // parameters. If so, then use that signature's parameter types for parsing
758 // (and inferring the types of) the arguments.
759 optional<std::size_t> singleMatchingSignature;
760 for (std::size_t j = 0; j < definition.size(); j++) {
761 const std::unique_ptr<detail::SignatureBase>& signature = definition[j];
762 if (
763 signature->params.is<VarargsType>() ||
764 signature->params.get<std::vector<type::Type>>().size() == length - 1
765 ) {
766 if (singleMatchingSignature) {
767 singleMatchingSignature = {};
768 } else {
769 singleMatchingSignature = j;
770 }
771 }
772 }
773
774 // parse subexpressions first
775 std::vector<std::unique_ptr<Expression>> args;
776 args.reserve(length - 1);
777 for (std::size_t i = 1; i < length; i++) {
778 optional<type::Type> expected;
779
780 if (singleMatchingSignature) {
781 expected = definition[*singleMatchingSignature]->params.match(
782 [](const VarargsType& varargs) { return varargs.type; },
783 [&](const std::vector<type::Type>& params_) { return params_[i - 1]; }
784 );
785 }
786
787 auto parsed = ctx.parse(arrayMember(value, i), i, expected);
788 if (!parsed) {
789 return parsed;
790 }
791 args.push_back(std::move(*parsed));
792 }
793
794 return createCompoundExpression(definition, std::move(args), ctx);
795 }
796
createCompoundExpression(const std::string & name,std::vector<std::unique_ptr<Expression>> args,ParsingContext & ctx)797 ParseResult createCompoundExpression(const std::string& name,
798 std::vector<std::unique_ptr<Expression>> args,
799 ParsingContext& ctx)
800 {
801 return createCompoundExpression(CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx);
802 }
803
804 } // namespace expression
805 } // namespace style
806 } // namespace mbgl
807