#pragma once #include #include #include #include #include #include #include #include #include #include namespace mbgl { class GeometryTileFeature; namespace style { namespace expression { struct EvaluationError { std::string message; }; struct EvaluationParameters { float zoom; const GeometryTileFeature& feature; }; using EvaluationResult = variant; class Expression { public: Expression(std::string key_, type::Type type_) : key(key_), type(type_) {} virtual ~Expression() {} virtual EvaluationResult evaluate(const EvaluationParameters&) const = 0; // Exposed for use with pure Feature objects (e.g. beyond the context of tiled map data). EvaluationResult evaluate(float, const Feature&) const; type::Type getType() const { return type; } type::ValueType getResultType() const { return type.match( [&] (const type::Lambda& lambdaType) { return lambdaType.getResult(); }, [&] (const auto& t) -> type::ValueType { return t; } ); } bool isFeatureConstant() { return true; } bool isZoomConstant() { return true; } private: std::string key; type::Type type; }; struct CompileError { std::string message; std::string key; }; using ParseResult = variant>; template ParseResult parseExpression(const V& value, const ParsingContext& context); using namespace mbgl::style::conversion; class LiteralExpression : public Expression { public: LiteralExpression(std::string key, type::Type type, Value value_) : Expression(key, type), value(value_) {} EvaluationResult evaluate(const EvaluationParameters&) const override { return value; } template static ParseResult parse(const V& value, const ParsingContext& ctx) { const Value& parsedValue = parseValue(value); const type::Type& type = typeOf(parsedValue); return std::make_unique(ctx.key(), type, parsedValue); } private: template static Value parseValue(const V& value) { if (isUndefined(value)) return Null; if (isObject(value)) { std::unordered_map result; eachMember(value, [&] (const std::string& k, const V& v) -> optional { result.emplace(k, parseValue(v)); return {}; }); return result; } if (isArray(value)) { std::vector result; const auto length = arrayLength(value); for(std::size_t i = 0; i < length; i++) { result.emplace_back(parseValue(arrayMember(value, i))); } return result; } optional v = toValue(value); assert(v); return v->match( [&] (const std::string& s) -> Value { return s; }, [&] (bool b) -> Value { return b; }, [&] (auto f) -> Value { return *numericValue(f); } ); } Value value; }; class LambdaExpression : public Expression { public: using Args = std::vector>; LambdaExpression(std::string key, std::string name_, Args args_, type::Lambda type) : Expression(key, type), args(std::move(args_)), name(name_) {} template static ParseResult parse(const V& value, const ParsingContext& ctx) { assert(isArray(value)); auto length = arrayLength(value); Args args; for(size_t i = 1; i < length; i++) { const auto& arg = arrayMember(value, i); auto parsedArg = parseExpression(arg, ParsingContext(ctx, i, {})); if (parsedArg.template is>()) { args.push_back(std::move(parsedArg.template get>())); } else { return parsedArg.template get(); } } return std::make_unique(ctx.key(), std::move(args)); } protected: Args args; private: std::string name; }; template EvaluationResult evaluateBinaryOperator(const EvaluationParameters& params, const LambdaExpression::Args& args, optional initial, Rfunc reduce) { optional memo = initial; for(const auto& arg : args) { auto argValue = arg->evaluate(params); if (argValue.is()) { return argValue.get(); } T value = argValue.get().get(); if (!memo) memo = {value}; else memo = reduce(*memo, value); } return {*memo}; } class PlusExpression : public LambdaExpression { public: PlusExpression(std::string key, Args args) : LambdaExpression(key, "+", std::move(args), {type::Primitive::Number, {type::NArgs({type::Primitive::Number})}}) {} EvaluationResult evaluate(const EvaluationParameters& params) const override { return evaluateBinaryOperator(params, args, {}, [](float memo, float next) { return memo + next; }); } }; class TimesExpression : public LambdaExpression { public: TimesExpression(std::string key, Args args) : LambdaExpression(key, "*", std::move(args), {type::Primitive::Number, {type::NArgs({type::Primitive::Number})}}) {} EvaluationResult evaluate(const EvaluationParameters& params) const override { return evaluateBinaryOperator(params, args, {}, [](float memo, float next) { return memo * next; }); } }; class MinusExpression : public LambdaExpression { public: MinusExpression(std::string key, Args args) : LambdaExpression(key, "-", std::move(args), {type::Primitive::Number, {type::Primitive::Number, type::Primitive::Number}}) {} EvaluationResult evaluate(const EvaluationParameters& params) const override { return evaluateBinaryOperator(params, args, {}, [](float memo, float next) { return memo - next; }); } }; class DivideExpression : public LambdaExpression { public: DivideExpression(std::string key, Args args) : LambdaExpression(key, "/", std::move(args), {type::Primitive::Number, {type::Primitive::Number, type::Primitive::Number}}) {} EvaluationResult evaluate(const EvaluationParameters& params) const override { return evaluateBinaryOperator(params, args, {}, [](float memo, float next) { return memo / next; }); } }; } // namespace expression } // namespace style } // namespace mbgl