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