#include #include #include #include namespace mbgl { namespace style { namespace expression { EvaluationResult Let::evaluate(const EvaluationContext& params) const { return result->evaluate(params); } void Let::eachChild(const std::function& visit) const { for (const auto& binding : bindings) { visit(*binding.second); } visit(*result); } std::vector> Let::possibleOutputs() const { return result->possibleOutputs(); } using namespace mbgl::style::conversion; ParseResult Let::parse(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); std::size_t length = arrayLength(value); if (length < 4) { ctx.error("Expected at least 3 arguments, but found " + util::toString(length - 1) + " instead."); return ParseResult(); } std::map> bindings_; for(std::size_t i = 1; i < length - 1; i += 2) { optional name = toString(arrayMember(value, i)); if (!name) { ctx.error("Expected string, but found " + getJSONType(arrayMember(value, i)) + " instead.", i); return ParseResult(); } bool isValidName = std::all_of(name->begin(), name->end(), [](unsigned char c) { return ::isalnum(c) || c == '_'; }); if (!isValidName) { ctx.error("Variable names must contain only alphanumeric characters or '_'.", 1); return ParseResult(); } ParseResult bindingValue = ctx.parse(arrayMember(value, i + 1), i + 1); if (!bindingValue) { return ParseResult(); } bindings_.emplace(*name, std::move(*bindingValue)); } ParseResult result_ = ctx.parse(arrayMember(value, length - 1), length - 1, ctx.getExpected(), bindings_); if (!result_) { return ParseResult(); } return ParseResult(std::make_unique(std::move(bindings_), std::move(*result_))); } mbgl::Value Let::serialize() const { std::vector serialized; serialized.emplace_back(getOperator()); for (auto entry : bindings) { serialized.emplace_back(entry.first); serialized.emplace_back(entry.second->serialize()); } serialized.emplace_back(result->serialize()); return serialized; } EvaluationResult Var::evaluate(const EvaluationContext& params) const { return value->evaluate(params); } void Var::eachChild(const std::function&) const {} std::vector> Var::possibleOutputs() const { return { nullopt }; } ParseResult Var::parse(const Convertible& value_, ParsingContext& ctx) { assert(isArray(value_)); if (arrayLength(value_) != 2 || !toString(arrayMember(value_, 1))) { ctx.error("'var' expression requires exactly one string literal argument."); return ParseResult(); } std::string name_ = *toString(arrayMember(value_, 1)); optional> bindingValue = ctx.getBinding(name_); if (!bindingValue) { ctx.error(R"(Unknown variable ")" + name_ + R"(". Make sure ")" + name_ + R"(" has been bound in an enclosing "let" expression before using it.)", 1); return ParseResult(); } return ParseResult(std::make_unique(name_, std::move(*bindingValue))); } mbgl::Value Var::serialize() const { return std::vector{{ getOperator(), name }}; } } // namespace expression } // namespace style } // namespace mbgl