1 #include <mbgl/style/conversion/function.hpp>
2 #include <mbgl/style/expression/dsl.hpp>
3 #include <mbgl/style/expression/step.hpp>
4 #include <mbgl/style/expression/interpolate.hpp>
5 #include <mbgl/style/expression/match.hpp>
6 #include <mbgl/style/expression/case.hpp>
7 #include <mbgl/style/expression/array_assertion.hpp>
8 #include <mbgl/util/string.hpp>
9 
10 #include <cassert>
11 
12 namespace mbgl {
13 namespace style {
14 namespace conversion {
15 
16 using namespace expression;
17 using namespace expression::dsl;
18 
19 const static std::string tokenReservedChars = "{}";
20 
hasTokens(const std::string & source)21 bool hasTokens(const std::string& source) {
22     auto pos = source.begin();
23     const auto end = source.end();
24 
25     while (pos != end) {
26         auto brace = std::find(pos, end, '{');
27         if (brace == end)
28             return false;
29         for (brace++; brace != end && tokenReservedChars.find(*brace) == std::string::npos; brace++);
30         if (brace != end && *brace == '}') {
31             return true;
32         }
33         pos = brace;
34     }
35 
36     return false;
37 }
38 
convertTokenStringToExpression(const std::string & source)39 std::unique_ptr<Expression> convertTokenStringToExpression(const std::string& source) {
40     std::vector<std::unique_ptr<Expression>> inputs;
41 
42     auto pos = source.begin();
43     const auto end = source.end();
44 
45     while (pos != end) {
46         auto brace = std::find(pos, end, '{');
47         if (pos != brace) {
48             inputs.push_back(literal(std::string(pos, brace)));
49         }
50         pos = brace;
51         if (pos != end) {
52             for (brace++; brace != end && tokenReservedChars.find(*brace) == std::string::npos; brace++);
53             if (brace != end && *brace == '}') {
54                 inputs.push_back(toString(get(literal(std::string(pos + 1, brace)))));
55                 pos = brace + 1;
56             } else {
57                 inputs.push_back(literal(std::string(pos, brace)));
58                 pos = brace;
59             }
60         }
61     }
62 
63     switch (inputs.size()) {
64     case 0:
65         return literal(source);
66     case 1:
67         return std::move(inputs[0]);
68     default:
69         return concat(std::move(inputs));
70     }
71 }
72 
73 // Ad-hoc Converters for double and int64_t. We should replace float with double wholesale,
74 // and promote the int64_t Converter to general use (and it should check that the input is
75 // an integer).
76 template <>
77 struct Converter<double> {
operator ()mbgl::style::conversion::Converter78     optional<double> operator()(const Convertible& value, Error& error) const {
79         auto converted = convert<float>(value, error);
80         if (!converted) {
81             return {};
82         }
83         return *converted;
84     }
85 };
86 
87 template <>
88 struct Converter<int64_t> {
operator ()mbgl::style::conversion::Converter89     optional<int64_t> operator()(const Convertible& value, Error& error) const {
90         auto converted = convert<float>(value, error);
91         if (!converted) {
92             return {};
93         }
94         return *converted;
95     }
96 };
97 
98 enum class FunctionType {
99     Interval,
100     Exponential,
101     Categorical,
102     Identity,
103     Invalid
104 };
105 
interpolatable(type::Type type)106 static bool interpolatable(type::Type type) {
107     return type.match(
108         [&] (const type::NumberType&) {
109             return true;
110         },
111         [&] (const type::ColorType&) {
112             return true;
113         },
114         [&] (const type::Array& array) {
115             return array.N && array.itemType == type::Number;
116         },
117         [&] (const auto&) {
118             return false;
119         }
120     );
121 }
122 
convertLiteral(type::Type type,const Convertible & value,Error & error,bool convertTokens=false)123 static optional<std::unique_ptr<Expression>> convertLiteral(type::Type type, const Convertible& value, Error& error, bool convertTokens = false) {
124     return type.match(
125         [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> {
126             auto result = convert<float>(value, error);
127             if (!result) {
128                 return {};
129             }
130             return literal(double(*result));
131         },
132         [&] (const type::BooleanType&) -> optional<std::unique_ptr<Expression>> {
133             auto result = convert<bool>(value, error);
134             if (!result) {
135                 return {};
136             }
137             return literal(*result);
138         },
139         [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> {
140             auto result = convert<std::string>(value, error);
141             if (!result) {
142                 return {};
143             }
144             return convertTokens ? convertTokenStringToExpression(*result) : literal(*result);
145         },
146         [&] (const type::ColorType&) -> optional<std::unique_ptr<Expression>> {
147             auto result = convert<Color>(value, error);
148             if (!result) {
149                 return {};
150             }
151             return literal(*result);
152         },
153         [&] (const type::Array& array) -> optional<std::unique_ptr<Expression>> {
154             if (!isArray(value)) {
155                 error = { "value must be an array" };
156                 return {};
157             }
158             if (array.N && arrayLength(value) != *array.N) {
159                 error = { "value must be an array of length " + util::toString(*array.N) };
160                 return {};
161             }
162             return array.itemType.match(
163                 [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> {
164                     std::vector<expression::Value> result;
165                     result.reserve(arrayLength(value));
166                     for (std::size_t i = 0; i < arrayLength(value); ++i) {
167                         optional<float> number = toNumber(arrayMember(value, i));
168                         if (!number) {
169                             error = { "value must be an array of numbers" };
170                             return {};
171                         }
172                         result.push_back(double(*number));
173                     }
174                     return literal(result);
175                 },
176                 [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> {
177                     std::vector<expression::Value> result;
178                     result.reserve(arrayLength(value));
179                     for (std::size_t i = 0; i < arrayLength(value); ++i) {
180                         optional<std::string> string = toString(arrayMember(value, i));
181                         if (!string) {
182                             error = { "value must be an array of strings" };
183                             return {};
184                         }
185                         result.push_back(*string);
186                     }
187                     return literal(result);
188                 },
189                 [&] (const auto&) -> optional<std::unique_ptr<Expression>> {
190                     assert(false); // No properties use this type.
191                     return {};
192                 }
193             );
194         },
195         [&] (const type::NullType&) -> optional<std::unique_ptr<Expression>> {
196             assert(false); // No properties use this type.
197             return {};
198         },
199         [&] (const type::ObjectType&) -> optional<std::unique_ptr<Expression>> {
200             assert(false); // No properties use this type.
201             return {};
202         },
203         [&] (const type::ErrorType&) -> optional<std::unique_ptr<Expression>> {
204             assert(false); // No properties use this type.
205             return {};
206         },
207         [&] (const type::ValueType&) -> optional<std::unique_ptr<Expression>> {
208             assert(false); // No properties use this type.
209             return {};
210         },
211         [&] (const type::CollatorType&) -> optional<std::unique_ptr<Expression>> {
212             assert(false); // No properties use this type.
213             return {};
214         }
215     );
216 }
217 
convertStops(type::Type type,const Convertible & value,Error & error,bool convertTokens)218 static optional<std::map<double, std::unique_ptr<Expression>>> convertStops(type::Type type,
219                                                                             const Convertible& value,
220                                                                             Error& error,
221                                                                             bool convertTokens) {
222     auto stopsValue = objectMember(value, "stops");
223     if (!stopsValue) {
224         error = { "function value must specify stops" };
225         return {};
226     }
227 
228     if (!isArray(*stopsValue)) {
229         error = { "function stops must be an array" };
230         return {};
231     }
232 
233     if (arrayLength(*stopsValue) == 0) {
234         error = { "function must have at least one stop" };
235         return {};
236     }
237 
238     std::map<double, std::unique_ptr<Expression>> stops;
239     for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
240         const auto& stopValue = arrayMember(*stopsValue, i);
241 
242         if (!isArray(stopValue)) {
243             error = { "function stop must be an array" };
244             return {};
245         }
246 
247         if (arrayLength(stopValue) != 2) {
248             error = { "function stop must have two elements" };
249             return {};
250         }
251 
252         optional<float> t = convert<float>(arrayMember(stopValue, 0), error);
253         if (!t) {
254             return {};
255         }
256 
257         optional<std::unique_ptr<Expression>> e = convertLiteral(type, arrayMember(stopValue, 1), error, convertTokens);
258         if (!e) {
259             return {};
260         }
261 
262         stops.emplace(*t, std::move(*e));
263     }
264 
265     return { std::move(stops) };
266 }
267 
268 template <class T>
convertBranches(type::Type type,const Convertible & value,Error & error)269 optional<std::map<T, std::unique_ptr<Expression>>> convertBranches(type::Type type,
270                                                                    const Convertible& value,
271                                                                    Error& error) {
272     auto stopsValue = objectMember(value, "stops");
273     if (!stopsValue) {
274         error = { "function value must specify stops" };
275         return {};
276     }
277 
278     if (!isArray(*stopsValue)) {
279         error = { "function stops must be an array" };
280         return {};
281     }
282 
283     if (arrayLength(*stopsValue) == 0) {
284         error = { "function must have at least one stop" };
285         return {};
286     }
287 
288     std::map<T, std::unique_ptr<Expression>> stops;
289     for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
290         const auto& stopValue = arrayMember(*stopsValue, i);
291 
292         if (!isArray(stopValue)) {
293             error = { "function stop must be an array" };
294             return {};
295         }
296 
297         if (arrayLength(stopValue) != 2) {
298             error = { "function stop must have two elements" };
299             return {};
300         }
301 
302         optional<T> t = convert<T>(arrayMember(stopValue, 0), error);
303         if (!t) {
304             return {};
305         }
306 
307         optional<std::unique_ptr<Expression>> e = convertLiteral(type, arrayMember(stopValue, 1), error);
308         if (!e) {
309             return {};
310         }
311 
312         stops.emplace(*t, std::move(*e));
313     }
314 
315     return { std::move(stops) };
316 }
317 
convertBase(const Convertible & value,Error & error)318 static optional<double> convertBase(const Convertible& value, Error& error) {
319     auto baseValue = objectMember(value, "base");
320 
321     if (!baseValue) {
322         return 1.0;
323     }
324 
325     auto base = toNumber(*baseValue);
326     if (!base) {
327         error = { "function base must be a number" };
328         return {};
329     }
330 
331     return *base;
332 }
333 
step(type::Type type,std::unique_ptr<Expression> input,std::map<double,std::unique_ptr<Expression>> stops)334 static std::unique_ptr<Expression> step(type::Type type, std::unique_ptr<Expression> input, std::map<double, std::unique_ptr<Expression>> stops) {
335     return std::make_unique<Step>(type, std::move(input), std::move(stops));
336 }
337 
interpolate(type::Type type,Interpolator interpolator,std::unique_ptr<Expression> input,std::map<double,std::unique_ptr<Expression>> stops)338 static std::unique_ptr<Expression> interpolate(type::Type type, Interpolator interpolator, std::unique_ptr<Expression> input, std::map<double, std::unique_ptr<Expression>> stops) {
339     ParsingContext ctx;
340     auto result = createInterpolate(type, std::move(interpolator), std::move(input), std::move(stops), ctx);
341     if (!result) {
342         assert(false);
343         return {};
344     }
345     return std::move(*result);
346 }
347 
348 template <class T>
categorical(type::Type type,const std::string & property,std::map<T,std::unique_ptr<Expression>> branches)349 std::unique_ptr<Expression> categorical(type::Type type, const std::string& property, std::map<T, std::unique_ptr<Expression>> branches) {
350     std::unordered_map<T, std::shared_ptr<Expression>> convertedBranches;
351     for (auto& b : branches) {
352         convertedBranches[b.first] = std::move(b.second);
353     }
354     return std::make_unique<Match<T>>(type, get(literal(property)), std::move(convertedBranches), error("replaced with default"));
355 }
356 
357 template <>
categorical(type::Type type,const std::string & property,std::map<bool,std::unique_ptr<Expression>> branches)358 std::unique_ptr<Expression> categorical<bool>(type::Type type, const std::string& property, std::map<bool, std::unique_ptr<Expression>> branches) {
359     auto it = branches.find(true);
360     std::unique_ptr<Expression> trueCase = it == branches.end() ?
361         error("replaced with default") :
362         std::move(it->second);
363 
364     it = branches.find(false);
365     std::unique_ptr<Expression> falseCase = it == branches.end() ?
366         error("replaced with default") :
367         std::move(it->second);
368 
369     std::vector<typename Case::Branch> trueBranch;
370     trueBranch.emplace_back(get(literal(property)), std::move(trueCase));
371 
372     return std::make_unique<Case>(type, std::move(trueBranch), std::move(falseCase));
373 }
374 
convertIntervalFunction(type::Type type,const Convertible & value,Error & error,std::unique_ptr<Expression> input,bool convertTokens=false)375 static optional<std::unique_ptr<Expression>> convertIntervalFunction(type::Type type,
376                                                                      const Convertible& value,
377                                                                      Error& error,
378                                                                      std::unique_ptr<Expression> input,
379                                                                      bool convertTokens = false) {
380     auto stops = convertStops(type, value, error, convertTokens);
381     if (!stops) {
382         return {};
383     }
384     return step(type, std::move(input), std::move(*stops));
385 }
386 
convertExponentialFunction(type::Type type,const Convertible & value,Error & error,std::unique_ptr<Expression> input,bool convertTokens=false)387 static optional<std::unique_ptr<Expression>> convertExponentialFunction(type::Type type,
388                                                                         const Convertible& value,
389                                                                         Error& error,
390                                                                         std::unique_ptr<Expression> input,
391                                                                         bool convertTokens = false) {
392     auto stops = convertStops(type, value, error, convertTokens);
393     if (!stops) {
394         return {};
395     }
396     auto base = convertBase(value, error);
397     if (!base) {
398         return {};
399     }
400     return interpolate(type, exponential(*base), std::move(input), std::move(*stops));
401 }
402 
convertCategoricalFunction(type::Type type,const Convertible & value,Error & err,const std::string & property)403 static optional<std::unique_ptr<Expression>> convertCategoricalFunction(type::Type type,
404                                                                         const Convertible& value,
405                                                                         Error& err,
406                                                                         const std::string& property) {
407     auto stopsValue = objectMember(value, "stops");
408     if (!stopsValue) {
409         err = { "function value must specify stops" };
410         return {};
411     }
412 
413     if (!isArray(*stopsValue)) {
414         err = { "function stops must be an array" };
415         return {};
416     }
417 
418     if (arrayLength(*stopsValue) == 0) {
419         err = { "function must have at least one stop" };
420         return {};
421     }
422 
423     const auto& first = arrayMember(*stopsValue, 0);
424 
425     if (!isArray(first)) {
426         err = { "function stop must be an array" };
427         return {};
428     }
429 
430     if (arrayLength(first) != 2) {
431         err = { "function stop must have two elements" };
432         return {};
433     }
434 
435     if (toBool(arrayMember(first, 0))) {
436         auto branches = convertBranches<bool>(type, value, err);
437         if (!branches) {
438             return {};
439         }
440         return categorical(type, property, std::move(*branches));
441     }
442 
443     if (toNumber(arrayMember(first, 0))) {
444         auto branches = convertBranches<int64_t>(type, value, err);
445         if (!branches) {
446             return {};
447         }
448         return categorical(type, property, std::move(*branches));
449     }
450 
451     if (toString(arrayMember(first, 0))) {
452         auto branches = convertBranches<std::string>(type, value, err);
453         if (!branches) {
454             return {};
455         }
456         return categorical(type, property, std::move(*branches));
457     }
458 
459     err = { "stop domain value must be a number, string, or boolean" };
460     return {};
461 }
462 
463 template <class T, class Fn>
composite(type::Type type,const Convertible & value,Error & error,const Fn & makeInnerExpression)464 optional<std::unique_ptr<Expression>> composite(type::Type type,
465                                                 const Convertible& value,
466                                                 Error& error,
467                                                 const Fn& makeInnerExpression) {
468     auto base = convertBase(value, error);
469     if (!base) {
470         return {};
471     }
472 
473     auto stopsValue = objectMember(value, "stops");
474 
475     // Checked by caller.
476     assert(stopsValue);
477     assert(isArray(*stopsValue));
478 
479     std::map<float, std::map<T, std::unique_ptr<Expression>>> map;
480 
481     for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
482         const auto& stopValue = arrayMember(*stopsValue, i);
483 
484         if (!isArray(stopValue)) {
485             error = { "function stop must be an array" };
486             return {};
487         }
488 
489         if (arrayLength(stopValue) != 2) {
490             error = { "function stop must have two elements" };
491             return {};
492         }
493 
494         const auto& stopInput = arrayMember(stopValue, 0);
495 
496         if (!isObject(stopInput)) {
497             error = { "stop input must be an object" };
498             return {};
499         }
500 
501         auto zoomValue = objectMember(stopInput, "zoom");
502         if (!zoomValue) {
503             error = { "stop input must specify zoom" };
504             return {};
505         }
506 
507         auto sourceValue = objectMember(stopInput, "value");
508         if (!sourceValue) {
509             error = { "stop input must specify value" };
510             return {};
511         }
512 
513         optional<float> z = convert<float>(*zoomValue, error);
514         if (!z) {
515             return {};
516         }
517 
518         optional<T> d = convert<T>(*sourceValue, error);
519         if (!d) {
520             return {};
521         }
522 
523         optional<std::unique_ptr<Expression>> r = convertLiteral(type, arrayMember(stopValue, 1), error);
524         if (!r) {
525             return {};
526         }
527 
528         map[*z].emplace(*d, std::move(*r));
529     }
530 
531     std::map<double, std::unique_ptr<Expression>> stops;
532 
533     for (auto& e : map) {
534         stops.emplace(e.first, makeInnerExpression(type, *base, std::move(e.second)));
535     }
536 
537     if (interpolatable(type)) {
538         return interpolate(type, linear(), zoom(), std::move(stops));
539     } else {
540         return step(type, zoom(), std::move(stops));
541     }
542 }
543 
convertFunctionToExpression(type::Type type,const Convertible & value,Error & err,bool convertTokens)544 optional<std::unique_ptr<Expression>> convertFunctionToExpression(type::Type type,
545                                                                   const Convertible& value,
546                                                                   Error& err,
547 																  bool convertTokens) {
548     if (!isObject(value)) {
549         err = { "function must be an object" };
550         return {};
551     }
552 
553     FunctionType functionType = FunctionType::Invalid;
554 
555     auto typeValue = objectMember(value, "type");
556     if (!typeValue) {
557         functionType = interpolatable(type) ? FunctionType::Exponential : FunctionType::Interval;
558     } else {
559         optional<std::string> string = toString(*typeValue);
560         if (string) {
561             if (*string == "interval")
562                 functionType = FunctionType::Interval;
563             if (*string == "exponential" && interpolatable(type))
564                 functionType = FunctionType::Exponential;
565             if (*string == "categorical")
566                 functionType = FunctionType::Categorical;
567             if (*string == "identity")
568                 functionType = FunctionType::Identity;
569         }
570     }
571 
572     if (!objectMember(value, "property")) {
573         // Camera function.
574         switch (functionType) {
575         case FunctionType::Interval:
576             return convertIntervalFunction(type, value, err, zoom(), convertTokens);
577         case FunctionType::Exponential:
578             return convertExponentialFunction(type, value, err, zoom(), convertTokens);
579         default:
580             err = { "unsupported function type" };
581             return {};
582         }
583     }
584 
585     auto propertyValue = objectMember(value, "property");
586     if (!propertyValue) {
587         err = { "function must specify property" };
588         return {};
589     }
590 
591     auto property = toString(*propertyValue);
592     if (!property) {
593         err = { "function property must be a string" };
594         return {};
595     }
596 
597     if (functionType == FunctionType::Identity) {
598         return type.match(
599             [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> {
600                 return string(get(literal(*property)));
601             },
602             [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> {
603                 return number(get(literal(*property)));
604             },
605             [&] (const type::BooleanType&) -> optional<std::unique_ptr<Expression>> {
606                 return boolean(get(literal(*property)));
607             },
608             [&] (const type::ColorType&) -> optional<std::unique_ptr<Expression>> {
609                 return toColor(get(literal(*property)));
610             },
611             [&] (const type::Array& array) -> optional<std::unique_ptr<Expression>> {
612                 return std::unique_ptr<Expression>(
613                     std::make_unique<ArrayAssertion>(array, get(literal(*property))));
614             },
615             [&] (const auto&) -> optional<std::unique_ptr<Expression>>  {
616                 assert(false); // No properties use this type.
617                 return {};
618             }
619         );
620     }
621 
622     auto stopsValue = objectMember(value, "stops");
623     if (!stopsValue) {
624         err = { "function value must specify stops" };
625         return {};
626     }
627 
628     if (!isArray(*stopsValue)) {
629         err = { "function stops must be an array" };
630         return {};
631     }
632 
633     if (arrayLength(*stopsValue) == 0) {
634         err = { "function must have at least one stop" };
635         return {};
636     }
637 
638     const auto& first = arrayMember(*stopsValue, 0);
639 
640     if (!isArray(first)) {
641         err = { "function stop must be an array" };
642         return {};
643     }
644 
645     if (arrayLength(first) != 2) {
646         err = { "function stop must have two elements" };
647         return {};
648     }
649 
650     const auto& stop = arrayMember(first, 0);
651 
652     if (!isObject(stop)) {
653         // Source function.
654         switch (functionType) {
655         case FunctionType::Interval:
656             return convertIntervalFunction(type, value, err, number(get(literal(*property))));
657         case FunctionType::Exponential:
658             return convertExponentialFunction(type, value, err, number(get(literal(*property))));
659         case FunctionType::Categorical:
660             return convertCategoricalFunction(type, value, err, *property);
661         default:
662             err = { "unsupported function type" };
663             return {};
664         }
665     } else {
666         // Composite function.
667         auto sourceValue = objectMember(stop, "value");
668         if (!sourceValue) {
669             err = { "stop must specify value" };
670             return {};
671         }
672 
673         if (toBool(*sourceValue)) {
674             switch (functionType) {
675             case FunctionType::Categorical:
676                 return composite<bool>(type, value, err, [&] (type::Type type_, double, std::map<bool, std::unique_ptr<Expression>> stops) {
677                     return categorical<bool>(type_, *property, std::move(stops));
678                 });
679             default:
680                 err = { "unsupported function type" };
681                 return {};
682             }
683         }
684 
685         if (toNumber(*sourceValue)) {
686             switch (functionType) {
687             case FunctionType::Interval:
688                 return composite<double>(type, value, err, [&] (type::Type type_, double, std::map<double, std::unique_ptr<Expression>> stops) {
689                     return step(type_, number(get(literal(*property))), std::move(stops));
690                 });
691             case FunctionType::Exponential:
692                 return composite<double>(type, value, err, [&] (type::Type type_, double base, std::map<double, std::unique_ptr<Expression>> stops) {
693                     return interpolate(type_, exponential(base), number(get(literal(*property))), std::move(stops));
694                 });
695             case FunctionType::Categorical:
696                 return composite<int64_t>(type, value, err, [&] (type::Type type_, double, std::map<int64_t, std::unique_ptr<Expression>> stops) {
697                     return categorical<int64_t>(type_, *property, std::move(stops));
698                 });
699             default:
700                 err = { "unsupported function type" };
701                 return {};
702             }
703         }
704 
705         if (toString(*sourceValue)) {
706             switch (functionType) {
707             case FunctionType::Categorical:
708                 return composite<std::string>(type, value, err, [&] (type::Type type_, double, std::map<std::string, std::unique_ptr<Expression>> stops) {
709                     return categorical<std::string>(type_, *property, std::move(stops));
710                 });
711             default:
712                 err = { "unsupported function type" };
713                 return {};
714             }
715         }
716 
717         err = { "stop domain value must be a number, string, or boolean" };
718         return {};
719     }
720 }
721 
722 } // namespace conversion
723 } // namespace style
724 } // namespace mbgl
725