summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnand Thakker <github@anandthakker.net>2017-07-07 17:06:28 -0400
committerAnand Thakker <github@anandthakker.net>2017-07-07 17:17:44 -0400
commita6d0cf83b1cba21e4b7b8420a69f6c2643bb7899 (patch)
tree23ffc5c07e80356a7190d8a77c87ad4c18b44236
parentd1b85505cde735cf40b37c994423380d6c0b02ac (diff)
downloadqtlocation-mapboxgl-a6d0cf83b1cba21e4b7b8420a69f6c2643bb7899.tar.gz
Add initial impl of +, -, *, /
-rw-r--r--include/mbgl/style/expression/expression.hpp150
-rw-r--r--include/mbgl/style/expression/parse.hpp20
-rw-r--r--include/mbgl/style/function/type.hpp1
-rw-r--r--platform/node/src/node_expression.cpp2
4 files changed, 165 insertions, 8 deletions
diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp
index d7053fc1b8..20fe5be8f8 100644
--- a/include/mbgl/style/expression/expression.hpp
+++ b/include/mbgl/style/expression/expression.hpp
@@ -44,10 +44,19 @@ public:
// Exposed for use with pure Feature objects (e.g. beyond the context of tiled map data).
optional<OutputValue> evaluate(float, const Feature&, EvaluationError&) const;
- type::Type getType() {
+ type::Type getType() const {
return type;
}
+ type::ValueType getResultType() const {
+ return type.match(
+ [&] (const type::Lambda& lambdaType) {
+ return lambdaType.getResult();
+ },
+ [&] (const auto& t) -> type::ValueType { return t; }
+ );
+ }
+
bool isFeatureConstant() {
return true;
}
@@ -110,20 +119,149 @@ private:
class LambdaExpression : public Expression {
public:
+ using Args = std::vector<std::unique_ptr<Expression>>;
+
LambdaExpression(std::string key,
- type::Lambda type,
std::string name_,
- std::vector<std::unique_ptr<Expression>> args_) :
+ Args args_,
+ type::Lambda type) :
Expression(key, type),
- name(name_),
- args(std::move(args_))
+ args(std::move(args_)),
+ name(name_)
{}
+ template <class V>
+ static variant<CompileError, Args> parseArgs(const V& value, const ParsingContext& ctx) {
+ assert(isArray(value));
+ auto length = arrayLength(value);
+ Args args;
+ for(size_t i = 1; i < length; i++) {
+ const auto& arg = arrayMember(value, i);
+ auto parsedArg = parseExpression(arg, ParsingContext(ctx, i, {}));
+ if (parsedArg.template is<std::unique_ptr<Expression>>()) {
+ args.push_back(std::move(parsedArg.template get<std::unique_ptr<Expression>>()));
+ } else {
+ return parsedArg.template get<CompileError>();
+ }
+ }
+ return std::move(args);
+ }
+
+protected:
+ Args args;
private:
std::string name;
- std::vector<std::unique_ptr<Expression>> args;
};
+template <typename T, typename Rfunc>
+optional<OutputValue> evaluateBinaryOperator(float z,
+ const GeometryTileFeature& f,
+ EvaluationError& e,
+ const LambdaExpression::Args& args,
+ optional<T> initial,
+ Rfunc reduce)
+{
+ optional<T> memo = initial;
+ for(const auto& arg : args) {
+ auto argValue = arg->evaluate(z, f, e);
+ if (!argValue) return {};
+ if (!memo) memo = {argValue->get<T>()};
+ else memo = reduce(*memo, argValue->get<T>());
+ }
+ return {*memo};
+}
+
+class PlusExpression : public LambdaExpression {
+public:
+ PlusExpression(std::string key, Args args) :
+ LambdaExpression(key, "+", std::move(args),
+ {type::Primitive::Number, {type::NArgs({type::Primitive::Number})}})
+ {}
+
+ optional<OutputValue> evaluate(float zoom, const GeometryTileFeature& feature, EvaluationError& error) const override {
+ return evaluateBinaryOperator<float>(zoom, feature, error, args,
+ {}, [](float memo, float next) { return memo + next; });
+ }
+
+ template <class V>
+ static ParseResult parse(const V& value, const ParsingContext& ctx) {
+ auto args = LambdaExpression::parseArgs(value, ctx);
+ if (args.template is<LambdaExpression::Args>()) {
+ return std::make_unique<PlusExpression>(ctx.key(), std::move(args.template get<Args>()));
+ } else {
+ return args.template get<CompileError>();
+ }
+ }
+};
+
+class TimesExpression : public LambdaExpression {
+public:
+ TimesExpression(std::string key, Args args) :
+ LambdaExpression(key, "*", std::move(args),
+ {type::Primitive::Number, {type::NArgs({type::Primitive::Number})}})
+ {}
+
+ optional<OutputValue> evaluate(float zoom, const GeometryTileFeature& feature, EvaluationError& error) const override {
+ return evaluateBinaryOperator<float>(zoom, feature, error, args,
+ {}, [](float memo, float next) { return memo * next; });
+ }
+
+ template <class V>
+ static ParseResult parse(const V& value, const ParsingContext& ctx) {
+ auto args = LambdaExpression::parseArgs(value, ctx);
+ if (args.template is<LambdaExpression::Args>()) {
+ return std::make_unique<TimesExpression>(ctx.key(), std::move(args.template get<Args>()));
+ } else {
+ return args.template get<CompileError>();
+ }
+ }
+};
+
+class MinusExpression : public LambdaExpression {
+public:
+ MinusExpression(std::string key, Args args) :
+ LambdaExpression(key, "-", std::move(args),
+ {type::Primitive::Number, {type::Primitive::Number, type::Primitive::Number}})
+ {}
+
+ optional<OutputValue> evaluate(float zoom, const GeometryTileFeature& feature, EvaluationError& error) const override {
+ return evaluateBinaryOperator<float>(zoom, feature, error, args,
+ {}, [](float memo, float next) { return memo - next; });
+ }
+
+ template <class V>
+ static ParseResult parse(const V& value, const ParsingContext& ctx) {
+ auto args = LambdaExpression::parseArgs(value, ctx);
+ if (args.template is<LambdaExpression::Args>()) {
+ return std::make_unique<MinusExpression>(ctx.key(), std::move(args.template get<Args>()));
+ } else {
+ return args.template get<CompileError>();
+ }
+ }
+};
+
+class DivideExpression : public LambdaExpression {
+public:
+ DivideExpression(std::string key, Args args) :
+ LambdaExpression(key, "/", std::move(args),
+ {type::Primitive::Number, {type::Primitive::Number, type::Primitive::Number}})
+ {}
+
+ optional<OutputValue> evaluate(float zoom, const GeometryTileFeature& feature, EvaluationError& error) const override {
+ return evaluateBinaryOperator<float>(zoom, feature, error, args,
+ {}, [](float memo, float next) { return memo / next; });
+ }
+
+ template <class V>
+ static ParseResult parse(const V& value, const ParsingContext& ctx) {
+ auto args = LambdaExpression::parseArgs(value, ctx);
+ if (args.template is<LambdaExpression::Args>()) {
+ return std::make_unique<DivideExpression>(ctx.key(), std::move(args.template get<Args>()));
+ } else {
+ return args.template get<CompileError>();
+ }
+ }
+};
diff --git a/include/mbgl/style/expression/parse.hpp b/include/mbgl/style/expression/parse.hpp
index 3d7fad70b3..4776706749 100644
--- a/include/mbgl/style/expression/parse.hpp
+++ b/include/mbgl/style/expression/parse.hpp
@@ -54,8 +54,26 @@ ParseResult parseExpression(const V& value, const ParsingContext& context)
};
return error;
}
- }
+
+ if (*op == "+") return PlusExpression::parse(value, context);
+ if (*op == "-") return MinusExpression::parse(value, context);
+ if (*op == "*") return TimesExpression::parse(value, context);
+ if (*op == "/") return DivideExpression::parse(value, context);
+
+ return CompileError {
+ std::string("Unknown expression \"") + *op + "\". If you wanted a literal array, use [\"literal\", [...]].",
+ context.key(0)
+ };
+ }
+
+ if (isObject(value)) {
+ return CompileError {
+ "Bare objects invalid. Use [\"literal\", {...}] instead.",
+ context.key()
+ };
+ }
+
return LiteralExpression::parse(value, context);
}
diff --git a/include/mbgl/style/function/type.hpp b/include/mbgl/style/function/type.hpp
index 461c95eb0d..94f710c005 100644
--- a/include/mbgl/style/function/type.hpp
+++ b/include/mbgl/style/function/type.hpp
@@ -104,6 +104,7 @@ public:
std::string getName() const {
return "lambda";
}
+ ValueType getResult() const { return result; }
private:
ValueType result;
std::vector<ValueType> params;
diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp
index dc9a50abd4..c6c2a04bfb 100644
--- a/platform/node/src/node_expression.cpp
+++ b/platform/node/src/node_expression.cpp
@@ -131,7 +131,7 @@ void NodeExpression::GetType(const Nan::FunctionCallbackInfo<v8::Value>& info) {
NodeExpression* nodeExpr = ObjectWrap::Unwrap<NodeExpression>(info.Holder());
const auto& expression = nodeExpr->expression;
- const auto& type = expression->getType();
+ const auto& type = expression->getResultType();
const auto& name = type.match([&] (const auto& t) { return t.getName(); });
info.GetReturnValue().Set(Nan::New(name.c_str()).ToLocalChecked());
}