1 #pragma once 2 3 #include <mbgl/util/optional.hpp> 4 #include <mbgl/util/string.hpp> 5 #include <mbgl/style/expression/type.hpp> 6 #include <mbgl/style/conversion.hpp> 7 8 #include <iterator> 9 #include <map> 10 #include <string> 11 #include <vector> 12 #include <memory> 13 14 namespace mbgl { 15 namespace style { 16 namespace expression { 17 18 class Expression; 19 20 struct ParsingError { 21 std::string message; 22 std::string key; operator ==mbgl::style::expression::ParsingError23 bool operator==(const ParsingError& rhs) const { return message == rhs.message && key == rhs.key; } 24 }; 25 26 using ParseResult = optional<std::unique_ptr<Expression>>; 27 28 namespace detail { 29 30 class Scope { 31 public: Scope(const std::map<std::string,std::shared_ptr<Expression>> & bindings_,std::shared_ptr<Scope> parent_=nullptr)32 Scope(const std::map<std::string, std::shared_ptr<Expression>>& bindings_, std::shared_ptr<Scope> parent_ = nullptr) : 33 bindings(bindings_), 34 parent(std::move(parent_)) 35 {} 36 37 const std::map<std::string, std::shared_ptr<Expression>>& bindings; 38 std::shared_ptr<Scope> parent; 39 get(const std::string & name)40 optional<std::shared_ptr<Expression>> get(const std::string& name) { 41 auto it = bindings.find(name); 42 if (it != bindings.end()) { 43 return {it->second}; 44 } else if (parent) { 45 return parent->get(name); 46 } else { 47 return optional<std::shared_ptr<Expression>>(); 48 } 49 } 50 }; 51 52 } // namespace detail 53 54 class ParsingContext { 55 public: ParsingContext()56 ParsingContext() : errors(std::make_shared<std::vector<ParsingError>>()) {} ParsingContext(std::string key_)57 ParsingContext(std::string key_) : key(std::move(key_)), errors(std::make_shared<std::vector<ParsingError>>()) {} ParsingContext(type::Type expected_)58 explicit ParsingContext(type::Type expected_) 59 : expected(std::move(expected_)), 60 errors(std::make_shared<std::vector<ParsingError>>()) 61 {} 62 ParsingContext(ParsingContext&&) = default; 63 64 ParsingContext(const ParsingContext&) = delete; 65 ParsingContext& operator=(const ParsingContext&) = delete; 66 getKey() const67 std::string getKey() const { return key; } getExpected() const68 optional<type::Type> getExpected() const { return expected; } getErrors() const69 const std::vector<ParsingError>& getErrors() const { return *errors; } 70 const std::string getCombinedErrors() const; 71 72 enum TypeAnnotationOption { 73 includeTypeAnnotations, 74 omitTypeAnnotations 75 }; 76 77 /* 78 Parse the given style-spec JSON value as an expression. 79 */ 80 ParseResult parseExpression(const mbgl::style::conversion::Convertible& value, 81 TypeAnnotationOption typeAnnotationOption = includeTypeAnnotations); 82 83 /* 84 Parse the given style-spec JSON value as an expression intended to be used 85 in a layout or paint property. This entails checking additional constraints 86 that exist in that context but not, e.g., for filters. 87 */ 88 ParseResult parseLayerPropertyExpression(const mbgl::style::conversion::Convertible& value, 89 TypeAnnotationOption typeAnnotationOption = includeTypeAnnotations); 90 91 /* 92 Parse a child expression. For use by individual Expression::parse() methods. 93 */ 94 ParseResult parse(const mbgl::style::conversion::Convertible&, 95 std::size_t, 96 optional<type::Type> = {}, 97 TypeAnnotationOption typeAnnotationOption = includeTypeAnnotations); 98 99 /* 100 Parse a child expression. For use by individual Expression::parse() methods. 101 */ 102 ParseResult parse(const mbgl::style::conversion::Convertible&, 103 std::size_t index, 104 optional<type::Type>, 105 const std::map<std::string, std::shared_ptr<Expression>>&); 106 107 /* 108 Check whether `t` is a subtype of `expected`, collecting an error if not. 109 */ 110 optional<std::string> checkType(const type::Type& t); 111 getBinding(const std::string name)112 optional<std::shared_ptr<Expression>> getBinding(const std::string name) { 113 if (!scope) return optional<std::shared_ptr<Expression>>(); 114 return scope->get(name); 115 } 116 error(std::string message)117 void error(std::string message) { 118 errors->push_back({message, key}); 119 } 120 error(std::string message,std::size_t child)121 void error(std::string message, std::size_t child) { 122 errors->push_back({message, key + "[" + util::toString(child) + "]"}); 123 } 124 error(std::string message,std::size_t child,std::size_t grandchild)125 void error(std::string message, std::size_t child, std::size_t grandchild) { 126 errors->push_back({message, key + "[" + util::toString(child) + "][" + util::toString(grandchild) + "]"}); 127 } 128 appendErrors(ParsingContext && ctx)129 void appendErrors(ParsingContext&& ctx) { 130 errors->reserve(errors->size() + ctx.errors->size()); 131 std::move(ctx.errors->begin(), ctx.errors->end(), std::inserter(*errors, errors->end())); 132 ctx.errors->clear(); 133 } 134 clearErrors()135 void clearErrors() { 136 errors->clear(); 137 } 138 139 private: ParsingContext(std::string key_,std::shared_ptr<std::vector<ParsingError>> errors_,optional<type::Type> expected_,std::shared_ptr<detail::Scope> scope_)140 ParsingContext(std::string key_, 141 std::shared_ptr<std::vector<ParsingError>> errors_, 142 optional<type::Type> expected_, 143 std::shared_ptr<detail::Scope> scope_) 144 : key(std::move(key_)), 145 expected(std::move(expected_)), 146 scope(std::move(scope_)), 147 errors(std::move(errors_)) 148 {} 149 150 151 /* 152 Parse the given style-spec JSON value into an Expression object. 153 Specifically, this function is responsible for determining the expression 154 type (either Literal, or the one named in value[0]) and dispatching to the 155 appropriate ParseXxxx::parse(const V&, ParsingContext) method. 156 */ 157 ParseResult parse(const mbgl::style::conversion::Convertible& value, 158 TypeAnnotationOption typeAnnotationOption = includeTypeAnnotations); 159 160 std::string key; 161 optional<type::Type> expected; 162 std::shared_ptr<detail::Scope> scope; 163 std::shared_ptr<std::vector<ParsingError>> errors; 164 }; 165 166 using ParseFunction = ParseResult (*)(const conversion::Convertible&, ParsingContext&); 167 using ExpressionRegistry = std::unordered_map<std::string, ParseFunction>; 168 const ExpressionRegistry& getExpressionRegistry(); 169 170 } // namespace expression 171 } // namespace style 172 } // namespace mbgl 173