summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnand Thakker <github@anandthakker.net>2017-07-06 09:37:46 -0400
committerAnand Thakker <github@anandthakker.net>2017-07-06 17:01:50 -0400
commit9db5832d362fb7f1930d4b182a3fe37af492a9a0 (patch)
tree9965b1b077e7487b3be406e25efa1d222c494169
parente032c15fbe1647803599d3031b9da471aa77a616 (diff)
downloadqtlocation-mapboxgl-9db5832d362fb7f1930d4b182a3fe37af492a9a0.tar.gz
Add base Expression model
-rw-r--r--include/mbgl/style/conversion/expression.hpp56
-rw-r--r--include/mbgl/style/conversion/function.hpp1
-rw-r--r--include/mbgl/style/function/expression.hpp101
-rw-r--r--include/mbgl/style/function/type.hpp116
-rw-r--r--src/mbgl/style/function/expression.cpp49
-rw-r--r--src/mbgl/style/function/type.cpp26
6 files changed, 349 insertions, 0 deletions
diff --git a/include/mbgl/style/conversion/expression.hpp b/include/mbgl/style/conversion/expression.hpp
new file mode 100644
index 0000000000..d70e3e0b33
--- /dev/null
+++ b/include/mbgl/style/conversion/expression.hpp
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <memory>
+#include <sstream>
+#include <mbgl/style/function/expression.hpp>
+#include <mbgl/style/conversion.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+using namespace mbgl::style::expression;
+
+template<> struct Converter<std::unique_ptr<Expression>> {
+ template <class V>
+ std::string getJSType(const V& value) const {
+ if (isUndefined(value)) {
+ return "undefined";
+ }
+ if (isArray(value) || isObject(value)) {
+ return "object";
+ }
+ optional<mbgl::Value> v = toValue(value);
+ assert(v);
+ return v->match(
+ [&] (std::string) { return "string"; },
+ [&] (bool) { return "boolean"; },
+ [&] (auto) { return "number"; }
+ );
+ }
+
+ template <class V>
+ optional<std::unique_ptr<Expression>> operator()(const V& value, Error& error) const {
+ if (isArray(value)) {
+ if (arrayLength(value) == 0) {
+ error = { "Expected an array with at least one element. If you wanted a literal array, use [\"literal\", []]." };
+ return {};
+ }
+
+ const optional<std::string>& op = toString(arrayMember(value, 0));
+ if (!op) {
+ std::ostringstream ss;
+ ss << "Expression name must be a string, but found "
+ << getJSType(arrayMember(value, 0))
+ << " instead. If you wanted a literal array, use [\"literal\", [...]].";
+ error = { ss.str() };
+ return {};
+ }
+ }
+ return {std::make_unique<LiteralExpression>("", 1.0f)};
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
index bf5b27a9a6..d1d0bb709f 100644
--- a/include/mbgl/style/conversion/function.hpp
+++ b/include/mbgl/style/conversion/function.hpp
@@ -3,6 +3,7 @@
#include <mbgl/style/function/camera_function.hpp>
#include <mbgl/style/function/source_function.hpp>
#include <mbgl/style/function/composite_function.hpp>
+#include <mbgl/style/function/expression.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/util/ignore.hpp>
diff --git a/include/mbgl/style/function/expression.hpp b/include/mbgl/style/function/expression.hpp
new file mode 100644
index 0000000000..6a25f006df
--- /dev/null
+++ b/include/mbgl/style/function/expression.hpp
@@ -0,0 +1,101 @@
+#pragma once
+
+#include <array>
+#include <vector>
+#include <memory>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/color.hpp>
+#include <mbgl/style/function/type.hpp>
+#include <mbgl/util/feature.hpp>
+
+
+namespace mbgl {
+
+class GeometryTileFeature;
+
+
+namespace style {
+namespace expression {
+
+using OutputValue = variant<
+ float,
+ std::string,
+ mbgl::Color,
+ std::array<float, 2>,
+ std::array<float, 4>>;
+
+class Error {
+public:
+ Error() {}
+ Error(std::string message_) : message(message_) {}
+ std::string message;
+};
+
+class Expression {
+public:
+ Expression(std::string key_, type::Type type_) : key(key_), type(type_) {}
+ virtual ~Expression() {}
+
+ virtual optional<OutputValue> evaluate(float, const GeometryTileFeature&, Error& e) const = 0;
+
+ // Exposed for use with pure Feature objects (e.g. beyond the context of tiled map data).
+ optional<OutputValue> evaluate(float, const Feature&, Error&) const;
+
+ type::Type getType() {
+ return type;
+ }
+
+ bool isFeatureConstant() {
+ return true;
+ }
+
+ bool isZoomConstant() {
+ return true;
+ }
+
+private:
+ std::string key;
+ type::Type type;
+};
+
+class LiteralExpression : public Expression {
+public:
+ LiteralExpression(std::string key, OutputValue value_) :
+ Expression(key, value_.match(
+ [&] (const float&) -> type::Type { return type::Primitive::Number; },
+ [&] (const std::string&) { return type::Primitive::String; },
+ [&] (const mbgl::Color) { return type::Primitive::Color; },
+ [&] (const auto&) { return type::Primitive::Null; } // TODO (remaining output types)
+ )),
+ value(value_)
+ {}
+
+ optional<OutputValue> evaluate(float, const GeometryTileFeature&, Error&) const override {
+ return {value};
+ }
+
+private:
+ OutputValue value;
+};
+
+class LambdaExpression : public Expression {
+public:
+ LambdaExpression(std::string key,
+ type::Lambda type,
+ std::string name_,
+ std::vector<std::unique_ptr<Expression>> args_) :
+ Expression(key, type),
+ name(name_),
+ args(std::move(args_))
+ {}
+
+private:
+ std::string name;
+ std::vector<std::unique_ptr<Expression>> args;
+};
+
+
+
+} // namespace expression
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/type.hpp b/include/mbgl/style/function/type.hpp
new file mode 100644
index 0000000000..461c95eb0d
--- /dev/null
+++ b/include/mbgl/style/function/type.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <vector>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+namespace style {
+namespace expression {
+namespace type {
+
+class Primitive;
+class Variant;
+class Array;
+class NArgs;
+class Typename;
+class Lambda;
+
+using ValueType = variant<
+ Primitive,
+ Typename,
+ mapbox::util::recursive_wrapper<Variant>,
+ mapbox::util::recursive_wrapper<Array>,
+ mapbox::util::recursive_wrapper<NArgs>>;
+
+using Type = variant<
+ Primitive,
+ Typename,
+ Variant,
+ Array,
+ NArgs,
+ Lambda>;
+
+class Primitive {
+public:
+ std::string getName() const { return name; }
+
+ static Primitive Null;
+ static Primitive Number;
+ static Primitive String;
+ static Primitive Color;
+ static Primitive Object;
+
+ // It's weird for this to be on Primitive. Where should it go?
+ static Type Value;
+
+private:
+ std::string name;
+ Primitive(std::string name_) : name(name_) {}
+};
+
+class Typename {
+public:
+ Typename(std::string name_) : name(name_) {}
+ std::string getName() const { return name; }
+private:
+ std::string name;
+};
+
+class Array {
+public:
+ Array(ValueType itemType_) : itemType(itemType_) {}
+ Array(ValueType itemType_, int N_) : itemType(itemType_), N(N_) {}
+ std::string getName() const {
+ return "array";
+ }
+
+private:
+ ValueType itemType;
+ optional<int> N;
+};
+
+class Variant {
+public:
+ Variant(std::vector<ValueType> members_) : members(members_) {}
+ std::string getName() const {
+ return "variant";
+ }
+
+ std::vector<ValueType> getMembers() {
+ return members;
+ }
+
+private:
+ std::vector<ValueType> members;
+};
+
+class NArgs {
+public:
+ NArgs(std::vector<ValueType> types_) : types(types_) {}
+ std::string getName() const {
+ return "nargs";
+ }
+private:
+ std::vector<ValueType> types;
+};
+
+class Lambda {
+public:
+ Lambda(ValueType result_, std::vector<ValueType> params_) :
+ result(result_),
+ params(params_)
+ {}
+ std::string getName() const {
+ return "lambda";
+ }
+private:
+ ValueType result;
+ std::vector<ValueType> params;
+};
+
+
+} // namespace type
+} // namespace expression
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/function/expression.cpp b/src/mbgl/style/function/expression.cpp
new file mode 100644
index 0000000000..c620b0bb22
--- /dev/null
+++ b/src/mbgl/style/function/expression.cpp
@@ -0,0 +1,49 @@
+#include <mbgl/style/function/expression.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
+
+namespace mbgl {
+namespace style {
+namespace expression {
+
+class GeoJSONFeature : public GeometryTileFeature {
+public:
+ const Feature& feature;
+
+ GeoJSONFeature(const Feature& feature_)
+ : feature(feature_) {
+ }
+
+ FeatureType getType() const override {
+ return apply_visitor(ToFeatureType(), feature.geometry);
+ }
+
+ PropertyMap getProperties() const override {
+ return feature.properties;
+ }
+
+ optional<FeatureIdentifier> getID() const override {
+ return feature.id;
+ }
+
+ GeometryCollection getGeometries() const override {
+ return {};
+ }
+
+ optional<Value> getValue(const std::string& key) const override {
+ auto it = feature.properties.find(key);
+ if (it != feature.properties.end()) {
+ return optional<Value>(it->second);
+ }
+ return optional<Value>();
+ }
+};
+
+optional<OutputValue> Expression::evaluate(float z, const Feature& feature, Error& error) const {
+ std::unique_ptr<const GeometryTileFeature> f = std::make_unique<const GeoJSONFeature>(feature);
+ return this->evaluate(z, *f, error);
+}
+
+
+} // namespace expression
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/function/type.cpp b/src/mbgl/style/function/type.cpp
new file mode 100644
index 0000000000..fbfe6efbc3
--- /dev/null
+++ b/src/mbgl/style/function/type.cpp
@@ -0,0 +1,26 @@
+#include <mbgl/style/function/type.hpp>
+
+namespace mbgl {
+namespace style {
+namespace expression {
+namespace type {
+
+Primitive Primitive::Null = {"Null"};
+Primitive Primitive::String = {"String"};
+Primitive Primitive::Number = {"Number"};
+Primitive Primitive::Color = {"Color"};
+Primitive Primitive::Object = {"Object"};
+
+// Need to add Array(Types::Value) to the member list somehow...
+Type Primitive::Value = Variant({
+ Primitive::Null,
+ Primitive::String,
+ Primitive::Number,
+ Primitive::Color,
+ Primitive::Object
+});
+
+} // namespace type
+} // namespace expression
+} // namespace style
+} // namespace mbgl