[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`
This commit is contained in:
@@ -33,6 +33,9 @@ public:
|
||||
std::vector<optional<Value>> possibleOutputs() const override {
|
||||
return input->possibleOutputs();
|
||||
}
|
||||
|
||||
mbgl::Value serialize() const override;
|
||||
std::string getOperator() const override { return "array"; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Expression> input;
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
bool operator==(const Expression& e) const override;
|
||||
|
||||
std::vector<optional<Value>> possibleOutputs() const override;
|
||||
|
||||
std::string getOperator() const override;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Expression>> inputs;
|
||||
|
||||
@@ -31,6 +31,8 @@ public:
|
||||
std::vector<optional<Value>> possibleOutputs() const override {
|
||||
return { nullopt };
|
||||
}
|
||||
|
||||
std::string getOperator() const override { return "at"; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Expression> index;
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
bool operator==(const Expression& e) const override;
|
||||
std::vector<optional<Value>> possibleOutputs() const override;
|
||||
|
||||
std::string getOperator() const override { return "any"; }
|
||||
private:
|
||||
std::vector<std::unique_ptr<Expression>> inputs;
|
||||
};
|
||||
@@ -41,6 +42,7 @@ public:
|
||||
bool operator==(const Expression& e) const override;
|
||||
std::vector<optional<Value>> possibleOutputs() const override;
|
||||
|
||||
std::string getOperator() const override { return "all"; }
|
||||
private:
|
||||
std::vector<std::unique_ptr<Expression>> inputs;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
|
||||
std::vector<optional<Value>> possibleOutputs() const override;
|
||||
|
||||
std::string getOperator() const override { return "case"; }
|
||||
private:
|
||||
std::vector<Branch> branches;
|
||||
std::unique_ptr<Expression> otherwise;
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
return args.at(i).get();
|
||||
}
|
||||
|
||||
std::string getOperator() const override { return "coalesce"; }
|
||||
private:
|
||||
Args args;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
|
||||
std::vector<optional<Value>> possibleOutputs() const override;
|
||||
|
||||
std::string getOperator() const override;
|
||||
private:
|
||||
EvaluationResult (*coerceSingleValue) (const Value& v);
|
||||
std::vector<std::unique_ptr<Expression>> inputs;
|
||||
|
||||
@@ -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<std::vector<type::Type>, VarargsType> params_) :
|
||||
SignatureBase(type::Type result_, variant<std::vector<type::Type>, 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<Expression> makeExpression(const std::string& name, std::vector<std::unique_ptr<Expression>>) const = 0;
|
||||
virtual std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>>) const = 0;
|
||||
type::Type result;
|
||||
variant<std::vector<type::Type>, 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<std::unique_ptr<Expression>> args,
|
||||
ParsingContext& ctx);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
EvaluationResult evaluate(const EvaluationContext&) const override;
|
||||
std::vector<optional<Value>> possibleOutputs() const override;
|
||||
|
||||
std::string getOperator() const override { return negate ? "!=" : "=="; }
|
||||
private:
|
||||
std::unique_ptr<Expression> lhs;
|
||||
std::unique_ptr<Expression> rhs;
|
||||
|
||||
@@ -135,6 +135,17 @@ public:
|
||||
* complete set of outputs is statically undecidable.
|
||||
*/
|
||||
virtual std::vector<optional<Value>> possibleOutputs() const = 0;
|
||||
|
||||
virtual mbgl::Value serialize() const {
|
||||
std::vector<mbgl::Value> serialized;
|
||||
serialized.emplace_back(getOperator());
|
||||
eachChild([&](const Expression &child) {
|
||||
serialized.emplace_back(child.serialize());
|
||||
});
|
||||
return serialized;
|
||||
};
|
||||
|
||||
virtual std::string getOperator() const = 0;
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
|
||||
@@ -185,6 +185,9 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mbgl::Value serialize() const override;
|
||||
std::string getOperator() const override { return "interpolate"; }
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
|
||||
@@ -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<Expression> result;
|
||||
@@ -66,6 +68,8 @@ public:
|
||||
|
||||
std::vector<optional<Value>> possibleOutputs() const override;
|
||||
|
||||
mbgl::Value serialize() const override;
|
||||
std::string getOperator() const override { return "var"; }
|
||||
private:
|
||||
std::string name;
|
||||
std::shared_ptr<Expression> value;
|
||||
|
||||
@@ -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> value_) : Expression(type_), value(value_) {}
|
||||
Literal(Value value_)
|
||||
: Expression(typeOf(value_))
|
||||
, value(value_)
|
||||
{}
|
||||
|
||||
Literal(type::Array type_, std::vector<Value> value_)
|
||||
: Expression(type_)
|
||||
, value(value_)
|
||||
{}
|
||||
|
||||
EvaluationResult evaluate(const EvaluationContext&) const override {
|
||||
return value;
|
||||
}
|
||||
@@ -33,6 +41,8 @@ public:
|
||||
return {{ value }};
|
||||
}
|
||||
|
||||
mbgl::Value serialize() const override;
|
||||
std::string getOperator() const override { return "literal"; }
|
||||
private:
|
||||
Value value;
|
||||
};
|
||||
|
||||
@@ -32,7 +32,9 @@ public:
|
||||
bool operator==(const Expression& e) const override;
|
||||
|
||||
std::vector<optional<Value>> possibleOutputs() const override;
|
||||
|
||||
|
||||
mbgl::Value serialize() const override;
|
||||
std::string getOperator() const override { return "match"; }
|
||||
private:
|
||||
std::unique_ptr<Expression> input;
|
||||
Branches branches;
|
||||
|
||||
@@ -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<Expression> input;
|
||||
const std::map<double, std::unique_ptr<Expression>> stops;
|
||||
|
||||
@@ -110,6 +110,7 @@ struct ValueConverter<float> {
|
||||
template<>
|
||||
struct ValueConverter<mbgl::Value> {
|
||||
static Value toExpressionValue(const mbgl::Value& value);
|
||||
static mbgl::Value fromExpressionValue(const Value& value);
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string getOperator() const override { return "error"; }
|
||||
private:
|
||||
std::string message;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "node_conversion.hpp"
|
||||
#include "node_expression.hpp"
|
||||
#include "node_feature.hpp"
|
||||
|
||||
#include <mbgl/style/expression/parsing_context.hpp>
|
||||
#include <mbgl/style/expression/is_constant.hpp>
|
||||
@@ -24,6 +25,8 @@ void NodeExpression::Init(v8::Local<v8::Object> 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<v8::Object> type) {
|
||||
{"color", type::Color},
|
||||
{"value", type::Value}
|
||||
};
|
||||
|
||||
|
||||
v8::Local<v8::Value> 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<std::size_t> N;
|
||||
|
||||
|
||||
v8::Local<v8::String> 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<v8::Value>& info) {
|
||||
v8::Local<v8::Function> cons = Nan::New(constructor);
|
||||
|
||||
|
||||
if (info.Length() < 1 || info[0]->IsUndefined()) {
|
||||
return Nan::ThrowTypeError("Requires a JSON style expression argument.");
|
||||
}
|
||||
|
||||
|
||||
mbgl::optional<type::Type> expected;
|
||||
if (info.Length() > 1 && info[1]->IsObject()) {
|
||||
expected = parseType(info[1]->ToObject());
|
||||
@@ -84,7 +87,7 @@ void NodeExpression::Parse(const Nan::FunctionCallbackInfo<v8::Value>& info) {
|
||||
info.GetReturnValue().Set(wrapped);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
v8::Local<v8::Array> result = Nan::New<v8::Array>();
|
||||
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<v8::Value> operator()(const mbgl::Color& color) {
|
||||
return operator()(std::vector<Value> {
|
||||
static_cast<double>(color.r),
|
||||
@@ -227,4 +230,12 @@ void NodeExpression::IsZoomConstant(const Nan::FunctionCallbackInfo<v8::Value>&
|
||||
info.GetReturnValue().Set(Nan::New(isZoomConstant(*expression)));
|
||||
}
|
||||
|
||||
void NodeExpression::Serialize(const Nan::FunctionCallbackInfo<v8::Value>& info) {
|
||||
NodeExpression* nodeExpr = ObjectWrap::Unwrap<NodeExpression>(info.Holder());
|
||||
const std::unique_ptr<Expression>& expression = nodeExpr->expression;
|
||||
|
||||
const mbgl::Value serialized = expression->serialize();
|
||||
info.GetReturnValue().Set(toJS(serialized));
|
||||
}
|
||||
|
||||
} // namespace node_mbgl
|
||||
|
||||
@@ -32,6 +32,9 @@ private:
|
||||
static void GetType(const Nan::FunctionCallbackInfo<v8::Value>&);
|
||||
static void IsFeatureConstant(const Nan::FunctionCallbackInfo<v8::Value>&);
|
||||
static void IsZoomConstant(const Nan::FunctionCallbackInfo<v8::Value>&);
|
||||
|
||||
static void Serialize(const Nan::FunctionCallbackInfo<v8::Value>&);
|
||||
|
||||
static Nan::Persistent<v8::Function> constructor;
|
||||
|
||||
std::unique_ptr<Expression> expression;
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
|
||||
@@ -81,6 +81,25 @@ ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext& ctx)
|
||||
));
|
||||
}
|
||||
|
||||
mbgl::Value ArrayAssertion::serialize() const {
|
||||
std::vector<mbgl::Value> serialized;
|
||||
serialized.emplace_back(getOperator());
|
||||
|
||||
|
||||
const auto array = getType().get<type::Array>();
|
||||
if (array.itemType.is<type::StringType>()
|
||||
|| array.itemType.is<type::NumberType>()
|
||||
|| array.itemType.is<type::BooleanType>()) {
|
||||
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
|
||||
|
||||
@@ -35,6 +35,10 @@ ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) {
|
||||
return ParseResult(std::make_unique<Assertion>(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);
|
||||
|
||||
@@ -81,6 +81,13 @@ Coercion::Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> 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<std::string, type::Type> types {
|
||||
|
||||
@@ -42,20 +42,19 @@ template <class R, class... Params>
|
||||
struct Signature<R (Params...)> : SignatureBase {
|
||||
using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>;
|
||||
|
||||
Signature(R (*evaluate_)(Params...)) :
|
||||
Signature(R (*evaluate_)(Params...), std::string name_) :
|
||||
SignatureBase(
|
||||
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
|
||||
std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...}
|
||||
std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...},
|
||||
std::move(name_)
|
||||
),
|
||||
evaluate(evaluate_)
|
||||
{}
|
||||
evaluate(evaluate_) {}
|
||||
|
||||
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
|
||||
return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{});
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> makeExpression(const std::string& name,
|
||||
std::vector<std::unique_ptr<Expression>> args) const override {
|
||||
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
|
||||
typename Signature::Args argsArray;
|
||||
std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin());
|
||||
return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray));
|
||||
@@ -80,16 +79,16 @@ template <class R, typename T>
|
||||
struct Signature<R (const Varargs<T>&)> : SignatureBase {
|
||||
using Args = std::vector<std::unique_ptr<Expression>>;
|
||||
|
||||
Signature(R (*evaluate_)(const Varargs<T>&)) :
|
||||
Signature(R (*evaluate_)(const Varargs<T>&), std::string name_) :
|
||||
SignatureBase(
|
||||
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
|
||||
VarargsType { valueTypeToExpressionType<T>() }
|
||||
VarargsType { valueTypeToExpressionType<T>() },
|
||||
std::move(name_)
|
||||
),
|
||||
evaluate(evaluate_)
|
||||
{}
|
||||
|
||||
std::unique_ptr<Expression> makeExpression(const std::string& name,
|
||||
std::vector<std::unique_ptr<Expression>> args) const override {
|
||||
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
|
||||
return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args));
|
||||
};
|
||||
|
||||
@@ -115,16 +114,16 @@ template <class R, class... Params>
|
||||
struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase {
|
||||
using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>;
|
||||
|
||||
Signature(R (*evaluate_)(const EvaluationContext&, Params...)) :
|
||||
Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) :
|
||||
SignatureBase(
|
||||
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
|
||||
std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...}
|
||||
std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...},
|
||||
std::move(name_)
|
||||
),
|
||||
evaluate(evaluate_)
|
||||
{}
|
||||
|
||||
std::unique_ptr<Expression> makeExpression(const std::string& name,
|
||||
std::vector<std::unique_ptr<Expression>> args) const override {
|
||||
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
|
||||
typename Signature::Args argsArray;
|
||||
std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin());
|
||||
return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray));
|
||||
@@ -176,14 +175,14 @@ struct Signature<Lambda, std::enable_if_t<std::is_class<Lambda>::value>>
|
||||
using Definition = CompoundExpressionRegistry::Definition;
|
||||
|
||||
template <typename Fn>
|
||||
static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction) {
|
||||
return std::make_unique<detail::Signature<Fn>>(evaluateFunction);
|
||||
static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction, std::string name) {
|
||||
return std::make_unique<detail::Signature<Fn>>(evaluateFunction, std::move(name));
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() {
|
||||
std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions;
|
||||
auto define = [&](std::string name, auto fn) {
|
||||
definitions[name].push_back(makeSignature(fn));
|
||||
definitions[name].push_back(makeSignature(fn, name));
|
||||
};
|
||||
|
||||
define("e", []() -> Result<double> { 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<std::unique_ptr<Expression>> 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<std::unique_ptr<Expression>> 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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -216,6 +216,30 @@ std::vector<optional<Value>> InterpolateBase::possibleOutputs() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
mbgl::Value Interpolate<T>::serialize() const {
|
||||
std::vector<mbgl::Value> serialized;
|
||||
serialized.emplace_back(getOperator());
|
||||
|
||||
interpolator.match(
|
||||
[&](const ExponentialInterpolator& exponential) {
|
||||
serialized.emplace_back(std::vector<mbgl::Value>{{ 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<mbgl::Value>{{ 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
|
||||
|
||||
@@ -65,6 +65,17 @@ ParseResult Let::parse(const Convertible& value, ParsingContext& ctx) {
|
||||
return ParseResult(std::make_unique<Let>(std::move(bindings_), std::move(*result_)));
|
||||
}
|
||||
|
||||
mbgl::Value Let::serialize() const {
|
||||
std::vector<mbgl::Value> 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<Var>(name_, std::move(*bindingValue)));
|
||||
}
|
||||
|
||||
mbgl::Value Var::serialize() const {
|
||||
return std::vector<mbgl::Value>{{ getOperator(), name }};
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -102,6 +102,14 @@ ParseResult Literal::parse(const Convertible& value, ParsingContext& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
mbgl::Value Literal::serialize() const {
|
||||
if (getType().is<type::Array>() || getType().is<type::ObjectType>()) {
|
||||
return std::vector<mbgl::Value>{{ getOperator(), *fromExpressionValue<mbgl::Value>(value) }};
|
||||
} else {
|
||||
return *fromExpressionValue<mbgl::Value>(value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -40,6 +40,42 @@ std::vector<optional<Value>> Match<T>::possibleOutputs() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
mbgl::Value Match<T>::serialize() const {
|
||||
std::vector<mbgl::Value> 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<T, std::shared_ptr<Expression>> sortedBranches(branches.begin(), branches.end());
|
||||
|
||||
// Group branches by unique match expression to support condensed serializations
|
||||
// of the form [case1, case2, ...] -> matchExpression
|
||||
std::map<Expression*, size_t> outputLookup;
|
||||
std::vector<std::pair<Expression*, std::vector<mbgl::Value>>> 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<mbgl::Value>{{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<std::string>::evaluate(const EvaluationContext& params) const {
|
||||
const EvaluationResult inputValue = input->evaluate(params);
|
||||
|
||||
@@ -168,6 +168,18 @@ ParseResult Step::parse(const mbgl::style::conversion::Convertible& value, Parsi
|
||||
return ParseResult(std::make_unique<Step>(*outputType, std::move(*input), std::move(stops)));
|
||||
}
|
||||
|
||||
mbgl::Value Step::serialize() const {
|
||||
std::vector<mbgl::Value> serialized;
|
||||
serialized.emplace_back(getOperator());
|
||||
serialized.emplace_back(input->serialize());
|
||||
for (auto& entry : stops) {
|
||||
if (entry.first > -std::numeric_limits<double>::infinity()) {
|
||||
serialized.emplace_back(entry.first);
|
||||
}
|
||||
serialized.emplace_back(entry.second->serialize());
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
|
||||
@@ -103,6 +103,37 @@ Value ValueConverter<mbgl::Value>::toExpressionValue(const mbgl::Value& value) {
|
||||
return mbgl::Value::visit(value, FromMBGLValue());
|
||||
}
|
||||
|
||||
mbgl::Value ValueConverter<mbgl::Value>::fromExpressionValue(const Value& value) {
|
||||
return value.match(
|
||||
[&](const Color& color)->mbgl::Value {
|
||||
return std::vector<mbgl::Value>{
|
||||
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<Value>& values)->mbgl::Value {
|
||||
std::vector<mbgl::Value> converted;
|
||||
converted.reserve(values.size());
|
||||
for (const Value& v : values) {
|
||||
converted.emplace_back(fromExpressionValue(v));
|
||||
}
|
||||
return converted;
|
||||
},
|
||||
[&](const std::unordered_map<std::string, Value>& values)->mbgl::Value {
|
||||
std::unordered_map<std::string, mbgl::Value> 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<float>::toExpressionValue(const float value) {
|
||||
return static_cast<double>(value);
|
||||
}
|
||||
@@ -237,7 +268,7 @@ template <> type::Type valueTypeToExpressionType<type::ErrorType>() { return typ
|
||||
|
||||
|
||||
template Value toExpressionValue(const mbgl::Value&);
|
||||
|
||||
template optional<mbgl::Value> fromExpressionValue<mbgl::Value>(const Value&);
|
||||
|
||||
// for to_rgba expression
|
||||
template type::Type valueTypeToExpressionType<std::array<double, 4>>();
|
||||
|
||||
Reference in New Issue
Block a user