#pragma once #include #include #include #include #include #include #include #include #include namespace mbgl { namespace style { namespace expression { class Expression; struct ParsingError { std::string message; std::string key; bool operator==(const ParsingError& rhs) const { return message == rhs.message && key == rhs.key; } }; using ParseResult = optional>; namespace detail { class Scope { public: Scope(const std::map>& bindings_, std::shared_ptr parent_ = nullptr) : bindings(bindings_), parent(std::move(parent_)) {} const std::map>& bindings; std::shared_ptr parent; optional> get(const std::string& name) { auto it = bindings.find(name); if (it != bindings.end()) { return {it->second}; } else if (parent) { return parent->get(name); } else { return optional>(); } } }; } // namespace detail class ParsingContext { public: ParsingContext() : errors(std::make_shared>()) {} ParsingContext(std::string key_) : key(std::move(key_)), errors(std::make_shared>()) {} explicit ParsingContext(type::Type expected_) : expected(std::move(expected_)), errors(std::make_shared>()) {} ParsingContext(ParsingContext&&) = default; ParsingContext(const ParsingContext&) = delete; ParsingContext& operator=(const ParsingContext&) = delete; std::string getKey() const { return key; } optional getExpected() const { return expected; } const std::vector& getErrors() const { return *errors; } const std::string getCombinedErrors() const; enum TypeAnnotationOption { includeTypeAnnotations, omitTypeAnnotations }; /* Parse the given style-spec JSON value as an expression. */ ParseResult parseExpression(const mbgl::style::conversion::Convertible& value, TypeAnnotationOption typeAnnotationOption = includeTypeAnnotations); /* Parse the given style-spec JSON value as an expression intended to be used in a layout or paint property. This entails checking additional constraints that exist in that context but not, e.g., for filters. */ ParseResult parseLayerPropertyExpression(const mbgl::style::conversion::Convertible& value, TypeAnnotationOption typeAnnotationOption = includeTypeAnnotations); /* Parse a child expression. For use by individual Expression::parse() methods. */ ParseResult parse(const mbgl::style::conversion::Convertible&, std::size_t, optional = {}, TypeAnnotationOption typeAnnotationOption = includeTypeAnnotations); /* Parse a child expression. For use by individual Expression::parse() methods. */ ParseResult parse(const mbgl::style::conversion::Convertible&, std::size_t index, optional, const std::map>&); /* Check whether `t` is a subtype of `expected`, collecting an error if not. */ optional checkType(const type::Type& t); optional> getBinding(const std::string name) { if (!scope) return optional>(); return scope->get(name); } void error(std::string message) { errors->push_back({message, key}); } void error(std::string message, std::size_t child) { errors->push_back({message, key + "[" + util::toString(child) + "]"}); } void error(std::string message, std::size_t child, std::size_t grandchild) { errors->push_back({message, key + "[" + util::toString(child) + "][" + util::toString(grandchild) + "]"}); } void appendErrors(ParsingContext&& ctx) { errors->reserve(errors->size() + ctx.errors->size()); std::move(ctx.errors->begin(), ctx.errors->end(), std::inserter(*errors, errors->end())); ctx.errors->clear(); } void clearErrors() { errors->clear(); } private: ParsingContext(std::string key_, std::shared_ptr> errors_, optional expected_, std::shared_ptr scope_) : key(std::move(key_)), expected(std::move(expected_)), scope(std::move(scope_)), errors(std::move(errors_)) {} /* Parse the given style-spec JSON value into an Expression object. Specifically, this function is responsible for determining the expression type (either Literal, or the one named in value[0]) and dispatching to the appropriate ParseXxxx::parse(const V&, ParsingContext) method. */ ParseResult parse(const mbgl::style::conversion::Convertible& value, TypeAnnotationOption typeAnnotationOption = includeTypeAnnotations); std::string key; optional expected; std::shared_ptr scope; std::shared_ptr> errors; }; using ParseFunction = ParseResult (*)(const conversion::Convertible&, ParsingContext&); using ExpressionRegistry = std::unordered_map; const ExpressionRegistry& getExpressionRegistry(); } // namespace expression } // namespace style } // namespace mbgl