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