#pragma once #include #include #include #include #include #include #include #include #include namespace mbgl { namespace style { namespace expression { /* CompoundExpression provides a mechanism for implementing an expression simply by providing a list of pure functions of the form (const T0& arg0, const T1& arg1, ...) -> Result where T0, T1, ..., U are member types of mbgl::style::expression::Value. The majority of expressions specified in the style-spec are implemented in this fashion (see compound_expression.cpp). */ /* Represents the parameter list for an expression that takes an arbitrary number of arguments (of a specific type). */ struct VarargsType { type::Type type; }; template struct Varargs : std::vector { using std::vector::vector; }; namespace detail { // Base class for the Signature structs that are used to determine // each CompoundExpression definition's type::Type data from the type of its // "evaluate" function. struct SignatureBase { SignatureBase(type::Type result_, variant, VarargsType> params_, std::string name_) : result(std::move(result_)), params(std::move(params_)), name(std::move(name_)) {} virtual ~SignatureBase() = default; virtual std::unique_ptr makeExpression(std::vector>) const = 0; type::Type result; variant, VarargsType> params; std::string name; }; } // namespace detail /* Common base class for CompoundExpression instances. Used to allow downcasting (and access to things like name & parameter list) during an Expression tree traversal. */ class CompoundExpressionBase : public Expression { public: CompoundExpressionBase(std::string name_, const detail::SignatureBase& signature) : Expression(signature.result), name(std::move(name_)), params(signature.params) {} std::string getName() const { return name; } optional getParameterCount() const { return params.match( [&](const VarargsType&) { return optional(); }, [&](const std::vector& p) -> optional { return p.size(); } ); } std::vector> possibleOutputs() const override { return { nullopt }; } private: std::string name; variant, VarargsType> params; }; template class CompoundExpression : public CompoundExpressionBase { public: using Args = typename Signature::Args; CompoundExpression(const std::string& name_, Signature signature_, typename Signature::Args args_) : CompoundExpressionBase(name_, signature_), signature(signature_), args(std::move(args_)) {} EvaluationResult evaluate(const EvaluationContext& evaluationParams) const override { return signature.apply(evaluationParams, args); } void eachChild(const std::function& visit) const override { for (const std::unique_ptr& e : args) { visit(*e); } } bool operator==(const Expression& e) const override { if (auto rhs = dynamic_cast(&e)) { return getName() == rhs->getName() && Expression::childrenEqual(args, rhs->args); } return false; } std::string getOperator() const override { return signature.name; } private: Signature signature; typename Signature::Args args; }; /* Holds the map of expression name => implementation (which is just one or more evaluation functions, each wrapped in a Signature struct). */ struct CompoundExpressionRegistry { using Definition = std::vector>; static std::unordered_map definitions; }; ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); ParseResult createCompoundExpression(const CompoundExpressionRegistry::Definition& definition, std::vector> args, ParsingContext& ctx); ParseResult createCompoundExpression(const std::string& name, std::vector> args, ParsingContext& ctx); // Convenience method for use expressions that have 0, 1, or 2 args. ParseResult createCompoundExpression(const std::string& name, ParsingContext& ctx); ParseResult createCompoundExpression(const std::string& name, std::unique_ptr arg1, ParsingContext& ctx); ParseResult createCompoundExpression(const std::string& name, std::unique_ptr arg1, std::unique_ptr arg2, ParsingContext& ctx); } // namespace expression } // namespace style } // namespace mbgl