From 75feda12f17dececadf72986c45af78fe18afc56 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Thu, 8 Feb 2018 15:23:29 -0800 Subject: [core] Implement Expression::serialize() Issue #10714 - Each expression stores its operator as a string, and default serialization is [operator, serialize(child1), ...] - Custom implementations of `serialize` for Expression types that don't follow the pattern - expression::Value -> mbgl::Value converter - node_expression bindings to expose `serialize` --- include/mbgl/style/expression/array_assertion.hpp | 3 ++ include/mbgl/style/expression/assertion.hpp | 2 ++ include/mbgl/style/expression/at.hpp | 2 ++ include/mbgl/style/expression/boolean_operator.hpp | 2 ++ include/mbgl/style/expression/case.hpp | 1 + include/mbgl/style/expression/coalesce.hpp | 1 + include/mbgl/style/expression/coercion.hpp | 1 + .../mbgl/style/expression/compound_expression.hpp | 15 +++++--- include/mbgl/style/expression/equals.hpp | 1 + include/mbgl/style/expression/expression.hpp | 11 ++++++ include/mbgl/style/expression/interpolate.hpp | 3 ++ include/mbgl/style/expression/let.hpp | 4 +++ include/mbgl/style/expression/literal.hpp | 14 ++++++-- include/mbgl/style/expression/match.hpp | 4 ++- include/mbgl/style/expression/step.hpp | 2 ++ include/mbgl/style/expression/value.hpp | 1 + include/mbgl/style/function/convert.hpp | 1 + platform/node/src/node_expression.cpp | 27 +++++++++----- platform/node/src/node_expression.hpp | 3 ++ platform/node/test/expression.test.js | 4 ++- src/mbgl/style/expression/array_assertion.cpp | 19 ++++++++++ src/mbgl/style/expression/assertion.cpp | 4 +++ src/mbgl/style/expression/coercion.cpp | 7 ++++ src/mbgl/style/expression/compound_expression.cpp | 42 +++++++++++----------- src/mbgl/style/expression/interpolate.cpp | 24 +++++++++++++ src/mbgl/style/expression/let.cpp | 15 ++++++++ src/mbgl/style/expression/literal.cpp | 8 +++++ src/mbgl/style/expression/match.cpp | 36 +++++++++++++++++++ src/mbgl/style/expression/step.cpp | 12 +++++++ src/mbgl/style/expression/value.cpp | 33 ++++++++++++++++- 30 files changed, 262 insertions(+), 40 deletions(-) diff --git a/include/mbgl/style/expression/array_assertion.hpp b/include/mbgl/style/expression/array_assertion.hpp index 7f36f8aac2..af153611ff 100644 --- a/include/mbgl/style/expression/array_assertion.hpp +++ b/include/mbgl/style/expression/array_assertion.hpp @@ -33,6 +33,9 @@ public: std::vector> possibleOutputs() const override { return input->possibleOutputs(); } + + mbgl::Value serialize() const override; + std::string getOperator() const override { return "array"; } private: std::unique_ptr input; diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp index 43ea73f2ba..d1e919b10f 100644 --- a/include/mbgl/style/expression/assertion.hpp +++ b/include/mbgl/style/expression/assertion.hpp @@ -26,6 +26,8 @@ public: bool operator==(const Expression& e) const override; std::vector> possibleOutputs() const override; + + std::string getOperator() const override; private: std::vector> inputs; diff --git a/include/mbgl/style/expression/at.hpp b/include/mbgl/style/expression/at.hpp index 27fccc761f..1e6f1c7dd2 100644 --- a/include/mbgl/style/expression/at.hpp +++ b/include/mbgl/style/expression/at.hpp @@ -31,6 +31,8 @@ public: std::vector> possibleOutputs() const override { return { nullopt }; } + + std::string getOperator() const override { return "at"; } private: std::unique_ptr index; diff --git a/include/mbgl/style/expression/boolean_operator.hpp b/include/mbgl/style/expression/boolean_operator.hpp index 115a096665..6d0f85756a 100644 --- a/include/mbgl/style/expression/boolean_operator.hpp +++ b/include/mbgl/style/expression/boolean_operator.hpp @@ -23,6 +23,7 @@ public: bool operator==(const Expression& e) const override; std::vector> possibleOutputs() const override; + std::string getOperator() const override { return "any"; } private: std::vector> inputs; }; @@ -41,6 +42,7 @@ public: bool operator==(const Expression& e) const override; std::vector> possibleOutputs() const override; + std::string getOperator() const override { return "all"; } private: std::vector> inputs; }; diff --git a/include/mbgl/style/expression/case.hpp b/include/mbgl/style/expression/case.hpp index e61a55fc6d..667ca53712 100644 --- a/include/mbgl/style/expression/case.hpp +++ b/include/mbgl/style/expression/case.hpp @@ -28,6 +28,7 @@ public: std::vector> possibleOutputs() const override; + std::string getOperator() const override { return "case"; } private: std::vector branches; std::unique_ptr otherwise; diff --git a/include/mbgl/style/expression/coalesce.hpp b/include/mbgl/style/expression/coalesce.hpp index 52d9498cbd..a858bef695 100644 --- a/include/mbgl/style/expression/coalesce.hpp +++ b/include/mbgl/style/expression/coalesce.hpp @@ -38,6 +38,7 @@ public: return args.at(i).get(); } + std::string getOperator() const override { return "coalesce"; } private: Args args; }; diff --git a/include/mbgl/style/expression/coercion.hpp b/include/mbgl/style/expression/coercion.hpp index 40d2490186..d83bd6dfa7 100644 --- a/include/mbgl/style/expression/coercion.hpp +++ b/include/mbgl/style/expression/coercion.hpp @@ -28,6 +28,7 @@ public: std::vector> possibleOutputs() const override; + std::string getOperator() const override; private: EvaluationResult (*coerceSingleValue) (const Value& v); std::vector> inputs; diff --git a/include/mbgl/style/expression/compound_expression.hpp b/include/mbgl/style/expression/compound_expression.hpp index 8b74027578..6baaae862f 100644 --- a/include/mbgl/style/expression/compound_expression.hpp +++ b/include/mbgl/style/expression/compound_expression.hpp @@ -40,14 +40,16 @@ namespace detail { // each CompoundExpression definition's type::Type data from the type of its // "evaluate" function. struct SignatureBase { - SignatureBase(type::Type result_, variant, VarargsType> params_) : + SignatureBase(type::Type result_, variant, VarargsType> params_, std::string name_) : result(std::move(result_)), - params(std::move(params_)) + params(std::move(params_)), + name(std::move(name_)) {} virtual ~SignatureBase() = default; - virtual std::unique_ptr makeExpression(const std::string& name, std::vector>) const = 0; + virtual std::unique_ptr makeExpression(std::vector>) const = 0; type::Type result; variant, VarargsType> params; + std::string name; }; } // namespace detail @@ -111,6 +113,10 @@ public: } return false; } + + std::string getOperator() const override { + return signature.name; + } private: Signature signature; @@ -128,8 +134,7 @@ struct CompoundExpressionRegistry { ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); -ParseResult createCompoundExpression(const std::string& name, - const CompoundExpressionRegistry::Definition& definition, +ParseResult createCompoundExpression(const CompoundExpressionRegistry::Definition& definition, std::vector> args, ParsingContext& ctx); diff --git a/include/mbgl/style/expression/equals.hpp b/include/mbgl/style/expression/equals.hpp index 80550bd59d..54df890a68 100644 --- a/include/mbgl/style/expression/equals.hpp +++ b/include/mbgl/style/expression/equals.hpp @@ -21,6 +21,7 @@ public: EvaluationResult evaluate(const EvaluationContext&) const override; std::vector> possibleOutputs() const override; + std::string getOperator() const override { return negate ? "!=" : "=="; } private: std::unique_ptr lhs; std::unique_ptr rhs; diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index cf9fa0cb21..c41ac0b5f1 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -135,6 +135,17 @@ public: * complete set of outputs is statically undecidable. */ virtual std::vector> possibleOutputs() const = 0; + + virtual mbgl::Value serialize() const { + std::vector serialized; + serialized.emplace_back(getOperator()); + eachChild([&](const Expression &child) { + serialized.emplace_back(child.serialize()); + }); + return serialized; + }; + + virtual std::string getOperator() const = 0; protected: template diff --git a/include/mbgl/style/expression/interpolate.hpp b/include/mbgl/style/expression/interpolate.hpp index dbed74b4cd..cc744ac7b7 100644 --- a/include/mbgl/style/expression/interpolate.hpp +++ b/include/mbgl/style/expression/interpolate.hpp @@ -185,6 +185,9 @@ public: } return false; } + + mbgl::Value serialize() const override; + std::string getOperator() const override { return "interpolate"; } }; } // namespace expression diff --git a/include/mbgl/style/expression/let.hpp b/include/mbgl/style/expression/let.hpp index 6829ded9b8..75d2adda62 100644 --- a/include/mbgl/style/expression/let.hpp +++ b/include/mbgl/style/expression/let.hpp @@ -39,6 +39,8 @@ public: return result.get(); } + mbgl::Value serialize() const override; + std::string getOperator() const override { return "let"; } private: Bindings bindings; std::unique_ptr result; @@ -66,6 +68,8 @@ public: std::vector> possibleOutputs() const override; + mbgl::Value serialize() const override; + std::string getOperator() const override { return "var"; } private: std::string name; std::shared_ptr value; diff --git a/include/mbgl/style/expression/literal.hpp b/include/mbgl/style/expression/literal.hpp index a5c5fa109d..a00c468efc 100644 --- a/include/mbgl/style/expression/literal.hpp +++ b/include/mbgl/style/expression/literal.hpp @@ -12,8 +12,16 @@ namespace expression { class Literal : public Expression { public: - Literal(Value value_) : Expression(typeOf(value_)), value(value_) {} - Literal(type::Array type_, std::vector value_) : Expression(type_), value(value_) {} + Literal(Value value_) + : Expression(typeOf(value_)) + , value(value_) + {} + + Literal(type::Array type_, std::vector value_) + : Expression(type_) + , value(value_) + {} + EvaluationResult evaluate(const EvaluationContext&) const override { return value; } @@ -37,6 +45,8 @@ public: return value; } + mbgl::Value serialize() const override; + std::string getOperator() const override { return "literal"; } private: Value value; }; diff --git a/include/mbgl/style/expression/match.hpp b/include/mbgl/style/expression/match.hpp index 682d784b0f..3775e38067 100644 --- a/include/mbgl/style/expression/match.hpp +++ b/include/mbgl/style/expression/match.hpp @@ -32,7 +32,9 @@ public: bool operator==(const Expression& e) const override; std::vector> possibleOutputs() const override; - + + mbgl::Value serialize() const override; + std::string getOperator() const override { return "match"; } private: std::unique_ptr input; Branches branches; diff --git a/include/mbgl/style/expression/step.hpp b/include/mbgl/style/expression/step.hpp index 6bf42e20f1..2f9524a53c 100644 --- a/include/mbgl/style/expression/step.hpp +++ b/include/mbgl/style/expression/step.hpp @@ -38,6 +38,8 @@ public: static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); + mbgl::Value serialize() const override; + std::string getOperator() const override { return "step"; } private: const std::unique_ptr input; const std::map> stops; diff --git a/include/mbgl/style/expression/value.hpp b/include/mbgl/style/expression/value.hpp index be5be64752..7839ff2ca7 100644 --- a/include/mbgl/style/expression/value.hpp +++ b/include/mbgl/style/expression/value.hpp @@ -110,6 +110,7 @@ struct ValueConverter { template<> struct ValueConverter { static Value toExpressionValue(const mbgl::Value& value); + static mbgl::Value fromExpressionValue(const Value& value); }; template diff --git a/include/mbgl/style/function/convert.hpp b/include/mbgl/style/function/convert.hpp index 8e544d3ad5..401a81d52e 100644 --- a/include/mbgl/style/function/convert.hpp +++ b/include/mbgl/style/function/convert.hpp @@ -49,6 +49,7 @@ public: return {}; } + std::string getOperator() const override { return "error"; } private: std::string message; }; diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp index 8958d5c6c7..84515060a3 100644 --- a/platform/node/src/node_expression.cpp +++ b/platform/node/src/node_expression.cpp @@ -1,5 +1,6 @@ #include "node_conversion.hpp" #include "node_expression.hpp" +#include "node_feature.hpp" #include #include @@ -24,6 +25,8 @@ void NodeExpression::Init(v8::Local target) { Nan::SetPrototypeMethod(tpl, "isFeatureConstant", IsFeatureConstant); Nan::SetPrototypeMethod(tpl, "isZoomConstant", IsZoomConstant); + Nan::SetPrototypeMethod(tpl, "serialize", Serialize); + Nan::SetMethod(tpl, "parse", Parse); constructor.Reset(tpl->GetFunction()); // what is this doing? @@ -39,31 +42,31 @@ type::Type parseType(v8::Local type) { {"color", type::Color}, {"value", type::Value} }; - + v8::Local v8kind = Nan::Get(type, Nan::New("kind").ToLocalChecked()).ToLocalChecked(); std::string kind(*v8::String::Utf8Value(v8kind)); - + if (kind == "array") { type::Type itemType = parseType(Nan::Get(type, Nan::New("itemType").ToLocalChecked()).ToLocalChecked()->ToObject()); mbgl::optional N; - + v8::Local Nkey = Nan::New("N").ToLocalChecked(); if (Nan::Has(type, Nkey).FromMaybe(false)) { N = Nan::Get(type, Nkey).ToLocalChecked()->ToInt32()->Value(); } return type::Array(itemType, N); } - + return types[kind]; } void NodeExpression::Parse(const Nan::FunctionCallbackInfo& info) { v8::Local cons = Nan::New(constructor); - + if (info.Length() < 1 || info[0]->IsUndefined()) { return Nan::ThrowTypeError("Requires a JSON style expression argument."); } - + mbgl::optional expected; if (info.Length() > 1 && info[1]->IsObject()) { expected = parseType(info[1]->ToObject()); @@ -84,7 +87,7 @@ void NodeExpression::Parse(const Nan::FunctionCallbackInfo& info) { info.GetReturnValue().Set(wrapped); return; } - + v8::Local result = Nan::New(); for (std::size_t i = 0; i < ctx.getErrors().size(); i++) { const auto& error = ctx.getErrors()[i]; @@ -140,7 +143,7 @@ struct ToValue { } return scope.Escape(result); } - + v8::Local operator()(const mbgl::Color& color) { return operator()(std::vector { static_cast(color.r), @@ -227,4 +230,12 @@ void NodeExpression::IsZoomConstant(const Nan::FunctionCallbackInfo& info.GetReturnValue().Set(Nan::New(isZoomConstant(*expression))); } +void NodeExpression::Serialize(const Nan::FunctionCallbackInfo& info) { + NodeExpression* nodeExpr = ObjectWrap::Unwrap(info.Holder()); + const std::unique_ptr& expression = nodeExpr->expression; + + const mbgl::Value serialized = expression->serialize(); + info.GetReturnValue().Set(toJS(serialized)); +} + } // namespace node_mbgl diff --git a/platform/node/src/node_expression.hpp b/platform/node/src/node_expression.hpp index 7af5b7ab51..05af217bde 100644 --- a/platform/node/src/node_expression.hpp +++ b/platform/node/src/node_expression.hpp @@ -32,6 +32,9 @@ private: static void GetType(const Nan::FunctionCallbackInfo&); static void IsFeatureConstant(const Nan::FunctionCallbackInfo&); static void IsZoomConstant(const Nan::FunctionCallbackInfo&); + + static void Serialize(const Nan::FunctionCallbackInfo&); + static Nan::Persistent constructor; std::unique_ptr expression; diff --git a/platform/node/test/expression.test.js b/platform/node/test/expression.test.js index aac039ce18..d7a44abbaa 100644 --- a/platform/node/test/expression.test.js +++ b/platform/node/test/expression.test.js @@ -45,6 +45,9 @@ suite.run('native', {ignores: ignores, tests: tests}, (fixture) => { compiled.isZoomConstant = expression.isZoomConstant(); compiled.type = expression.getType(); + console.log("input: " + JSON.stringify(fixture.expression)); + console.log("output: " + JSON.stringify(expression.serialize())); + const evaluate = fixture.inputs || []; const evaluateResults = []; for (const input of evaluate) { @@ -68,4 +71,3 @@ suite.run('native', {ignores: ignores, tests: tests}, (fixture) => { return result; }); - diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp index 29f6a47b10..4049301b0b 100644 --- a/src/mbgl/style/expression/array_assertion.cpp +++ b/src/mbgl/style/expression/array_assertion.cpp @@ -81,6 +81,25 @@ ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext& ctx) )); } +mbgl::Value ArrayAssertion::serialize() const { + std::vector serialized; + serialized.emplace_back(getOperator()); + + + const auto array = getType().get(); + if (array.itemType.is() + || array.itemType.is() + || array.itemType.is()) { + serialized.emplace_back(type::toString(array.itemType)); + if (array.N) { + serialized.emplace_back(uint64_t(*array.N)); + } + } + + serialized.emplace_back(input->serialize()); + return serialized; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 0187921af9..d6f3f1b584 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -35,6 +35,10 @@ ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique(it->second, std::move(parsed))); } +std::string Assertion::getOperator() const { + return type::toString(getType()); +} + EvaluationResult Assertion::evaluate(const EvaluationContext& params) const { for (std::size_t i = 0; i < inputs.size(); i++) { EvaluationResult value = inputs[i]->evaluate(params); diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index 56ab33fcfd..d9cd3ffdc9 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -81,6 +81,13 @@ Coercion::Coercion(type::Type type_, std::vector> in } } +std::string Coercion::getOperator() const { + return getType().match( + [](const type::NumberType&) { return "to-number"; }, + [](const type::ColorType&) { return "to-color"; }, + [](const auto&) { assert(false); return ""; }); +} + using namespace mbgl::style::conversion; ParseResult Coercion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map types { diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 42cb655024..86d968c521 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -42,20 +42,19 @@ template struct Signature : SignatureBase { using Args = std::array, sizeof...(Params)>; - Signature(R (*evaluate_)(Params...)) : + Signature(R (*evaluate_)(Params...), std::string name_) : SignatureBase( valueTypeToExpressionType>(), - std::vector {valueTypeToExpressionType>()...} + std::vector {valueTypeToExpressionType>()...}, + std::move(name_) ), - evaluate(evaluate_) - {} + evaluate(evaluate_) {} EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const { return applyImpl(evaluationParameters, args, std::index_sequence_for{}); } - std::unique_ptr makeExpression(const std::string& name, - std::vector> args) const override { + std::unique_ptr makeExpression(std::vector> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique>(name, *this, std::move(argsArray)); @@ -80,16 +79,16 @@ template struct Signature&)> : SignatureBase { using Args = std::vector>; - Signature(R (*evaluate_)(const Varargs&)) : + Signature(R (*evaluate_)(const Varargs&), std::string name_) : SignatureBase( valueTypeToExpressionType>(), - VarargsType { valueTypeToExpressionType() } + VarargsType { valueTypeToExpressionType() }, + std::move(name_) ), evaluate(evaluate_) {} - std::unique_ptr makeExpression(const std::string& name, - std::vector> args) const override { + std::unique_ptr makeExpression(std::vector> args) const override { return std::make_unique>(name, *this, std::move(args)); }; @@ -115,16 +114,16 @@ template struct Signature : SignatureBase { using Args = std::array, sizeof...(Params)>; - Signature(R (*evaluate_)(const EvaluationContext&, Params...)) : + Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) : SignatureBase( valueTypeToExpressionType>(), - std::vector {valueTypeToExpressionType>()...} + std::vector {valueTypeToExpressionType>()...}, + std::move(name_) ), evaluate(evaluate_) {} - std::unique_ptr makeExpression(const std::string& name, - std::vector> args) const override { + std::unique_ptr makeExpression(std::vector> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique>(name, *this, std::move(argsArray)); @@ -176,14 +175,14 @@ struct Signature::value>> using Definition = CompoundExpressionRegistry::Definition; template -static std::unique_ptr makeSignature(Fn evaluateFunction) { - return std::make_unique>(evaluateFunction); +static std::unique_ptr makeSignature(Fn evaluateFunction, std::string name) { + return std::make_unique>(evaluateFunction, std::move(name)); } std::unordered_map initializeDefinitions() { std::unordered_map definitions; auto define = [&](std::string name, auto fn) { - definitions[name].push_back(makeSignature(fn)); + definitions[name].push_back(makeSignature(fn, name)); }; define("e", []() -> Result { return 2.718281828459045; }); @@ -461,7 +460,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v } args.push_back(std::move(*parsed)); } - return createCompoundExpression(name, definition, std::move(args), ctx); + return createCompoundExpression(definition, std::move(args), ctx); } @@ -469,12 +468,11 @@ ParseResult createCompoundExpression(const std::string& name, std::vector> args, ParsingContext& ctx) { - return createCompoundExpression(name, CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); + return createCompoundExpression(CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); } -ParseResult createCompoundExpression(const std::string& name, - const Definition& definition, +ParseResult createCompoundExpression(const Definition& definition, std::vector> args, ParsingContext& ctx) { @@ -512,7 +510,7 @@ ParseResult createCompoundExpression(const std::string& name, } if (signatureContext.getErrors().size() == 0) { - return ParseResult(signature->makeExpression(name, std::move(args))); + return ParseResult(signature->makeExpression(std::move(args))); } } diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index 4cb22a3e4f..30b2cba81b 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -216,6 +216,30 @@ std::vector> InterpolateBase::possibleOutputs() const { return result; } +template +mbgl::Value Interpolate::serialize() const { + std::vector serialized; + serialized.emplace_back(getOperator()); + + interpolator.match( + [&](const ExponentialInterpolator& exponential) { + serialized.emplace_back(std::vector{{ std::string("exponential"), exponential.base }}); + }, + [&](const CubicBezierInterpolator& cubicBezier) { + static const std::string cubicBezierTag("cubic-bezier"); + auto p1 = cubicBezier.ub.getP1(); + auto p2 = cubicBezier.ub.getP2(); + serialized.emplace_back(std::vector{{ cubicBezierTag, p1.first, p1.second, p2.first, p2.second }}); + } + ); + serialized.emplace_back(input->serialize()); + for (auto& entry : stops) { + serialized.emplace_back(entry.first); + serialized.emplace_back(entry.second->serialize()); + }; + return serialized; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/let.cpp b/src/mbgl/style/expression/let.cpp index fe48138ac3..242a995b0b 100644 --- a/src/mbgl/style/expression/let.cpp +++ b/src/mbgl/style/expression/let.cpp @@ -65,6 +65,17 @@ ParseResult Let::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique(std::move(bindings_), std::move(*result_))); } +mbgl::Value Let::serialize() const { + std::vector serialized; + serialized.emplace_back(getOperator()); + for (auto entry : bindings) { + serialized.emplace_back(entry.first); + serialized.emplace_back(entry.second->serialize()); + } + serialized.emplace_back(result->serialize()); + return serialized; +} + EvaluationResult Var::evaluate(const EvaluationContext& params) const { return value->evaluate(params); } @@ -95,6 +106,10 @@ ParseResult Var::parse(const Convertible& value_, ParsingContext& ctx) { return ParseResult(std::make_unique(name_, std::move(*bindingValue))); } +mbgl::Value Var::serialize() const { + return std::vector{{ getOperator(), name }}; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 7e79fcbfe6..8a63980dba 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -102,6 +102,14 @@ ParseResult Literal::parse(const Convertible& value, ParsingContext& ctx) { } } +mbgl::Value Literal::serialize() const { + if (getType().is() || getType().is()) { + return std::vector{{ getOperator(), *fromExpressionValue(value) }}; + } else { + return *fromExpressionValue(value); + } +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp index 0b2790b688..3d41f0bdd3 100644 --- a/src/mbgl/style/expression/match.cpp +++ b/src/mbgl/style/expression/match.cpp @@ -40,6 +40,42 @@ std::vector> Match::possibleOutputs() const { return result; } +template +mbgl::Value Match::serialize() const { + std::vector serialized; + serialized.emplace_back(getOperator()); + serialized.emplace_back(input->serialize()); + + // Sort so serialization has an arbitrary defined order, even though branch order doesn't affect evaluation + std::map> sortedBranches(branches.begin(), branches.end()); + + // Group branches by unique match expression to support condensed serializations + // of the form [case1, case2, ...] -> matchExpression + std::map outputLookup; + std::vector>> groupedByOutput; + for (auto& entry : sortedBranches) { + auto outputIndex = outputLookup.find(entry.second.get()); + if (outputIndex == outputLookup.end()) { + // First time seeing this output, add it to the end of the grouped list + outputLookup[entry.second.get()] = groupedByOutput.size(); + groupedByOutput.emplace_back(entry.second.get(), std::vector{{entry.first}}); + } else { + // We've seen this expression before, add the label to that output's group + groupedByOutput[outputIndex->second].second.emplace_back(entry.first); + } + }; + + for (auto& entry : groupedByOutput) { + entry.second.size() == 1 + ? serialized.emplace_back(entry.second[0]) // Only a single label matches this output expression + : serialized.emplace_back(entry.second); // Array of literal labels pointing to this output expression + serialized.emplace_back(entry.first->serialize()); // The output expression itself + } + + serialized.emplace_back(otherwise->serialize()); + return serialized; +} + template<> EvaluationResult Match::evaluate(const EvaluationContext& params) const { const EvaluationResult inputValue = input->evaluate(params); diff --git a/src/mbgl/style/expression/step.cpp b/src/mbgl/style/expression/step.cpp index 34537d48ae..ddaf9417cb 100644 --- a/src/mbgl/style/expression/step.cpp +++ b/src/mbgl/style/expression/step.cpp @@ -168,6 +168,18 @@ ParseResult Step::parse(const mbgl::style::conversion::Convertible& value, Parsi return ParseResult(std::make_unique(*outputType, std::move(*input), std::move(stops))); } +mbgl::Value Step::serialize() const { + std::vector serialized; + serialized.emplace_back(getOperator()); + serialized.emplace_back(input->serialize()); + for (auto& entry : stops) { + if (entry.first > -std::numeric_limits::infinity()) { + serialized.emplace_back(entry.first); + } + serialized.emplace_back(entry.second->serialize()); + } + return serialized; +} } // namespace expression } // namespace style diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index faa44e78aa..72779d4956 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -103,6 +103,37 @@ Value ValueConverter::toExpressionValue(const mbgl::Value& value) { return mbgl::Value::visit(value, FromMBGLValue()); } +mbgl::Value ValueConverter::fromExpressionValue(const Value& value) { + return value.match( + [&](const Color& color)->mbgl::Value { + return std::vector{ + std::string("rgba"), + double(255 * color.r / color.a), + double(255 * color.g / color.a), + double(255 * color.b / color.a), + double(color.a) + }; + }, + [&](const std::vector& values)->mbgl::Value { + std::vector converted; + converted.reserve(values.size()); + for (const Value& v : values) { + converted.emplace_back(fromExpressionValue(v)); + } + return converted; + }, + [&](const std::unordered_map& values)->mbgl::Value { + std::unordered_map converted; + converted.reserve(values.size()); + for(const auto& entry : values) { + converted.emplace(entry.first, fromExpressionValue(entry.second)); + } + return converted; + }, + [&](const auto& a)->mbgl::Value { return a; } + ); +} + Value ValueConverter::toExpressionValue(const float value) { return static_cast(value); } @@ -237,7 +268,7 @@ template <> type::Type valueTypeToExpressionType() { return typ template Value toExpressionValue(const mbgl::Value&); - +template optional fromExpressionValue(const Value&); // for to_rgba expression template type::Type valueTypeToExpressionType>(); -- cgit v1.2.1