From 50bdbea570ad079490f160a189010271bd33bcb1 Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Mon, 3 Jun 2019 15:34:13 +0300 Subject: [core] Add number-format expression --- src/mbgl/style/expression/number_format.cpp | 215 ++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 src/mbgl/style/expression/number_format.cpp (limited to 'src/mbgl/style/expression/number_format.cpp') diff --git a/src/mbgl/style/expression/number_format.cpp b/src/mbgl/style/expression/number_format.cpp new file mode 100644 index 0000000000..e31a9ce398 --- /dev/null +++ b/src/mbgl/style/expression/number_format.cpp @@ -0,0 +1,215 @@ +#include +#include +#include + +namespace mbgl { +namespace style { +namespace expression { + +const char localeKey[] = "locale"; +const char currencyKey[] = "currency"; +const char minFractionDigitsKey[] = "min-fraction-digits"; +const char maxFractionDigitsKey[] = "max-fraction-digits"; + +NumberFormat::NumberFormat(std::unique_ptr number_, + std::unique_ptr locale_, + std::unique_ptr currency_, + std::unique_ptr minFractionDigits_, + std::unique_ptr maxFractionDigits_) + : Expression(Kind::NumberFormat, type::String), + number(std::move(number_)), + locale(std::move(locale_)), + currency(std::move(currency_)), + minFractionDigits(std::move(minFractionDigits_)), + maxFractionDigits(std::move(maxFractionDigits_)) +{} + +NumberFormat::~NumberFormat() = default; + +EvaluationResult NumberFormat::evaluate(const EvaluationContext& params) const { + auto numberResult = number->evaluate(params); + if (!numberResult) { + return numberResult.error(); + } + double evaluatedNumber = numberResult->get(); + + std::string evaluatedLocale; + if (locale) { + auto localeResult = locale->evaluate(params); + if (!localeResult) { + return localeResult.error(); + } + evaluatedLocale = toString(*localeResult); + } + + std::string evaluatedCurrency; + if (currency) { + auto currencyResult = currency->evaluate(params); + if (!currencyResult) { + return currencyResult.error(); + } + evaluatedCurrency = toString(*currencyResult); + } + + uint8_t evaluatedMinFractionDigits = 0; + if (minFractionDigits) { + auto minDigitsResult = minFractionDigits->evaluate(params); + if (!minDigitsResult) { + return minDigitsResult.error(); + } + evaluatedMinFractionDigits = minDigitsResult->get(); + } + + uint8_t evaluatedMaxFractionDigits = 3; + if (maxFractionDigits) { + auto maxDigitsResult = maxFractionDigits->evaluate(params); + if (!maxDigitsResult) { + return maxDigitsResult.error(); + } + evaluatedMaxFractionDigits = maxDigitsResult->get(); + } + + std::string output; + output = platform::formatNumber(evaluatedNumber, + evaluatedLocale, + evaluatedCurrency, + evaluatedMinFractionDigits, + evaluatedMaxFractionDigits); + return output; +} + +void NumberFormat::eachChild(const std::function& visit) const { + visit(*number); + if (locale) visit(*locale); + if (currency) visit(*currency); + if (minFractionDigits) visit(*minFractionDigits); + if (maxFractionDigits) visit(*maxFractionDigits); +} + +bool NumberFormat::operator==(const Expression& e) const { + if (e.getKind() == Kind::NumberFormat) { + auto rhs = static_cast(&e); + if ((locale && (!rhs->locale || *locale != *rhs->locale)) || + (!locale && rhs->locale)) { + return false; + } + if ((currency && (!rhs->currency || *currency != *rhs->currency)) || + (!currency && rhs->currency)) { + return false; + } + if ((minFractionDigits && (!rhs->minFractionDigits || *minFractionDigits != *rhs->minFractionDigits)) || + (!minFractionDigits && rhs->minFractionDigits)) { + return false; + } + if ((maxFractionDigits && (!rhs->maxFractionDigits || *maxFractionDigits != *rhs->maxFractionDigits)) || + (!maxFractionDigits && rhs->maxFractionDigits)) { + return false; + } + return *number == *rhs->number; + } + return false; +} + +std::vector> NumberFormat::possibleOutputs() const { + return { nullopt }; +} + +using namespace mbgl::style::conversion; +ParseResult NumberFormat::parse(const Convertible& value, ParsingContext& ctx) { + std::size_t length = arrayLength(value); + + if (length != 3) { + ctx.error("Expected two arguments, but found " + util::toString(length) + " instead."); + return ParseResult(); + } + + ParseResult numberResult = ctx.parse(arrayMember(value, 1), 1, {type::Number}); + if (!numberResult) { + ctx.error("Failed to parse the number."); + return ParseResult(); + } + + type::Type type = (*numberResult)->getType(); + if (!type.is()) { + ctx.error("Expected argument of type number, but found " + toString(type) + " instead."); + return ParseResult(); + } + + auto options = arrayMember(value, 2); + if (!isObject(options)) { + ctx.error("Number-format options argument must be an object."); + return ParseResult(); + } + + const optional localeOption = objectMember(options, localeKey); + ParseResult localeResult; + if (localeOption) { + localeResult = ctx.parse(*localeOption, 1, {type::String}); + if (!localeResult) { + ctx.error("Number-format locale parsing failed."); + return ParseResult(); + } + } + + const optional currencyOption = objectMember(options, currencyKey); + ParseResult currencyResult; + if (currencyOption) { + currencyResult = ctx.parse(*currencyOption, 1, {type::String}); + if (!currencyResult) { + ctx.error("Number-format currency parsing failed."); + return ParseResult(); + } + } + + const optional minFractionDigitsOption = objectMember(options, minFractionDigitsKey); + ParseResult minFractionDigitsResult; + if (minFractionDigitsOption) { + minFractionDigitsResult = ctx.parse(*minFractionDigitsOption, 1, {type::Number}); + if (!minFractionDigitsResult) { + ctx.error("Number-format min-fraction-digits parsing failed."); + return ParseResult(); + } + } + + const optional maxFractionDigitsOption = objectMember(options, maxFractionDigitsKey); + ParseResult maxFractionDigitsResult; + if (maxFractionDigitsOption) { + maxFractionDigitsResult = ctx.parse(*maxFractionDigitsOption, 1, {type::Number}); + if (!maxFractionDigitsResult) { + ctx.error("Number-format max-fraction-digits parsing failed."); + return ParseResult(); + } + } + + return ParseResult(std::make_unique(std::move(*numberResult), + localeResult ? std::move(*localeResult) : nullptr, + currencyResult? std::move(*currencyResult) : nullptr, + minFractionDigitsResult ? std::move(*minFractionDigitsResult) : nullptr, + maxFractionDigitsResult ? std::move(*maxFractionDigitsResult) : nullptr)); +} + +mbgl::Value NumberFormat::serialize() const { + std::vector serialized{{ getOperator() }}; + serialized.emplace_back(number->serialize()); + + std::unordered_map options; + if (locale) { + options[localeKey] = locale->serialize(); + } + if (currency) { + options[currencyKey] = currency->serialize(); + } + if (minFractionDigits) { + options[minFractionDigitsKey] = minFractionDigits->serialize(); + } + if (maxFractionDigits) { + options[maxFractionDigitsKey] = maxFractionDigits->serialize(); + } + serialized.emplace_back(options); + + return serialized; +} + +} // namespace expression +} // namespace style +} // namespace mbgl -- cgit v1.2.1