summaryrefslogtreecommitdiff
path: root/include/mbgl/style/expression/compound_expression.hpp
blob: 6baaae862f547e9fb436bbaf850c07c1e6b08412 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#pragma once

#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/expression/type.hpp>
#include <mbgl/style/expression/value.hpp>

#include <mbgl/util/optional.hpp>
#include <mbgl/util/variant.hpp>

#include <memory>
#include <vector>

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<U> 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 <typename T>
struct Varargs : std::vector<T> { using std::vector<T>::vector; };

namespace detail {
// Base class for the Signature<Fn> structs that are used to determine the
// each CompoundExpression definition's type::Type data from the type of its
// "evaluate" function.
struct SignatureBase {
    SignatureBase(type::Type result_, variant<std::vector<type::Type>, VarargsType> params_, std::string name_) :
        result(std::move(result_)),
        params(std::move(params_)),
        name(std::move(name_))
    {}
    virtual ~SignatureBase() = default;
    virtual std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>>) const = 0;
    type::Type result;
    variant<std::vector<type::Type>, VarargsType> params;
    std::string name;
};
} // namespace detail


/*
    Common base class for CompoundExpression<Signature> 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<std::size_t> getParameterCount() const {
        return params.match(
            [&](const VarargsType&) { return optional<std::size_t>(); },
            [&](const std::vector<type::Type>& p) -> optional<std::size_t> { return p.size(); }
        );
    }

    std::vector<optional<Value>> possibleOutputs() const override {
        return { nullopt };
    }

private:
    std::string name;
    variant<std::vector<type::Type>, VarargsType> params;
};

template <typename Signature>
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<void(const Expression&)>& visit) const override {
        for (const std::unique_ptr<Expression>& e : args) {
            visit(*e);
        }
    }

    bool operator==(const Expression& e) const override {
        if (auto rhs = dynamic_cast<const CompoundExpression*>(&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<std::unique_ptr<detail::SignatureBase>>;
    static std::unordered_map<std::string, Definition> definitions;
};

ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);

ParseResult createCompoundExpression(const CompoundExpressionRegistry::Definition& definition,
                                     std::vector<std::unique_ptr<Expression>> args,
                                     ParsingContext& ctx);
    
ParseResult createCompoundExpression(const std::string& name,
                                     std::vector<std::unique_ptr<Expression>> args,
                                     ParsingContext& ctx);

} // namespace expression
} // namespace style
} // namespace mbgl