diff options
author | Anand Thakker <github@anandthakker.net> | 2017-07-07 08:23:37 -0400 |
---|---|---|
committer | Anand Thakker <github@anandthakker.net> | 2017-07-07 17:06:45 -0400 |
commit | d1b85505cde735cf40b37c994423380d6c0b02ac (patch) | |
tree | cfcb437202830f09cb51e81284e68433764eab38 /include | |
parent | 21de44b47f0cc4f42e56b120d014ef4609b162fd (diff) | |
download | qtlocation-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.hpp | 43 | ||||
-rw-r--r-- | include/mbgl/style/conversion/function.hpp | 1 | ||||
-rw-r--r-- | include/mbgl/style/expression/expression.hpp | 132 | ||||
-rw-r--r-- | include/mbgl/style/expression/parse.hpp | 65 | ||||
-rw-r--r-- | include/mbgl/style/expression/parsing_context.hpp | 40 | ||||
-rw-r--r-- | include/mbgl/style/function/expression.hpp | 101 |
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 |