diff options
author | Anand Thakker <github@anandthakker.net> | 2017-10-27 13:44:08 -0400 |
---|---|---|
committer | Anand Thakker <github@anandthakker.net> | 2017-10-27 13:44:08 -0400 |
commit | e3b12e8e17797b27e1017e67269d4b9d22d40c20 (patch) | |
tree | 660ef6410c41c81f60fb4a91bcdbbfe5f6a3dfb1 | |
parent | 9b17784ccc01f5a0dd313b1c3a55fa4a1bc684c1 (diff) | |
download | qtlocation-mapboxgl-e3b12e8e17797b27e1017e67269d4b9d22d40c20.tar.gz |
Refactor ParsingContext
- Pass by reference
- Hide members behind getters
- Create `errors` within ParsingContext() rather than taking a
reference
- Limit public constructors to "root" context and remove `concat()` in favor of parse() overloads for parsing child expressions
30 files changed, 217 insertions, 170 deletions
diff --git a/include/mbgl/style/conversion/expression.hpp b/include/mbgl/style/conversion/expression.hpp index 21f28ca8c1..c5fcf906a7 100644 --- a/include/mbgl/style/conversion/expression.hpp +++ b/include/mbgl/style/conversion/expression.hpp @@ -14,13 +14,13 @@ using namespace mbgl::style::expression; template<> struct Converter<std::unique_ptr<Expression>> { optional<std::unique_ptr<Expression>> operator()(const Convertible& value, Error& error, type::Type expected) const { - std::vector<ParsingError> errors; - ParseResult parsed = ParsingContext(errors, expected).parse(value); + ParsingContext ctx(optional<type::Type> {expected}); + ParseResult parsed = ctx.parse(value); if (parsed) { return std::move(*parsed); } std::string combinedError; - for (const ParsingError& parsingError : errors) { + for (const ParsingError& parsingError : ctx.getErrors()) { if (combinedError.size() > 0) { combinedError += "\n"; } diff --git a/include/mbgl/style/expression/array_assertion.hpp b/include/mbgl/style/expression/array_assertion.hpp index 1b0e766c13..d7b0f786cc 100644 --- a/include/mbgl/style/expression/array_assertion.hpp +++ b/include/mbgl/style/expression/array_assertion.hpp @@ -18,7 +18,7 @@ public: input(std::move(input_)) {} - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>& visit) const override; diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp index 635ec5eff1..e572f7a6f9 100644 --- a/include/mbgl/style/expression/assertion.hpp +++ b/include/mbgl/style/expression/assertion.hpp @@ -16,7 +16,7 @@ public: inputs(std::move(inputs_)) {} - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>& visit) const override; diff --git a/include/mbgl/style/expression/at.hpp b/include/mbgl/style/expression/at.hpp index f04b24dcb7..171c8ec9b1 100644 --- a/include/mbgl/style/expression/at.hpp +++ b/include/mbgl/style/expression/at.hpp @@ -16,7 +16,7 @@ public: input(std::move(input_)) {} - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>&) const override; diff --git a/include/mbgl/style/expression/boolean_operator.hpp b/include/mbgl/style/expression/boolean_operator.hpp index 7a7f2b30d3..4e025c5d2d 100644 --- a/include/mbgl/style/expression/boolean_operator.hpp +++ b/include/mbgl/style/expression/boolean_operator.hpp @@ -15,7 +15,7 @@ public: inputs(std::move(inputs_)) {} - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>& visit) const override; @@ -31,7 +31,7 @@ public: inputs(std::move(inputs_)) {} - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>& visit) const override; diff --git a/include/mbgl/style/expression/case.hpp b/include/mbgl/style/expression/case.hpp index 9ee3896e2b..26d030aed6 100644 --- a/include/mbgl/style/expression/case.hpp +++ b/include/mbgl/style/expression/case.hpp @@ -19,7 +19,7 @@ public: : Expression(type_), branches(std::move(branches_)), otherwise(std::move(otherwise_)) { } - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>& visit) const override; diff --git a/include/mbgl/style/expression/coalesce.hpp b/include/mbgl/style/expression/coalesce.hpp index 2dbf236032..f32949ea76 100644 --- a/include/mbgl/style/expression/coalesce.hpp +++ b/include/mbgl/style/expression/coalesce.hpp @@ -19,7 +19,7 @@ public: args(std::move(args_)) {} - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); EvaluationResult evaluate(const EvaluationContext& params) const override; diff --git a/include/mbgl/style/expression/coercion.hpp b/include/mbgl/style/expression/coercion.hpp index 978f6320d2..65bd1aab58 100644 --- a/include/mbgl/style/expression/coercion.hpp +++ b/include/mbgl/style/expression/coercion.hpp @@ -17,7 +17,7 @@ class Coercion : public Expression { public: Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_); - static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>& visit) const override; diff --git a/include/mbgl/style/expression/compound_expression.hpp b/include/mbgl/style/expression/compound_expression.hpp index 8dfe175f44..909927e299 100644 --- a/include/mbgl/style/expression/compound_expression.hpp +++ b/include/mbgl/style/expression/compound_expression.hpp @@ -115,16 +115,16 @@ struct CompoundExpressionRegistry { static std::unordered_map<std::string, Definition> definitions; }; -ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext ctx); +ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); ParseResult createCompoundExpression(const std::string& name, const CompoundExpressionRegistry::Definition& definition, std::vector<std::unique_ptr<Expression>> args, - ParsingContext ctx); + ParsingContext& ctx); ParseResult createCompoundExpression(const std::string& name, std::vector<std::unique_ptr<Expression>> args, - ParsingContext ctx); + ParsingContext& ctx); } // namespace expression } // namespace style diff --git a/include/mbgl/style/expression/curve.hpp b/include/mbgl/style/expression/curve.hpp index 6a46a6e152..c1d0eb6ac9 100644 --- a/include/mbgl/style/expression/curve.hpp +++ b/include/mbgl/style/expression/curve.hpp @@ -55,7 +55,7 @@ public: }; -ParseResult parseCurve(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); +ParseResult parseCurve(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); template <typename T> diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index 25c84fbf13..85fffae938 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -104,10 +104,9 @@ public: evaluation logic that can't be handled by CompoundExpression's inference mechanism. - Each Expression subclass has an accompanying - template <class V> ParseResult ParseXxxx::parse(const V&, ParsingContext), - found in style/expression/parse/xxxx.hpp, which handles parsing a style-spec - JSON representation of the expression. + Each Expression subclass also provides a static + ParseResult ExpressionClass::parse(const V&, ParsingContext), + which handles parsing a style-spec JSON representation of the expression. */ class Expression { public: diff --git a/include/mbgl/style/expression/let.hpp b/include/mbgl/style/expression/let.hpp index 499dd0b657..a9356853df 100644 --- a/include/mbgl/style/expression/let.hpp +++ b/include/mbgl/style/expression/let.hpp @@ -21,7 +21,7 @@ public: result(std::move(result_)) {} - static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext); + static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>&) const override; @@ -43,7 +43,7 @@ public: value(value_) {} - static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext); + static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression*)>&) const override; diff --git a/include/mbgl/style/expression/literal.hpp b/include/mbgl/style/expression/literal.hpp index 84f72d540a..34d539fedf 100644 --- a/include/mbgl/style/expression/literal.hpp +++ b/include/mbgl/style/expression/literal.hpp @@ -18,7 +18,7 @@ public: return value; } - static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext); + static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&); void eachChild(const std::function<void(const Expression*)>&) const override {} diff --git a/include/mbgl/style/expression/match.hpp b/include/mbgl/style/expression/match.hpp index 38d4edeee5..01c0db5bf5 100644 --- a/include/mbgl/style/expression/match.hpp +++ b/include/mbgl/style/expression/match.hpp @@ -36,7 +36,7 @@ private: std::unique_ptr<Expression> otherwise; }; -ParseResult parseMatch(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); +ParseResult parseMatch(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); } // namespace expression } // namespace style diff --git a/include/mbgl/style/expression/parsing_context.hpp b/include/mbgl/style/expression/parsing_context.hpp index 56d68c19d2..9aa287869b 100644 --- a/include/mbgl/style/expression/parsing_context.hpp +++ b/include/mbgl/style/expression/parsing_context.hpp @@ -24,7 +24,8 @@ using ParseResult = optional<std::unique_ptr<Expression>>; namespace detail { -struct Scope { +class Scope { +public: Scope(const std::map<std::string, std::shared_ptr<Expression>>& bindings_, std::shared_ptr<Scope> parent_ = nullptr) : bindings(bindings_), parent(std::move(parent_)) @@ -49,28 +50,18 @@ struct Scope { class ParsingContext { public: - ParsingContext(std::vector<ParsingError>& errors_, optional<type::Type> expected_ = {}) - : errors(errors_), - expected(std::move(expected_)) + ParsingContext() : errors(std::make_shared<std::vector<ParsingError>>()) {} + ParsingContext(std::string key) : key(std::move(key)), errors(std::make_shared<std::vector<ParsingError>>()) {} + explicit ParsingContext(optional<type::Type> expected_) + : expected(std::move(expected_)), + errors(std::make_shared<std::vector<ParsingError>>()) {} + ParsingContext(ParsingContext&&) = default; - ParsingContext concat(std::size_t index_, optional<type::Type> expected_ = {}) { - return ParsingContext(key + "[" + std::to_string(index_) + "]", - errors, - std::move(expected_), - scope); - } - - ParsingContext concat(std::size_t index_, - optional<type::Type> expected_, - const std::map<std::string, std::shared_ptr<Expression>>& bindings) { - return ParsingContext(key + "[" + std::to_string(index_) + "]", - errors, - std::move(expected_), - std::make_shared<detail::Scope>(bindings, scope)); + std::string getKey() const { return key; } + optional<type::Type> getExpected() const { return expected; } + const std::vector<ParsingError>& getErrors() const { return *errors; } - } - /* Parse the given style-spec JSON value into an Expression object. Specifically, this function is responsible for determining the expression @@ -80,6 +71,21 @@ public: ParseResult parse(const mbgl::style::conversion::Convertible& value); /* + Parse a child expression. + */ + ParseResult parse(const mbgl::style::conversion::Convertible&, + std::size_t, + optional<type::Type> = {}); + + /* + Parse a child expression. + */ + ParseResult parse(const mbgl::style::conversion::Convertible&, + std::size_t index, + optional<type::Type>, + const std::map<std::string, std::shared_ptr<Expression>>&); + + /* Check whether `t` is a subtype of `expected`, collecting an error if not. */ optional<std::string> checkType(const type::Type& t); @@ -90,28 +96,45 @@ public: } void error(std::string message) { - errors.push_back({message, key}); + errors->push_back({message, key}); } - void error(std::string message, std::size_t child) { - errors.push_back({message, key + "[" + std::to_string(child) + "]"}); + void error(std::string message, std::size_t child) { + errors->push_back({message, key + "[" + std::to_string(child) + "]"}); } - - std::string key; - std::vector<ParsingError>& errors; - optional<type::Type> expected; - std::shared_ptr<detail::Scope> scope; - + + void error(std::string message, std::size_t child, std::size_t grandchild) { + errors->push_back({message, key + "[" + std::to_string(child) + "][" + std::to_string(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::vector<ParsingError>& errors_, + std::shared_ptr<std::vector<ParsingError>> errors_, optional<type::Type> expected_, std::shared_ptr<detail::Scope> scope_) : key(std::move(key_)), - errors(errors_), expected(std::move(expected_)), - scope(std::move(scope_)) + scope(std::move(scope_)), + errors(std::move(errors_)) {} + + ParsingContext(const ParsingContext&) = delete; + ParsingContext& operator=(const ParsingContext&) = delete; + + std::string key; + optional<type::Type> expected; + std::shared_ptr<detail::Scope> scope; + std::shared_ptr<std::vector<ParsingError>> errors; }; } // namespace expression diff --git a/include/mbgl/style/function/convert.hpp b/include/mbgl/style/function/convert.hpp index ac148c7af1..e07b4038ea 100644 --- a/include/mbgl/style/function/convert.hpp +++ b/include/mbgl/style/function/convert.hpp @@ -55,10 +55,13 @@ struct Convert { return std::make_unique<Literal>(Value(toExpressionValue(value))); } - static std::unique_ptr<Expression> makeGet(type::Type type, const std::string& property, ParsingContext ctx) { + static std::unique_ptr<Expression> makeGet(type::Type type, const std::string& property) { + ParsingContext ctx; std::vector<std::unique_ptr<Expression>> getArgs; getArgs.push_back(makeLiteral(property)); ParseResult get = createCompoundExpression("get", std::move(getArgs), ctx); + assert(get); + assert(ctx.getErrors().size() == 0); std::vector<std::unique_ptr<Expression>> assertionArgs; assertionArgs.push_back(std::move(*get)); @@ -66,8 +69,12 @@ struct Convert { return std::make_unique<Assertion>(type, std::move(assertionArgs)); } - static std::unique_ptr<Expression> makeZoom(ParsingContext ctx) { - return std::move(*(createCompoundExpression("zoom", std::vector<std::unique_ptr<Expression>>(), ctx))); + static std::unique_ptr<Expression> makeZoom() { + ParsingContext ctx; + ParseResult zoom = createCompoundExpression("zoom", std::vector<std::unique_ptr<Expression>>(), ctx); + assert(zoom); + assert(ctx.getErrors().size() == 0); + return std::move(*zoom); } static std::unique_ptr<Expression> makeError(std::string message) { @@ -145,19 +152,16 @@ struct Convert { type::Type type = valueTypeToExpressionType<T>(); - std::vector<ParsingError> errors; - ParsingContext ctx(errors); - const CategoricalValue& firstKey = stops.begin()->first; return firstKey.match( [&](bool) { - return makeCase(type, makeGet(type::Boolean, property, ctx), std::move(convertedStops)); + return makeCase(type, makeGet(type::Boolean, property), std::move(convertedStops)); }, [&](const std::string&) { - return makeMatch<std::string>(type, makeGet(type::String, property, ctx), std::move(convertedStops)); + return makeMatch<std::string>(type, makeGet(type::String, property), std::move(convertedStops)); }, [&](int64_t) { - return makeMatch<int64_t>(type, makeGet(type::Number, property, ctx), std::move(convertedStops)); + return makeMatch<int64_t>(type, makeGet(type::Number, property), std::move(convertedStops)); } ); } @@ -177,10 +181,9 @@ struct Convert { template <typename T> static std::unique_ptr<Expression> toExpression(const ExponentialStops<T>& stops) { - std::vector<ParsingError> errors; ParseResult e = makeCurve<typename ValueConverter<T>::ExpressionType>( valueTypeToExpressionType<T>(), - makeZoom(ParsingContext(errors)), + makeZoom(), convertStops(stops.stops), ExponentialInterpolator(stops.base)); assert(e); @@ -190,9 +193,8 @@ struct Convert { template <typename T> static std::unique_ptr<Expression> toExpression(const IntervalStops<T>& stops) { - std::vector<ParsingError> errors; ParseResult e = makeCurve<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), - makeZoom(ParsingContext(errors)), + makeZoom(), convertStops(stops.stops), StepInterpolator()); assert(e); @@ -203,9 +205,8 @@ struct Convert { static std::unique_ptr<Expression> toExpression(const std::string& property, const ExponentialStops<T>& stops) { - std::vector<ParsingError> errors; ParseResult e = makeCurve<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), - makeGet(type::Number, property, ParsingContext(errors)), + makeGet(type::Number, property), convertStops(stops.stops), ExponentialInterpolator(stops.base)); assert(e); @@ -216,8 +217,7 @@ struct Convert { static std::unique_ptr<Expression> toExpression(const std::string& property, const IntervalStops<T>& stops) { - std::vector<ParsingError> errors; - std::unique_ptr<Expression> get = makeGet(type::Number, property, ParsingContext(errors)); + std::unique_ptr<Expression> get = makeGet(type::Number, property); ParseResult e = makeCurve<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), std::move(get), convertStops(stops.stops), @@ -250,10 +250,9 @@ struct Convert { static std::unique_ptr<Expression> toExpression(const std::string& property, const CompositeExponentialStops<T>& stops) { - std::vector<ParsingError> errors; std::map<double, std::unique_ptr<Expression>> outerStops; for (const std::pair<float, std::map<float, T>>& stop : stops.stops) { - std::unique_ptr<Expression> get = makeGet(type::Number, property, ParsingContext(errors)); + std::unique_ptr<Expression> get = makeGet(type::Number, property); ParseResult innerCurve = makeCurve<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), std::move(get), convertStops(stop.second), @@ -262,7 +261,7 @@ struct Convert { outerStops.emplace(stop.first, std::move(*innerCurve)); } ParseResult outerCurve = makeCurve<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), - makeZoom(ParsingContext(errors)), + makeZoom(), std::move(outerStops), zoomInterpolator<T>()); assert(outerCurve); @@ -273,10 +272,9 @@ struct Convert { static std::unique_ptr<Expression> toExpression(const std::string& property, const CompositeIntervalStops<T>& stops) { - std::vector<ParsingError> errors; std::map<double, std::unique_ptr<Expression>> outerStops; for (const std::pair<float, std::map<float, T>>& stop : stops.stops) { - std::unique_ptr<Expression> get = makeGet(type::Number, property, ParsingContext(errors)); + std::unique_ptr<Expression> get = makeGet(type::Number, property); ParseResult innerCurve = makeCurve<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), std::move(get), convertStops(stop.second), @@ -285,7 +283,7 @@ struct Convert { outerStops.emplace(stop.first, std::move(*innerCurve)); } ParseResult outerCurve = makeCurve<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), - makeZoom(ParsingContext(errors)), + makeZoom(), std::move(outerStops), zoomInterpolator<T>()); assert(outerCurve); @@ -296,7 +294,6 @@ struct Convert { static std::unique_ptr<Expression> toExpression(const std::string& property, const CompositeCategoricalStops<T>& stops) { - std::vector<ParsingError> errors; std::map<double, std::unique_ptr<Expression>> outerStops; for (const std::pair<float, std::map<CategoricalValue, T>>& stop : stops.stops) { ParseResult innerCurve = fromCategoricalStops(stop.second, property); @@ -304,7 +301,7 @@ struct Convert { outerStops.emplace(stop.first, std::move(*innerCurve)); } ParseResult outerCurve = makeCurve<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), - makeZoom(ParsingContext(errors)), + makeZoom(), std::move(outerStops), zoomInterpolator<T>()); assert(outerCurve); @@ -316,27 +313,28 @@ struct Convert { static std::unique_ptr<Expression> toExpression(const std::string& property, const IdentityStops<T>&) { - std::vector<ParsingError> errors; - std::unique_ptr<Expression> input = valueTypeToExpressionType<T>().match( [&] (const type::StringType&) { - return makeGet(type::String, property, ParsingContext(errors)); + return makeGet(type::String, property); }, [&] (const type::NumberType&) { - return makeGet(type::Number, property, ParsingContext(errors)); + return makeGet(type::Number, property); }, [&] (const type::BooleanType&) { - return makeGet(type::Boolean, property, ParsingContext(errors)); + return makeGet(type::Boolean, property); }, [&] (const type::ColorType&) { std::vector<std::unique_ptr<Expression>> args; - args.push_back(makeGet(type::String, property, ParsingContext(errors))); + args.push_back(makeGet(type::String, property)); return std::make_unique<Coercion>(type::Color, std::move(args)); }, [&] (const type::Array& arr) { std::vector<std::unique_ptr<Expression>> getArgs; getArgs.push_back(makeLiteral(property)); - ParseResult get = createCompoundExpression("get", std::move(getArgs), ParsingContext(errors)); + ParsingContext ctx; + ParseResult get = createCompoundExpression("get", std::move(getArgs), ctx); + assert(get); + assert(ctx.getErrors().size() == 0); return std::make_unique<ArrayAssertion>(arr, std::move(*get)); }, [&] (const auto&) -> std::unique_ptr<Expression> { diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp index 8ab3e71f9e..bcbd62cfd0 100644 --- a/platform/node/src/node_expression.cpp +++ b/platform/node/src/node_expression.cpp @@ -72,10 +72,10 @@ void NodeExpression::Parse(const Nan::FunctionCallbackInfo<v8::Value>& info) { auto expr = info[0]; try { - std::vector<ParsingError> errors; - ParseResult parsed = ParsingContext(errors, expected).parse(mbgl::style::conversion::Convertible(expr)); + ParsingContext ctx(expected); + ParseResult parsed = ctx.parse(mbgl::style::conversion::Convertible(expr)); if (parsed) { - assert(errors.size() == 0); + assert(ctx.getErrors().size() == 0); auto nodeExpr = new NodeExpression(std::move(*parsed)); const int argc = 0; v8::Local<v8::Value> argv[0] = {}; @@ -86,8 +86,8 @@ void NodeExpression::Parse(const Nan::FunctionCallbackInfo<v8::Value>& info) { } v8::Local<v8::Array> result = Nan::New<v8::Array>(); - for (std::size_t i = 0; i < errors.size(); i++) { - const auto& error = errors[i]; + for (std::size_t i = 0; i < ctx.getErrors().size(); i++) { + const auto& error = ctx.getErrors()[i]; v8::Local<v8::Object> err = Nan::New<v8::Object>(); Nan::Set(err, Nan::New("key").ToLocalChecked(), diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp index 2faa696302..8031868c9c 100644 --- a/src/mbgl/style/expression/array_assertion.cpp +++ b/src/mbgl/style/expression/array_assertion.cpp @@ -26,7 +26,7 @@ void ArrayAssertion::eachChild(const std::function<void(const Expression*)>& vis } using namespace mbgl::style::conversion; -ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext ctx) { +ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map<std::string, type::Type> itemTypes { {"string", type::String}, @@ -69,7 +69,7 @@ ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext ctx) N = optional<std::size_t>(*n); } - auto input = ctx.concat(length - 1, {type::Value}).parse(arrayMember(value, length - 1)); + auto input = ctx.parse(arrayMember(value, length - 1), length - 1, {type::Value}); if (!input) { return input; } diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 59b4c6e1ae..3b0846ec63 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -6,7 +6,7 @@ namespace style { namespace expression { using namespace mbgl::style::conversion; -ParseResult Assertion::parse(const Convertible& value, ParsingContext ctx) { +ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map<std::string, type::Type> types { {"string", type::String}, {"number", type::Number}, @@ -27,7 +27,7 @@ ParseResult Assertion::parse(const Convertible& value, ParsingContext ctx) { std::vector<std::unique_ptr<Expression>> parsed; parsed.reserve(length - 1); for (std::size_t i = 1; i < length; i++) { - ParseResult input = ctx.concat(i, {type::Value}).parse(arrayMember(value, i)); + ParseResult input = ctx.parse(arrayMember(value, i), i, {type::Value}); if (!input) return ParseResult(); parsed.push_back(std::move(*input)); } diff --git a/src/mbgl/style/expression/at.cpp b/src/mbgl/style/expression/at.cpp index 5c8fddeed1..535ebee8a0 100644 --- a/src/mbgl/style/expression/at.cpp +++ b/src/mbgl/style/expression/at.cpp @@ -38,7 +38,7 @@ void At::eachChild(const std::function<void(const Expression*)>& visit) const { } using namespace mbgl::style::conversion; -ParseResult At::parse(const Convertible& value, ParsingContext ctx) { +ParseResult At::parse(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); std::size_t length = arrayLength(value); @@ -47,8 +47,10 @@ ParseResult At::parse(const Convertible& value, ParsingContext ctx) { return ParseResult(); } - ParseResult index = ctx.concat(1, {type::Number}).parse(arrayMember(value, 1)); - ParseResult input = ctx.concat(2, {type::Array(ctx.expected ? *ctx.expected : type::Value)}).parse(arrayMember(value, 2)); + ParseResult index = ctx.parse(arrayMember(value, 1), 1, {type::Number}); + + type::Type inputType = type::Array(ctx.getExpected() ? *ctx.getExpected() : type::Value); + ParseResult input = ctx.parse(arrayMember(value, 2), 2, {inputType}); if (!index || !input) return ParseResult(); diff --git a/src/mbgl/style/expression/boolean_operator.cpp b/src/mbgl/style/expression/boolean_operator.cpp index 986de99d4b..c960d5d79a 100644 --- a/src/mbgl/style/expression/boolean_operator.cpp +++ b/src/mbgl/style/expression/boolean_operator.cpp @@ -37,7 +37,7 @@ void All::eachChild(const std::function<void(const Expression*)>& visit) const { using namespace mbgl::style::conversion; template <class T> -ParseResult parseBooleanOp(const Convertible& value, ParsingContext ctx) { +ParseResult parseBooleanOp(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); auto length = arrayLength(value); @@ -46,7 +46,7 @@ ParseResult parseBooleanOp(const Convertible& value, ParsingContext ctx) { parsedInputs.reserve(length - 1); for (std::size_t i = 1; i < length; i++) { - auto parsed = ctx.concat(i, {type::Boolean}).parse(arrayMember(value, i)); + auto parsed = ctx.parse(arrayMember(value, i), i, {type::Boolean}); if (!parsed) { return parsed; } @@ -57,11 +57,11 @@ ParseResult parseBooleanOp(const Convertible& value, ParsingContext ctx) { return ParseResult(std::make_unique<T>(std::move(parsedInputs))); } -ParseResult Any::parse(const Convertible& value, ParsingContext ctx) { +ParseResult Any::parse(const Convertible& value, ParsingContext& ctx) { return parseBooleanOp<Any>(value, ctx); } -ParseResult All::parse(const Convertible& value, ParsingContext ctx) { +ParseResult All::parse(const Convertible& value, ParsingContext& ctx) { return parseBooleanOp<All>(value, ctx); } diff --git a/src/mbgl/style/expression/case.cpp b/src/mbgl/style/expression/case.cpp index 8c6c2c0c8f..1d2fd70978 100644 --- a/src/mbgl/style/expression/case.cpp +++ b/src/mbgl/style/expression/case.cpp @@ -27,7 +27,7 @@ void Case::eachChild(const std::function<void(const Expression*)>& visit) const } using namespace mbgl::style::conversion; -ParseResult Case::parse(const Convertible& value, ParsingContext ctx) { +ParseResult Case::parse(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); auto length = arrayLength(value); if (length < 4) { @@ -42,19 +42,19 @@ ParseResult Case::parse(const Convertible& value, ParsingContext ctx) { } optional<type::Type> outputType; - if (ctx.expected && *ctx.expected != type::Value) { - outputType = ctx.expected; + if (ctx.getExpected() && *ctx.getExpected() != type::Value) { + outputType = ctx.getExpected(); } std::vector<Case::Branch> branches; branches.reserve((length - 2) / 2); for (size_t i = 1; i + 1 < length; i += 2) { - auto test = ctx.concat(i, {type::Boolean}).parse(arrayMember(value, i)); + auto test = ctx.parse(arrayMember(value, i), i, {type::Boolean}); if (!test) { return test; } - auto output = ctx.concat(i + 1, outputType).parse(arrayMember(value, i + 1)); + auto output = ctx.parse(arrayMember(value, i + 1), i + 1, outputType); if (!output) { return output; } @@ -68,7 +68,7 @@ ParseResult Case::parse(const Convertible& value, ParsingContext ctx) { assert(outputType); - auto otherwise = ctx.concat(length - 1, outputType).parse(arrayMember(value, length - 1)); + auto otherwise = ctx.parse(arrayMember(value, length - 1), length - 1, outputType); if (!otherwise) { return otherwise; } diff --git a/src/mbgl/style/expression/coalesce.cpp b/src/mbgl/style/expression/coalesce.cpp index 784492c51e..54ac0fa499 100644 --- a/src/mbgl/style/expression/coalesce.cpp +++ b/src/mbgl/style/expression/coalesce.cpp @@ -20,7 +20,7 @@ void Coalesce::eachChild(const std::function<void(const Expression*)>& visit) co } using namespace mbgl::style::conversion; -ParseResult Coalesce::parse(const Convertible& value, ParsingContext ctx) { +ParseResult Coalesce::parse(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); auto length = arrayLength(value); if (length < 2) { @@ -29,14 +29,14 @@ ParseResult Coalesce::parse(const Convertible& value, ParsingContext ctx) { } optional<type::Type> outputType; - if (ctx.expected && *ctx.expected != type::Value) { - outputType = ctx.expected; + if (ctx.getExpected() && *ctx.getExpected() != type::Value) { + outputType = ctx.getExpected(); } Coalesce::Args args; args.reserve(length - 1); for (std::size_t i = 1; i < length; i++) { - auto parsed = ctx.concat(i, outputType).parse(arrayMember(value, i)); + auto parsed = ctx.parse(arrayMember(value, i), i, outputType); if (!parsed) { return parsed; } diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index a0c4a1abfb..c5a9b80dd5 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -81,7 +81,7 @@ Coercion::Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> in } using namespace mbgl::style::conversion; -ParseResult Coercion::parse(const Convertible& value, ParsingContext ctx) { +ParseResult Coercion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map<std::string, type::Type> types { {"to-number", type::Number}, {"to-color", type::Color} @@ -100,7 +100,7 @@ ParseResult Coercion::parse(const Convertible& value, ParsingContext ctx) { std::vector<std::unique_ptr<Expression>> parsed; parsed.reserve(length - 1); for (std::size_t i = 1; i < length; i++) { - ParseResult input = ctx.concat(i, {type::Value}).parse(arrayMember(value, i)); + ParseResult input = ctx.parse(arrayMember(value, i), i, {type::Value}); if (!input) return ParseResult(); parsed.push_back(std::move(*input)); } diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index a08a556480..65ece14328 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -1,4 +1,5 @@ #include <mbgl/style/expression/compound_expression.hpp> +#include <mbgl/style/expression/check_subtype.hpp> #include <mbgl/style/expression/util.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/util/ignore.hpp> @@ -437,7 +438,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali std::unordered_map<std::string, Definition> CompoundExpressionRegistry::definitions = initializeDefinitions(); using namespace mbgl::style::conversion; -ParseResult parseCompoundExpression(const std::string name, const Convertible& value, ParsingContext ctx) { +ParseResult parseCompoundExpression(const std::string name, const Convertible& value, ParsingContext& ctx) { assert(isArray(value) && arrayLength(value) > 0); auto it = CompoundExpressionRegistry::definitions.find(name); @@ -483,7 +484,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v ); } - auto parsed = ctx.concat(i, expected).parse(arrayMember(value, i)); + auto parsed = ctx.parse(arrayMember(value, i), i, expected); if (!parsed) { return parsed; } @@ -495,7 +496,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v ParseResult createCompoundExpression(const std::string& name, std::vector<std::unique_ptr<Expression>> args, - ParsingContext ctx) + ParsingContext& ctx) { return createCompoundExpression(name, CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); } @@ -504,16 +505,12 @@ ParseResult createCompoundExpression(const std::string& name, ParseResult createCompoundExpression(const std::string& name, const Definition& definition, std::vector<std::unique_ptr<Expression>> args, - ParsingContext ctx) + ParsingContext& ctx) { - std::vector<ParsingError> currentSignatureErrors; - - ParsingContext signatureContext(currentSignatureErrors); - signatureContext.key = ctx.key; + ParsingContext signatureContext(ctx.getKey()); for (const std::unique_ptr<detail::SignatureBase>& signature : definition) { - currentSignatureErrors.clear(); - + signatureContext.clearErrors(); if (signature->params.is<std::vector<type::Type>>()) { const std::vector<type::Type>& params = signature->params.get<std::vector<type::Type>>(); @@ -527,23 +524,29 @@ ParseResult createCompoundExpression(const std::string& name, for (std::size_t i = 0; i < args.size(); i++) { const std::unique_ptr<Expression>& arg = args[i]; - signatureContext.concat(i + 1, params.at(i)).checkType(arg->getType()); + optional<std::string> err = type::checkSubtype(params.at(i), arg->getType()); + if (err) { + signatureContext.error(*err, i + 1); + } } } else if (signature->params.is<VarargsType>()) { const type::Type& paramType = signature->params.get<VarargsType>().type; for (std::size_t i = 0; i < args.size(); i++) { const std::unique_ptr<Expression>& arg = args[i]; - signatureContext.concat(i + 1, paramType).checkType(arg->getType()); + optional<std::string> err = type::checkSubtype(paramType, arg->getType()); + if (err) { + signatureContext.error(*err, i + 1); + } } } - if (currentSignatureErrors.size() == 0) { + if (signatureContext.getErrors().size() == 0) { return ParseResult(signature->makeExpression(name, std::move(args))); } } if (definition.size() == 1) { - ctx.errors.insert(ctx.errors.end(), currentSignatureErrors.begin(), currentSignatureErrors.end()); + ctx.appendErrors(std::move(signatureContext)); } else { std::string signatures; for (const auto& signature : definition) { diff --git a/src/mbgl/style/expression/curve.cpp b/src/mbgl/style/expression/curve.cpp index d34ac1cadd..d786a147aa 100644 --- a/src/mbgl/style/expression/curve.cpp +++ b/src/mbgl/style/expression/curve.cpp @@ -11,7 +11,7 @@ using Interpolator = variant<StepInterpolator, using namespace mbgl::style::conversion; -ParseResult parseCurve(const Convertible& value, ParsingContext ctx) { +ParseResult parseCurve(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); auto length = arrayLength(value); @@ -32,7 +32,6 @@ ParseResult parseCurve(const Convertible& value, ParsingContext ctx) { bool isStep = false; const optional<std::string> interpName = toString(arrayMember(interp, 0)); - ParsingContext interpContext = ctx.concat(1); if (interpName && *interpName == "step") { interpolator = StepInterpolator(); isStep = true; @@ -44,7 +43,7 @@ ParseResult parseCurve(const Convertible& value, ParsingContext ctx) { base = toDouble(arrayMember(interp, 1)); } if (!base) { - interpContext.error("Exponential interpolation requires a numeric base.", 1); + ctx.error("Exponential interpolation requires a numeric base.", 1, 1); return ParseResult(); } interpolator = ExponentialInterpolator(*base); @@ -66,13 +65,13 @@ ParseResult parseCurve(const Convertible& value, ParsingContext ctx) { *x2 < 0 || *x2 > 1 || *y2 < 0 || *y2 > 1 ) { - interpContext.error("Cubic bezier interpolation requires four numeric arguments with values between 0 and 1."); + ctx.error("Cubic bezier interpolation requires four numeric arguments with values between 0 and 1.", 1); return ParseResult(); } interpolator = CubicBezierInterpolator(*x1, *y1, *x2, *y2); } else { - interpContext.error("Unknown interpolation type " + (interpName ? *interpName : ""), 0); + ctx.error("Unknown interpolation type " + (interpName ? *interpName : ""), 1, 0); return ParseResult(); } @@ -90,15 +89,15 @@ ParseResult parseCurve(const Convertible& value, ParsingContext ctx) { } - ParseResult input = ctx.concat(2, {type::Number}).parse(arrayMember(value, 2)); + ParseResult input = ctx.parse(arrayMember(value, 2), 2, {type::Number}); if (!input) { return input; } std::map<double, std::unique_ptr<Expression>> stops; optional<type::Type> outputType; - if (ctx.expected && *ctx.expected != type::Value) { - outputType = ctx.expected; + if (ctx.getExpected() && *ctx.getExpected() != type::Value) { + outputType = ctx.getExpected(); } double previous = - std::numeric_limits<double>::infinity(); @@ -107,7 +106,7 @@ ParseResult parseCurve(const Convertible& value, ParsingContext ctx) { // than an input level, so consume that output value before proceeding into the // "stops" loop below. if (isStep) { - auto output = ctx.concat(3, outputType).parse(arrayMember(value, 3)); + auto output = ctx.parse(arrayMember(value, 3), 3, outputType); if (!output) { return ParseResult(); } @@ -163,7 +162,7 @@ ParseResult parseCurve(const Convertible& value, ParsingContext ctx) { } previous = *label; - auto output = ctx.concat(i + 1, outputType).parse(arrayMember(value, i + 1)); + auto output = ctx.parse(arrayMember(value, i + 1), i + 1, outputType); if (!output) { return ParseResult(); } diff --git a/src/mbgl/style/expression/let.cpp b/src/mbgl/style/expression/let.cpp index d94d80f6d7..daebf5dd08 100644 --- a/src/mbgl/style/expression/let.cpp +++ b/src/mbgl/style/expression/let.cpp @@ -18,7 +18,7 @@ void Let::eachChild(const std::function<void(const Expression*)>& visit) const { using namespace mbgl::style::conversion; -ParseResult Let::parse(const Convertible& value, ParsingContext ctx) { +ParseResult Let::parse(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); std::size_t length = arrayLength(value); @@ -44,7 +44,7 @@ ParseResult Let::parse(const Convertible& value, ParsingContext ctx) { return ParseResult(); } - ParseResult bindingValue = ctx.concat(i + 1).parse(arrayMember(value, i + 1)); + ParseResult bindingValue = ctx.parse(arrayMember(value, i + 1), i + 1); if (!bindingValue) { return ParseResult(); } @@ -52,8 +52,7 @@ ParseResult Let::parse(const Convertible& value, ParsingContext ctx) { bindings_.emplace(*name, std::move(*bindingValue)); } - auto resultContext = ctx.concat(length - 1, ctx.expected, bindings_); - ParseResult result_ = resultContext.parse(arrayMember(value, length - 1)); + ParseResult result_ = ctx.parse(arrayMember(value, length - 1), length - 1, ctx.getExpected(), bindings_); if (!result_) { return ParseResult(); } @@ -67,7 +66,7 @@ EvaluationResult Var::evaluate(const EvaluationContext& params) const { void Var::eachChild(const std::function<void(const Expression*)>&) const {} -ParseResult Var::parse(const Convertible& value_, ParsingContext ctx) { +ParseResult Var::parse(const Convertible& value_, ParsingContext& ctx) { assert(isArray(value_)); if (arrayLength(value_) != 2 || !toString(arrayMember(value_, 1))) { diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 900ebe2afb..85664f0399 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -15,7 +15,7 @@ optional<Value> checkNumber(T n) { } using namespace mbgl::style::conversion; -optional<Value> parseValue(const Convertible& value, ParsingContext ctx) { +optional<Value> parseValue(const Convertible& value, ParsingContext& ctx) { if (isUndefined(value)) return {Null}; if (isObject(value)) { std::unordered_map<std::string, Value> result; @@ -61,7 +61,7 @@ optional<Value> parseValue(const Convertible& value, ParsingContext ctx) { ); } -ParseResult Literal::parse(const Convertible& value, ParsingContext ctx) { +ParseResult Literal::parse(const Convertible& value, ParsingContext& ctx) { const optional<Value> parsedValue = parseValue(value, ctx); if (!parsedValue) { @@ -70,12 +70,12 @@ ParseResult Literal::parse(const Convertible& value, ParsingContext ctx) { // special case: infer the item type if possible for zero-length arrays if ( - ctx.expected && - ctx.expected->template is<type::Array>() && + ctx.getExpected() && + ctx.getExpected()->template is<type::Array>() && parsedValue->template is<std::vector<Value>>() ) { auto type = typeOf(*parsedValue).template get<type::Array>(); - auto expected = ctx.expected->template get<type::Array>(); + auto expected = ctx.getExpected()->template get<type::Array>(); if ( type.N && (*type.N == 0) && (!expected.N || (*expected.N == 0)) diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp index 93947813ac..22f6a9f3e5 100644 --- a/src/mbgl/style/expression/match.cpp +++ b/src/mbgl/style/expression/match.cpp @@ -1,4 +1,5 @@ #include <mbgl/style/expression/match.hpp> +#include <mbgl/style/expression/check_subtype.hpp> #include <mbgl/style/expression/parsing_context.hpp> namespace mbgl { @@ -52,7 +53,7 @@ template class Match<std::string>; using InputType = variant<int64_t, std::string>; using namespace mbgl::style::conversion; -optional<InputType> parseInputValue(const Convertible& input, ParsingContext ctx, optional<type::Type>& inputType) { +optional<InputType> parseInputValue(const Convertible& input, ParsingContext& parentContext, std::size_t index, optional<type::Type>& inputType) { using namespace mbgl::style::conversion; optional<InputType> result; optional<type::Type> type; @@ -63,7 +64,7 @@ optional<InputType> parseInputValue(const Convertible& input, ParsingContext ctx value->match( [&] (uint64_t n) { if (!Value::isSafeInteger(n)) { - ctx.error("Branch labels must be integers no larger than " + std::to_string(Value::maxSafeInteger()) + "."); + parentContext.error("Branch labels must be integers no larger than " + std::to_string(Value::maxSafeInteger()) + ".", index); } else { type = {type::Number}; result = {static_cast<int64_t>(n)}; @@ -71,7 +72,7 @@ optional<InputType> parseInputValue(const Convertible& input, ParsingContext ctx }, [&] (int64_t n) { if (!Value::isSafeInteger(n)) { - ctx.error("Branch labels must be integers no larger than " + std::to_string(Value::maxSafeInteger()) + "."); + parentContext.error("Branch labels must be integers no larger than " + std::to_string(Value::maxSafeInteger()) + ".", index); } else { type = {type::Number}; result = {n}; @@ -79,9 +80,9 @@ optional<InputType> parseInputValue(const Convertible& input, ParsingContext ctx }, [&] (double n) { if (!Value::isSafeInteger(n)) { - ctx.error("Branch labels must be integers no larger than " + std::to_string(Value::maxSafeInteger()) + "."); + parentContext.error("Branch labels must be integers no larger than " + std::to_string(Value::maxSafeInteger()) + ".", index); } else if (n != std::floor(n)) { - ctx.error("Numeric branch labels must be integer values."); + parentContext.error("Numeric branch labels must be integer values.", index); } else { type = {type::Number}; result = {static_cast<int64_t>(n)}; @@ -92,11 +93,11 @@ optional<InputType> parseInputValue(const Convertible& input, ParsingContext ctx result = {s}; }, [&] (const auto&) { - ctx.error("Branch labels must be numbers or strings."); + parentContext.error("Branch labels must be numbers or strings.", index); } ); } else { - ctx.error("Branch labels must be numbers or strings."); + parentContext.error("Branch labels must be numbers or strings.", index); } if (!type) { @@ -105,8 +106,12 @@ optional<InputType> parseInputValue(const Convertible& input, ParsingContext ctx if (!inputType) { inputType = type; - } else if (ctx.checkType(*type)) { - return optional<InputType>(); + } else { + optional<std::string> err = type::checkSubtype(*inputType, *type); + if (err) { + parentContext.error(*err, index); + return optional<InputType>(); + } } return result; @@ -118,7 +123,7 @@ static ParseResult create(type::Type outputType, std::vector<std::pair<std::vector<InputType>, std::unique_ptr<Expression>>> branches, std::unique_ptr<Expression> otherwise, - ParsingContext ctx) { + ParsingContext& ctx) { typename Match<T>::Branches typedBranches; std::size_t index = 2; @@ -146,7 +151,7 @@ static ParseResult create(type::Type outputType, )); } -ParseResult parseMatch(const Convertible& value, ParsingContext ctx) { +ParseResult parseMatch(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); auto length = arrayLength(value); if (length < 5) { @@ -164,8 +169,8 @@ ParseResult parseMatch(const Convertible& value, ParsingContext ctx) { optional<type::Type> inputType; optional<type::Type> outputType; - if (ctx.expected && *ctx.expected != type::Value) { - outputType = ctx.expected; + if (ctx.getExpected() && *ctx.getExpected() != type::Value) { + outputType = ctx.getExpected(); } std::vector<std::pair<std::vector<InputType>, @@ -181,27 +186,27 @@ ParseResult parseMatch(const Convertible& value, ParsingContext ctx) { if (isArray(label)) { auto groupLength = arrayLength(label); if (groupLength == 0) { - ctx.concat(i).error("Expected at least one branch label."); + ctx.error("Expected at least one branch label.", i); return ParseResult(); } labels.reserve(groupLength); for (size_t j = 0; j < groupLength; j++) { - const optional<InputType> inputValue = parseInputValue(arrayMember(label, j), ctx.concat(i, inputType), inputType); + const optional<InputType> inputValue = parseInputValue(arrayMember(label, j), ctx, i, inputType); if (!inputValue) { return ParseResult(); } labels.push_back(*inputValue); } } else { - const optional<InputType> inputValue = parseInputValue(label, ctx.concat(i, inputType), inputType); + const optional<InputType> inputValue = parseInputValue(label, ctx, i, inputType); if (!inputValue) { return ParseResult(); } labels.push_back(*inputValue); } - ParseResult output = ctx.concat(i + 1, outputType).parse(arrayMember(value, i + 1)); + ParseResult output = ctx.parse(arrayMember(value, i + 1), i + 1, outputType); if (!output) { return ParseResult(); } @@ -213,12 +218,12 @@ ParseResult parseMatch(const Convertible& value, ParsingContext ctx) { branches.push_back(std::make_pair(std::move(labels), std::move(*output))); } - auto input = ctx.concat(1, inputType).parse(arrayMember(value, 1)); + auto input = ctx.parse(arrayMember(value, 1), 1, inputType); if (!input) { return ParseResult(); } - auto otherwise = ctx.concat(length - 1, outputType).parse(arrayMember(value, length - 1)); + auto otherwise = ctx.parse(arrayMember(value, length - 1), length - 1, outputType); if (!otherwise) { return ParseResult(); } diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index e2447bd7e4..2f855a1ad9 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -50,6 +50,25 @@ bool isConstant(const Expression* expression) { } using namespace mbgl::style::conversion; + +ParseResult ParsingContext::parse(const Convertible& value, std::size_t index_, optional<type::Type> expected_) { + ParsingContext child(key + "[" + std::to_string(index_) + "]", + errors, + std::move(expected_), + scope); + return child.parse(value); +} + +ParseResult ParsingContext::parse(const Convertible& value, std::size_t index_, optional<type::Type> expected_, + const std::map<std::string, std::shared_ptr<Expression>>& bindings) { + ParsingContext child(key + "[" + std::to_string(index_) + "]", + errors, + std::move(expected_), + std::make_shared<detail::Scope>(bindings, scope)); + return child.parse(value); +} + +using namespace mbgl::style::conversion; ParseResult ParsingContext::parse(const Convertible& value) { ParseResult parsed; @@ -117,7 +136,7 @@ ParseResult ParsingContext::parse(const Convertible& value) } if (!parsed) { - assert(errors.size() > 0); + assert(errors->size() > 0); } else if (expected) { auto wrapForType = [&](const type::Type& target, std::unique_ptr<Expression> expression) -> std::unique_ptr<Expression> { std::vector<std::unique_ptr<Expression>> args; @@ -137,7 +156,7 @@ ParseResult ParsingContext::parse(const Convertible& value) } checkType((*parsed)->getType()); - if (errors.size() > 0) { + if (errors->size() > 0) { return ParseResult(); } } |