diff options
author | Juha Alanen <juha.alanen@mapbox.com> | 2019-06-03 15:34:13 +0300 |
---|---|---|
committer | Juha Alanen <19551460+jmalanen@users.noreply.github.com> | 2019-06-27 15:51:22 +0300 |
commit | 0ca8ea6f169149cd414a65f40d0f7bdd40f3cca3 (patch) | |
tree | db6a58892dd6326b8ba22da7fc822d008bdda01a /src | |
parent | 81ea5d020efd0257083bf323644a575f5ea800c9 (diff) | |
download | qtlocation-mapboxgl-0ca8ea6f169149cd414a65f40d0f7bdd40f3cca3.tar.gz |
[core] Add number-format expression
Diffstat (limited to 'src')
-rw-r--r-- | src/core-files.json | 2 | ||||
-rw-r--r-- | src/mbgl/style/expression/number_format.cpp | 215 | ||||
-rw-r--r-- | src/mbgl/style/expression/parsing_context.cpp | 2 |
3 files changed, 219 insertions, 0 deletions
diff --git a/src/core-files.json b/src/core-files.json index 665c203a78..fcc0dba9f5 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -192,6 +192,7 @@ "src/mbgl/style/expression/let.cpp", "src/mbgl/style/expression/literal.cpp", "src/mbgl/style/expression/match.cpp", + "src/mbgl/style/expression/number_format.cpp", "src/mbgl/style/expression/parsing_context.cpp", "src/mbgl/style/expression/step.cpp", "src/mbgl/style/expression/util.cpp", @@ -416,6 +417,7 @@ "mbgl/style/expression/let.hpp": "include/mbgl/style/expression/let.hpp", "mbgl/style/expression/literal.hpp": "include/mbgl/style/expression/literal.hpp", "mbgl/style/expression/match.hpp": "include/mbgl/style/expression/match.hpp", + "mbgl/style/expression/number_format.hpp": "include/mbgl/style/expression/number_format.hpp", "mbgl/style/expression/parsing_context.hpp": "include/mbgl/style/expression/parsing_context.hpp", "mbgl/style/expression/step.hpp": "include/mbgl/style/expression/step.hpp", "mbgl/style/expression/type.hpp": "include/mbgl/style/expression/type.hpp", 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 <mbgl/style/expression/number_format.hpp> +#include <mbgl/style/conversion_impl.hpp> +#include <mbgl/util/platform.hpp> + +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<Expression> number_, + std::unique_ptr<Expression> locale_, + std::unique_ptr<Expression> currency_, + std::unique_ptr<Expression> minFractionDigits_, + std::unique_ptr<Expression> 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<double>(); + + 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<double>(); + } + + uint8_t evaluatedMaxFractionDigits = 3; + if (maxFractionDigits) { + auto maxDigitsResult = maxFractionDigits->evaluate(params); + if (!maxDigitsResult) { + return maxDigitsResult.error(); + } + evaluatedMaxFractionDigits = maxDigitsResult->get<double>(); + } + + std::string output; + output = platform::formatNumber(evaluatedNumber, + evaluatedLocale, + evaluatedCurrency, + evaluatedMinFractionDigits, + evaluatedMaxFractionDigits); + return output; +} + +void NumberFormat::eachChild(const std::function<void(const Expression&)>& 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<const NumberFormat*>(&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<optional<Value>> 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<type::NumberType>()) { + 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<Convertible> 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<Convertible> 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<Convertible> 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<Convertible> 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<NumberFormat>(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<mbgl::Value> serialized{{ getOperator() }}; + serialized.emplace_back(number->serialize()); + + std::unordered_map<std::string, mbgl::Value> 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 diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index 411aa660e8..a7c04f563d 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -13,6 +13,7 @@ #include <mbgl/style/expression/coercion.hpp> #include <mbgl/style/expression/compound_expression.hpp> #include <mbgl/style/expression/comparison.hpp> +#include <mbgl/style/expression/number_format.hpp> #include <mbgl/style/expression/format_expression.hpp> #include <mbgl/style/expression/interpolate.hpp> #include <mbgl/style/expression/length.hpp> @@ -120,6 +121,7 @@ MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = mapbox::eternal::hash_m {"literal", Literal::parse}, {"match", parseMatch}, {"number", Assertion::parse}, + {"number-format", NumberFormat::parse}, {"object", Assertion::parse}, {"step", Step::parse}, {"string", Assertion::parse}, |