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; |
23 | 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: |
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 | |
40 | optional<std::shared_ptr<Expression>> get(const std::string& name) { |
41 | auto it = bindings.find(x: 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: |
56 | ParsingContext() : errors(std::make_shared<std::vector<ParsingError>>()) {} |
57 | ParsingContext(std::string key_) : key(std::move(key_)), errors(std::make_shared<std::vector<ParsingError>>()) {} |
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 | |
67 | std::string getKey() const { return key; } |
68 | optional<type::Type> getExpected() const { return expected; } |
69 | 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 | |
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 | |
117 | void error(std::string message) { |
118 | errors->push_back(x: {.message: message, .key: key}); |
119 | } |
120 | |
121 | void error(std::string message, std::size_t child) { |
122 | errors->push_back(x: {.message: message, .key: key + "[" + util::toString(t: child) + "]" }); |
123 | } |
124 | |
125 | void error(std::string message, std::size_t child, std::size_t grandchild) { |
126 | errors->push_back(x: {.message: message, .key: key + "[" + util::toString(t: child) + "][" + util::toString(t: grandchild) + "]" }); |
127 | } |
128 | |
129 | void appendErrors(ParsingContext&& ctx) { |
130 | errors->reserve(n: errors->size() + ctx.errors->size()); |
131 | std::move(first: ctx.errors->begin(), last: ctx.errors->end(), result: std::inserter(x&: *errors, i: errors->end())); |
132 | ctx.errors->clear(); |
133 | } |
134 | |
135 | void clearErrors() { |
136 | errors->clear(); |
137 | } |
138 | |
139 | private: |
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 | |