1
2 #include <mbgl/style/expression/parsing_context.hpp>
3 #include <mbgl/style/expression/check_subtype.hpp>
4 #include <mbgl/style/expression/is_constant.hpp>
5 #include <mbgl/style/expression/type.hpp>
6
7 #include <mbgl/style/expression/expression.hpp>
8 #include <mbgl/style/expression/at.hpp>
9 #include <mbgl/style/expression/array_assertion.hpp>
10 #include <mbgl/style/expression/assertion.hpp>
11 #include <mbgl/style/expression/boolean_operator.hpp>
12 #include <mbgl/style/expression/case.hpp>
13 #include <mbgl/style/expression/coalesce.hpp>
14 #include <mbgl/style/expression/coercion.hpp>
15 #include <mbgl/style/expression/compound_expression.hpp>
16 #include <mbgl/style/expression/equals.hpp>
17 #include <mbgl/style/expression/interpolate.hpp>
18 #include <mbgl/style/expression/length.hpp>
19 #include <mbgl/style/expression/let.hpp>
20 #include <mbgl/style/expression/literal.hpp>
21 #include <mbgl/style/expression/match.hpp>
22 #include <mbgl/style/expression/step.hpp>
23
24 #include <mbgl/style/expression/find_zoom_curve.hpp>
25
26 #include <mbgl/style/conversion/get_json_type.hpp>
27
28 #include <mbgl/util/string.hpp>
29
30 namespace mbgl {
31 namespace style {
32 namespace expression {
33
isConstant(const Expression & expression)34 bool isConstant(const Expression& expression) {
35 if (expression.getKind() == Kind::Var) {
36 auto varExpression = static_cast<const Var*>(&expression);
37 return isConstant(*varExpression->getBoundExpression());
38 }
39
40 if (expression.getKind() == Kind::CompoundExpression) {
41 auto compound = static_cast<const CompoundExpressionBase*>(&expression);
42 if (compound->getName() == "error") {
43 return false;
44 }
45 }
46
47 bool isTypeAnnotation = expression.getKind() == Kind::Coercion ||
48 expression.getKind() == Kind::Assertion ||
49 expression.getKind() == Kind::ArrayAssertion;
50
51 bool childrenConstant = true;
52 expression.eachChild([&](const Expression& child) {
53 // We can _almost_ assume that if `expressions` children are constant,
54 // they would already have been evaluated to Literal values when they
55 // were parsed. Type annotations are the exception, because they might
56 // have been inferred and added after a child was parsed.
57
58 // So we recurse into isConstant() for the children of type annotations,
59 // but otherwise simply check whether they are Literals.
60 if (isTypeAnnotation) {
61 childrenConstant = childrenConstant && isConstant(child);
62 } else {
63 childrenConstant = childrenConstant && child.getKind() == Kind::Literal;
64 }
65 });
66 if (!childrenConstant) {
67 return false;
68 }
69
70 return isFeatureConstant(expression) &&
71 isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "heatmap-density"}});
72 }
73
74 using namespace mbgl::style::conversion;
75
parse(const Convertible & value,std::size_t index_,optional<type::Type> expected_,TypeAnnotationOption typeAnnotationOption)76 ParseResult ParsingContext::parse(const Convertible& value,
77 std::size_t index_,
78 optional<type::Type> expected_,
79 TypeAnnotationOption typeAnnotationOption) {
80 ParsingContext child(key + "[" + util::toString(index_) + "]",
81 errors,
82 std::move(expected_),
83 scope);
84 return child.parse(value, typeAnnotationOption);
85 }
86
parse(const Convertible & value,std::size_t index_,optional<type::Type> expected_,const std::map<std::string,std::shared_ptr<Expression>> & bindings)87 ParseResult ParsingContext::parse(const Convertible& value, std::size_t index_, optional<type::Type> expected_,
88 const std::map<std::string, std::shared_ptr<Expression>>& bindings) {
89 ParsingContext child(key + "[" + util::toString(index_) + "]",
90 errors,
91 std::move(expected_),
92 std::make_shared<detail::Scope>(bindings, scope));
93 return child.parse(value);
94 }
95
getExpressionRegistry()96 const ExpressionRegistry& getExpressionRegistry() {
97 static ExpressionRegistry registry {{
98 {"==", Equals::parse},
99 {"!=", Equals::parse},
100 {"all", All::parse},
101 {"any", Any::parse},
102 {"array", ArrayAssertion::parse},
103 {"at", At::parse},
104 {"boolean", Assertion::parse},
105 {"case", Case::parse},
106 {"coalesce", Coalesce::parse},
107 {"collator", CollatorExpression::parse},
108 {"interpolate", parseInterpolate},
109 {"length", Length::parse},
110 {"let", Let::parse},
111 {"literal", Literal::parse},
112 {"match", parseMatch},
113 {"number", Assertion::parse},
114 {"object", Assertion::parse},
115 {"step", Step::parse},
116 {"string", Assertion::parse},
117 {"to-color", Coercion::parse},
118 {"to-number", Coercion::parse},
119 {"var", Var::parse}
120 }};
121 return registry;
122 }
123
parse(const Convertible & value,TypeAnnotationOption typeAnnotationOption)124 ParseResult ParsingContext::parse(const Convertible& value, TypeAnnotationOption typeAnnotationOption) {
125 ParseResult parsed;
126
127 if (isArray(value)) {
128 const std::size_t length = arrayLength(value);
129 if (length == 0) {
130 error(R"(Expected an array with at least one element. If you wanted a literal array, use ["literal", []].)");
131 return ParseResult();
132 }
133
134 const optional<std::string> op = toString(arrayMember(value, 0));
135 if (!op) {
136 error(
137 "Expression name must be a string, but found " + getJSONType(arrayMember(value, 0)) +
138 R"( instead. If you wanted a literal array, use ["literal", [...]].)",
139 0
140 );
141 return ParseResult();
142 }
143
144 const ExpressionRegistry& registry = getExpressionRegistry();
145 auto parseFunction = registry.find(*op);
146 if (parseFunction != registry.end()) {
147 parsed = parseFunction->second(value, *this);
148 } else {
149 parsed = parseCompoundExpression(*op, value, *this);
150 }
151 } else {
152 parsed = Literal::parse(value, *this);
153 }
154
155 if (!parsed) {
156 assert(errors->size() > 0);
157 return parsed;
158 }
159
160 auto array = [&](std::unique_ptr<Expression> expression) {
161 std::vector<std::unique_ptr<Expression>> args;
162 args.push_back(std::move(expression));
163 return args;
164 };
165
166 if (expected) {
167 const type::Type actual = (*parsed)->getType();
168 if ((*expected == type::String || *expected == type::Number || *expected == type::Boolean || *expected == type::Object) && actual == type::Value) {
169 if (typeAnnotationOption == includeTypeAnnotations) {
170 parsed = { std::make_unique<Assertion>(*expected, array(std::move(*parsed))) };
171 }
172 } else if (expected->is<type::Array>() && actual == type::Value) {
173 if (typeAnnotationOption == includeTypeAnnotations) {
174 parsed = { std::make_unique<ArrayAssertion>(expected->get<type::Array>(), std::move(*parsed)) };
175 }
176 } else if (*expected == type::Color && (actual == type::Value || actual == type::String)) {
177 if (typeAnnotationOption == includeTypeAnnotations) {
178 parsed = { std::make_unique<Coercion>(*expected, array(std::move(*parsed))) };
179 }
180 } else {
181 checkType((*parsed)->getType());
182 if (errors->size() > 0) {
183 return ParseResult();
184 }
185 }
186 }
187
188 // If an expression's arguments are all constant, we can evaluate
189 // it immediately and replace it with a literal value in the
190 // parsed result.
191 if ((*parsed)->getKind() != Kind::Literal && isConstant(**parsed)) {
192 EvaluationContext params(nullptr);
193 EvaluationResult evaluated((*parsed)->evaluate(params));
194 if (!evaluated) {
195 error(evaluated.error().message);
196 return ParseResult();
197 }
198
199 const type::Type type = (*parsed)->getType();
200 if (type.is<type::Array>()) {
201 // keep the original expression's array type, even if the evaluated
202 // type is more specific.
203 return ParseResult(std::make_unique<Literal>(
204 type.get<type::Array>(),
205 evaluated->get<std::vector<Value>>())
206 );
207 } else {
208 return ParseResult(std::make_unique<Literal>(*evaluated));
209 }
210 }
211
212 return parsed;
213 }
214
parseExpression(const Convertible & value,TypeAnnotationOption typeAnnotationOption)215 ParseResult ParsingContext::parseExpression(const Convertible& value, TypeAnnotationOption typeAnnotationOption) {
216 return parse(value, typeAnnotationOption);
217 }
218
parseLayerPropertyExpression(const Convertible & value,TypeAnnotationOption typeAnnotationOption)219 ParseResult ParsingContext::parseLayerPropertyExpression(const Convertible& value, TypeAnnotationOption typeAnnotationOption) {
220 ParseResult parsed = parse(value, typeAnnotationOption);
221 if (parsed && !isZoomConstant(**parsed)) {
222 optional<variant<const Interpolate*, const Step*, ParsingError>> zoomCurve = findZoomCurve(parsed->get());
223 if (!zoomCurve) {
224 error(R"("zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.)");
225 return ParseResult();
226 } else if (zoomCurve->is<ParsingError>()) {
227 error(zoomCurve->get<ParsingError>().message);
228 return ParseResult();
229 }
230 }
231 return parsed;
232 }
233
getCombinedErrors() const234 const std::string ParsingContext::getCombinedErrors() const {
235 std::string combinedError;
236 for (const ParsingError& parsingError : *errors) {
237 if (combinedError.size() > 0) {
238 combinedError += "\n";
239 }
240 if (parsingError.key.size() > 0) {
241 combinedError += parsingError.key + ": ";
242 }
243 combinedError += parsingError.message;
244 }
245 return combinedError;
246 }
247
checkType(const type::Type & t)248 optional<std::string> ParsingContext::checkType(const type::Type& t) {
249 assert(expected);
250 optional<std::string> err = type::checkSubtype(*expected, t);
251 if (err) {
252 error(*err);
253 }
254 return err;
255 }
256
257 } // namespace expression
258 } // namespace style
259 } // namespace mbgl
260