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