1 #pragma once
2 
3 #include <mbgl/style/expression/expression.hpp>
4 #include <mbgl/style/conversion.hpp>
5 #include <mbgl/style/expression/parsing_context.hpp>
6 #include <mbgl/style/expression/type.hpp>
7 #include <mbgl/style/expression/value.hpp>
8 
9 #include <mbgl/util/optional.hpp>
10 #include <mbgl/util/variant.hpp>
11 
12 #include <memory>
13 #include <vector>
14 
15 namespace mbgl {
16 namespace style {
17 namespace expression {
18 
19 /*
20     CompoundExpression provides a mechanism for implementing an expression
21     simply by providing a list of pure functions of the form
22     (const T0& arg0, const T1& arg1, ...) -> Result<U> where T0, T1, ..., U are
23     member types of mbgl::style::expression::Value.
24 
25     The majority of expressions specified in the style-spec are implemented in
26     this fashion (see compound_expression.cpp).
27 */
28 
29 
30 /*
31     Represents the parameter list for an expression that takes an arbitrary
32     number of arguments (of a specific type).
33 */
34 struct VarargsType { type::Type type; };
35 template <typename T>
36 struct Varargs : std::vector<T> {
37     template <class... Args>
Varargsmbgl::style::expression::Varargs38     Varargs(Args&&... args) : std::vector<T>(std::forward<Args>(args)...) {}
39 };
40 
41 namespace detail {
42 // Base class for the Signature<Fn> structs that are used to determine
43 // each CompoundExpression definition's type::Type data from the type of its
44 // "evaluate" function.
45 struct SignatureBase {
SignatureBasembgl::style::expression::detail::SignatureBase46     SignatureBase(type::Type result_, variant<std::vector<type::Type>, VarargsType> params_, std::string name_) :
47         result(std::move(result_)),
48         params(std::move(params_)),
49         name(std::move(name_))
50     {}
51     virtual ~SignatureBase() = default;
52     virtual std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>>) const = 0;
53     type::Type result;
54     variant<std::vector<type::Type>, VarargsType> params;
55     std::string name;
56 };
57 } // namespace detail
58 
59 
60 /*
61     Common base class for CompoundExpression<Signature> instances.  Used to
62     allow downcasting (and access to things like name & parameter list) during
63     an Expression tree traversal.
64 */
65 class CompoundExpressionBase : public Expression {
66 public:
CompoundExpressionBase(std::string name_,const detail::SignatureBase & signature)67     CompoundExpressionBase(std::string name_, const detail::SignatureBase& signature) :
68         Expression(Kind::CompoundExpression, signature.result),
69         name(std::move(name_)),
70         params(signature.params)
71     {}
72 
getName() const73     std::string getName() const { return name; }
getParameterCount() const74     optional<std::size_t> getParameterCount() const {
75         return params.match(
76             [&](const VarargsType&) { return optional<std::size_t>(); },
77             [&](const std::vector<type::Type>& p) -> optional<std::size_t> { return p.size(); }
78         );
79     }
80 
possibleOutputs() const81     std::vector<optional<Value>> possibleOutputs() const override {
82         return { nullopt };
83     }
84 
85 private:
86     std::string name;
87     variant<std::vector<type::Type>, VarargsType> params;
88 };
89 
90 template <typename Signature>
91 class CompoundExpression : public CompoundExpressionBase {
92 public:
93     using Args = typename Signature::Args;
94 
CompoundExpression(const std::string & name_,Signature signature_,typename Signature::Args args_)95     CompoundExpression(const std::string& name_,
96                        Signature signature_,
97                        typename Signature::Args args_) :
98         CompoundExpressionBase(name_, signature_),
99         signature(signature_),
100         args(std::move(args_))
101     {}
102 
evaluate(const EvaluationContext & evaluationParams) const103     EvaluationResult evaluate(const EvaluationContext& evaluationParams) const override {
104         return signature.apply(evaluationParams, args);
105     }
106 
eachChild(const std::function<void (const Expression &)> & visit) const107     void eachChild(const std::function<void(const Expression&)>& visit) const override {
108         for (const std::unique_ptr<Expression>& e : args) {
109             visit(*e);
110         }
111     }
112 
operator ==(const Expression & e) const113     bool operator==(const Expression& e) const override {
114         if (e.getKind() == Kind::CompoundExpression) {
115             auto rhs = static_cast<const CompoundExpression*>(&e);
116             return getName() == rhs->getName() && Expression::childrenEqual(args, rhs->args);
117         }
118         return false;
119     }
120 
getOperator() const121     std::string getOperator() const override {
122         return signature.name;
123     }
124 
125 private:
126     Signature signature;
127     typename Signature::Args args;
128 };
129 
130 /*
131     Holds the map of expression name => implementation (which is just one or
132     more evaluation functions, each wrapped in a Signature struct).
133 */
134 struct CompoundExpressionRegistry {
135     using Definition = std::vector<std::unique_ptr<detail::SignatureBase>>;
136     static std::unordered_map<std::string, Definition> definitions;
137 };
138 
139 ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
140 
141 ParseResult createCompoundExpression(const std::string& name,
142                                      std::vector<std::unique_ptr<Expression>> args,
143                                      ParsingContext& ctx);
144 
145 } // namespace expression
146 } // namespace style
147 } // namespace mbgl
148