summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorAnand Thakker <github@anandthakker.net>2017-07-07 08:23:37 -0400
committerAnand Thakker <github@anandthakker.net>2017-07-07 17:06:45 -0400
commitd1b85505cde735cf40b37c994423380d6c0b02ac (patch)
treecfcb437202830f09cb51e81284e68433764eab38 /include
parent21de44b47f0cc4f42e56b120d014ef4609b162fd (diff)
downloadqtlocation-mapboxgl-d1b85505cde735cf40b37c994423380d6c0b02ac.tar.gz
Factor out expression parsing
- Also make error reporting consistent with GL JS
Diffstat (limited to 'include')
-rw-r--r--include/mbgl/style/conversion/expression.hpp43
-rw-r--r--include/mbgl/style/conversion/function.hpp1
-rw-r--r--include/mbgl/style/expression/expression.hpp132
-rw-r--r--include/mbgl/style/expression/parse.hpp65
-rw-r--r--include/mbgl/style/expression/parsing_context.hpp40
-rw-r--r--include/mbgl/style/function/expression.hpp101
6 files changed, 244 insertions, 138 deletions
diff --git a/include/mbgl/style/conversion/expression.hpp b/include/mbgl/style/conversion/expression.hpp
index d70e3e0b33..bce7c91396 100644
--- a/include/mbgl/style/conversion/expression.hpp
+++ b/include/mbgl/style/conversion/expression.hpp
@@ -1,8 +1,7 @@
#pragma once
#include <memory>
-#include <sstream>
-#include <mbgl/style/function/expression.hpp>
+#include <mbgl/style/expression/parse.hpp>
#include <mbgl/style/conversion.hpp>
namespace mbgl {
@@ -13,42 +12,14 @@ 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 {};
- }
+ auto parsed = parseExpression(value, ParsingContext());
+ if (parsed.template is<std::unique_ptr<Expression>>()) {
+ return std::move(parsed.template get<std::unique_ptr<Expression>>());
}
- return {std::make_unique<LiteralExpression>("", 1.0f)};
- }
+ error = { parsed.template get<CompileError>().message };
+ return {};
+ };
};
} // namespace conversion
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
index d1d0bb709f..bf5b27a9a6 100644
--- a/include/mbgl/style/conversion/function.hpp
+++ b/include/mbgl/style/conversion/function.hpp
@@ -3,7 +3,6 @@
#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/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp
new file mode 100644
index 0000000000..d7053fc1b8
--- /dev/null
+++ b/include/mbgl/style/expression/expression.hpp
@@ -0,0 +1,132 @@
+#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>
+#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion.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>>;
+
+struct EvaluationError {
+ std::string message;
+};
+
+struct CompileError {
+ std::string message;
+ std::string key;
+};
+
+class Expression {
+public:
+ Expression(std::string key_, type::Type type_) : key(key_), type(type_) {}
+ virtual ~Expression() {}
+
+ virtual optional<OutputValue> evaluate(float, const GeometryTileFeature&, EvaluationError& 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&, EvaluationError&) const;
+
+ type::Type getType() {
+ return type;
+ }
+
+ bool isFeatureConstant() {
+ return true;
+ }
+
+ bool isZoomConstant() {
+ return true;
+ }
+
+private:
+ std::string key;
+ type::Type type;
+};
+
+using ParseResult = variant<CompileError, std::unique_ptr<Expression>>;
+template <class V>
+ParseResult parseExpression(const V& value, const ParsingContext& context);
+
+using namespace mbgl::style::conversion;
+
+class LiteralExpression : public Expression {
+public:
+ LiteralExpression(std::string key, float value_) : Expression(key, type::Primitive::Number), value(value_) {}
+ LiteralExpression(std::string key, const std::string& value_) : Expression(key, type::Primitive::String), value(value_) {}
+ LiteralExpression(std::string key, const mbgl::Color& value_) : Expression(key, type::Primitive::Color), value(value_) {}
+ LiteralExpression(std::string key) : Expression(key, type::Primitive::Null) {}
+
+ optional<OutputValue> evaluate(float, const GeometryTileFeature&, EvaluationError&) const override {
+ return value;
+ }
+
+ template <class V>
+ static ParseResult parse(const V& value, const ParsingContext& ctx) {
+ if (isUndefined(value))
+ return std::make_unique<LiteralExpression>(ctx.key());
+
+ if (isObject(value)) {
+ return CompileError {ctx.key(), "Unimplemented: object literals"};
+ }
+
+ if (isArray(value)) {
+ return CompileError {ctx.key(), "Unimplemented: array literals"};
+ }
+
+ optional<mbgl::Value> v = toValue(value);
+ assert(v);
+ return v->match(
+ [&] (std::string s) { return std::make_unique<LiteralExpression>(ctx.key(), s); },
+ [&] (bool b) { return std::make_unique<LiteralExpression>(ctx.key(), b); },
+ [&] (auto f) {
+ auto number = numericValue<float>(f);
+ assert(number);
+ return std::make_unique<LiteralExpression>(ctx.key(), *number);
+ }
+ );
+ }
+
+private:
+ optional<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/expression/parse.hpp b/include/mbgl/style/expression/parse.hpp
new file mode 100644
index 0000000000..3d7fad70b3
--- /dev/null
+++ b/include/mbgl/style/expression/parse.hpp
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <memory>
+#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/expression/expression.hpp>
+#include <mbgl/style/conversion.hpp>
+
+namespace mbgl {
+namespace style {
+namespace expression {
+
+using namespace mbgl::style;
+
+template <class V>
+std::string getJSType(const V& value) {
+ using namespace mbgl::style::conversion;
+ 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"; }
+ );
+}
+
+using ParseResult = variant<CompileError, std::unique_ptr<Expression>>;
+
+template <class V>
+ParseResult parseExpression(const V& value, const ParsingContext& context)
+{
+ using namespace mbgl::style::conversion;
+
+ if (isArray(value)) {
+ if (arrayLength(value) == 0) {
+ CompileError error = {
+ "Expected an array with at least one element. If you wanted a literal array, use [\"literal\", []].",
+ context.key()
+ };
+ return error;
+ }
+
+ const optional<std::string>& op = toString(arrayMember(value, 0));
+ if (!op) {
+ CompileError error = {
+ "Expression name must be a string, but found " + getJSType(arrayMember(value, 0)) +
+ " instead. If you wanted a literal array, use [\"literal\", [...]].",
+ context.key(0)
+ };
+ return error;
+ }
+ }
+
+ return LiteralExpression::parse(value, context);
+}
+
+
+} // namespace expression
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/expression/parsing_context.hpp b/include/mbgl/style/expression/parsing_context.hpp
new file mode 100644
index 0000000000..7898da790d
--- /dev/null
+++ b/include/mbgl/style/expression/parsing_context.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <mbgl/util/optional.hpp>
+
+namespace mbgl {
+namespace style {
+namespace expression {
+
+class ParsingContext {
+public:
+ ParsingContext() {}
+ ParsingContext(ParsingContext previous,
+ optional<size_t> index,
+ optional<std::string> name) :
+ path(previous.path),
+ ancestors(previous.ancestors)
+ {
+ if (index) path.emplace_back(*index);
+ if (name) ancestors.emplace_back(*name);
+ }
+
+ std::string key() const {
+ std::string result;
+ for(auto const& index : path) { result += "[" + std::to_string(index) + "]"; }
+ return result;
+ }
+
+ std::string key(size_t lastIndex) const {
+ return key() + "[" + std::to_string(lastIndex) + "]";
+ }
+
+ std::vector<size_t> path;
+ std::vector<std::string> ancestors;
+};
+
+} // namespace expression
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/expression.hpp b/include/mbgl/style/function/expression.hpp
deleted file mode 100644
index 6a25f006df..0000000000
--- a/include/mbgl/style/function/expression.hpp
+++ /dev/null
@@ -1,101 +0,0 @@
-#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