1 #pragma once 2 3 #include <mbgl/util/optional.hpp> 4 #include <mbgl/util/variant.hpp> 5 #include <mbgl/util/color.hpp> 6 #include <mbgl/style/expression/type.hpp> 7 #include <mbgl/style/expression/value.hpp> 8 #include <mbgl/style/expression/parsing_context.hpp> 9 10 #include <array> 11 #include <vector> 12 #include <memory> 13 14 namespace mbgl { 15 16 class GeometryTileFeature; 17 18 namespace style { 19 namespace expression { 20 21 class EvaluationError { 22 public: 23 std::string message; 24 }; 25 26 class EvaluationContext { 27 public: EvaluationContext(float zoom_)28 EvaluationContext(float zoom_) : zoom(zoom_), feature(nullptr) {} EvaluationContext(GeometryTileFeature const * feature_)29 EvaluationContext(GeometryTileFeature const * feature_) : zoom(optional<float>()), feature(feature_) {} EvaluationContext(float zoom_,GeometryTileFeature const * feature_)30 EvaluationContext(float zoom_, GeometryTileFeature const * feature_) : 31 zoom(zoom_), feature(feature_) 32 {} EvaluationContext(optional<float> zoom_,GeometryTileFeature const * feature_,optional<double> heatmapDensity_)33 EvaluationContext(optional<float> zoom_, GeometryTileFeature const * feature_, optional<double> heatmapDensity_) : 34 zoom(std::move(zoom_)), feature(feature_), heatmapDensity(std::move(heatmapDensity_)) 35 {} 36 37 optional<float> zoom; 38 GeometryTileFeature const * feature; 39 optional<double> heatmapDensity; 40 }; 41 42 template <typename T> 43 class Result : private variant<EvaluationError, T> { 44 public: 45 using variant<EvaluationError, T>::variant; 46 using Value = T; 47 48 Result() = default; 49 operator bool() const50 explicit operator bool () const { 51 return this->template is<T>(); 52 } 53 54 // optional does some type trait magic for this one, so this might 55 // be problematic as is. operator ->() const56 const T* operator->() const { 57 assert(this->template is<T>()); 58 return std::addressof(this->template get<T>()); 59 } 60 operator ->()61 T* operator->() { 62 assert(this->template is<T>()); 63 return std::addressof(this->template get<T>()); 64 } 65 operator *()66 T& operator*() { 67 assert(this->template is<T>()); 68 return this->template get<T>(); 69 } 70 operator *() const71 const T& operator*() const { 72 assert(this->template is<T>()); 73 return this->template get<T>(); 74 } 75 error() const76 const EvaluationError& error() const { 77 assert(this->template is<EvaluationError>()); 78 return this->template get<EvaluationError>(); 79 } 80 }; 81 82 class EvaluationResult : public Result<Value> { 83 public: 84 using Result::Result; // NOLINT 85 86 EvaluationResult() = default; 87 EvaluationResult(const std::array<double,4> & arr)88 EvaluationResult(const std::array<double, 4>& arr) : 89 Result(toExpressionValue(arr)) 90 {} 91 92 // used only for the special (private) "error" expression EvaluationResult(const type::ErrorType &)93 EvaluationResult(const type::ErrorType&) { 94 assert(false); 95 } 96 }; 97 98 /* 99 Expression is an abstract class that serves as an interface and base class 100 for particular expression implementations. 101 102 CompoundExpression implements the majority of expressions in the spec by 103 inferring the argument and output from a simple function (const T0& arg0, 104 const T1& arg1, ...) -> Result<U> where T0, T1, ..., U are member types of 105 mbgl::style::expression::Value. 106 107 The other Expression subclasses (Let, Curve, Match, etc.) exist in order to 108 implement expressions that need specialized parsing, type checking, or 109 evaluation logic that can't be handled by CompoundExpression's inference 110 mechanism. 111 112 Each Expression subclass also provides a static 113 ParseResult ExpressionClass::parse(const V&, ParsingContext), 114 which handles parsing a style-spec JSON representation of the expression. 115 */ 116 117 enum class Kind : int32_t { 118 Coalesce, 119 CompoundExpression, 120 Literal, 121 ArrayAssertion, 122 At, 123 Interpolate, 124 Assertion, 125 Length, 126 Step, 127 Let, 128 Var, 129 CollatorExpression, 130 Coercion, 131 Match, 132 Error, 133 Case, 134 Any, 135 All, 136 Equals, 137 }; 138 139 class Expression { 140 public: Expression(Kind kind_,type::Type type_)141 Expression(Kind kind_, type::Type type_) : kind(kind_), type(std::move(type_)) {} 142 virtual ~Expression() = default; 143 144 virtual EvaluationResult evaluate(const EvaluationContext& params) const = 0; 145 virtual void eachChild(const std::function<void(const Expression&)>&) const = 0; 146 virtual bool operator==(const Expression&) const = 0; operator !=(const Expression & rhs) const147 bool operator!=(const Expression& rhs) const { 148 return !operator==(rhs); 149 } 150 getKind() const151 Kind getKind() const { return kind; }; getType() const152 type::Type getType() const { return type; }; 153 154 EvaluationResult evaluate(optional<float> zoom, const Feature& feature, optional<double> heatmapDensity) const; 155 156 /** 157 * Statically analyze the expression, attempting to enumerate possible outputs. Returns 158 * an array of values plus the sentinel null optional value, used to indicate that the 159 * complete set of outputs is statically undecidable. 160 */ 161 virtual std::vector<optional<Value>> possibleOutputs() const = 0; 162 serialize() const163 virtual mbgl::Value serialize() const { 164 std::vector<mbgl::Value> serialized; 165 serialized.emplace_back(getOperator()); 166 eachChild([&](const Expression &child) { 167 serialized.emplace_back(child.serialize()); 168 }); 169 return serialized; 170 }; 171 172 virtual std::string getOperator() const = 0; 173 174 protected: 175 template <typename T> childrenEqual(const T & lhs,const T & rhs)176 static bool childrenEqual(const T& lhs, const T& rhs) { 177 if (lhs.size() != rhs.size()) return false; 178 for (auto leftChild = lhs.begin(), rightChild = rhs.begin(); 179 leftChild != lhs.end(); 180 leftChild++, rightChild++) 181 { 182 if (!Expression::childEqual(*leftChild, *rightChild)) return false; 183 } 184 return true; 185 } 186 childEqual(const std::unique_ptr<Expression> & lhs,const std::unique_ptr<Expression> & rhs)187 static bool childEqual(const std::unique_ptr<Expression>& lhs, const std::unique_ptr<Expression>& rhs) { 188 return *lhs == *rhs; 189 } 190 191 template <typename T> childEqual(const std::pair<T,std::unique_ptr<Expression>> & lhs,const std::pair<T,std::unique_ptr<Expression>> & rhs)192 static bool childEqual(const std::pair<T, std::unique_ptr<Expression>>& lhs, 193 const std::pair<T, std::unique_ptr<Expression>>& rhs) { 194 return lhs.first == rhs.first && *(lhs.second) == *(rhs.second); 195 } 196 197 template <typename T> childEqual(const std::pair<T,std::shared_ptr<Expression>> & lhs,const std::pair<T,std::shared_ptr<Expression>> & rhs)198 static bool childEqual(const std::pair<T, std::shared_ptr<Expression>>& lhs, 199 const std::pair<T, std::shared_ptr<Expression>>& rhs) { 200 return lhs.first == rhs.first && *(lhs.second) == *(rhs.second); 201 } 202 childEqual(const std::pair<std::unique_ptr<Expression>,std::unique_ptr<Expression>> & lhs,const std::pair<std::unique_ptr<Expression>,std::unique_ptr<Expression>> & rhs)203 static bool childEqual(const std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>& lhs, 204 const std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>& rhs) { 205 return *(lhs.first) == *(rhs.first) && *(lhs.second) == *(rhs.second); 206 } 207 208 private: 209 Kind kind; 210 type::Type type; 211 }; 212 213 } // namespace expression 214 } // namespace style 215 } // namespace mbgl 216