summaryrefslogtreecommitdiff
path: root/src/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl')
-rw-r--r--src/mbgl/style/conversion/function.cpp699
-rw-r--r--src/mbgl/style/expression/dsl.cpp9
-rw-r--r--src/mbgl/style/function/categorical_stops.cpp41
-rw-r--r--src/mbgl/style/function/convert.cpp40
-rw-r--r--src/mbgl/style/function/identity_stops.cpp89
5 files changed, 708 insertions, 170 deletions
diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp
new file mode 100644
index 0000000000..64adf522a1
--- /dev/null
+++ b/src/mbgl/style/conversion/function.cpp
@@ -0,0 +1,699 @@
+#include <mbgl/style/conversion/function.hpp>
+#include <mbgl/style/expression/dsl.hpp>
+#include <mbgl/style/expression/step.hpp>
+#include <mbgl/style/expression/interpolate.hpp>
+#include <mbgl/style/expression/match.hpp>
+#include <mbgl/style/expression/case.hpp>
+#include <mbgl/style/expression/array_assertion.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+using namespace expression;
+using namespace expression::dsl;
+
+// Ad-hoc Converters for double and int64_t. We should replace float with double wholesale,
+// and promote the int64_t Converter to general use (and it should check that the input is
+// an integer).
+template <>
+struct Converter<double> {
+ optional<double> operator()(const Convertible& value, Error& error) const {
+ auto converted = convert<float>(value, error);
+ if (!converted) {
+ return {};
+ }
+ return *converted;
+ }
+};
+
+template <>
+struct Converter<int64_t> {
+ optional<int64_t> operator()(const Convertible& value, Error& error) const {
+ auto converted = convert<float>(value, error);
+ if (!converted) {
+ return {};
+ }
+ return *converted;
+ }
+};
+
+enum class FunctionType {
+ Interval,
+ Exponential,
+ Categorical,
+ Identity,
+ Invalid
+};
+
+static bool interpolatable(type::Type type) {
+ return type.match(
+ [&] (const type::NumberType&) {
+ return true;
+ },
+ [&] (const type::ColorType&) {
+ return true;
+ },
+ [&] (const type::Array& array) {
+ return array.N && array.itemType == type::Number;
+ },
+ [&] (const auto&) {
+ return false;
+ }
+ );
+}
+
+static FunctionType functionType(type::Type type, const Convertible& value) {
+ auto typeValue = objectMember(value, "type");
+ if (!typeValue) {
+ return interpolatable(type) ? FunctionType::Exponential : FunctionType::Interval;
+ }
+
+ optional<std::string> string = toString(*typeValue);
+ if (!string) {
+ return FunctionType::Invalid;
+ }
+
+ if (*string == "interval")
+ return FunctionType::Interval;
+ if (*string == "exponential" && interpolatable(type))
+ return FunctionType::Exponential;
+ if (*string == "categorical")
+ return FunctionType::Categorical;
+ if (*string == "identity")
+ return FunctionType::Identity;
+
+ return FunctionType::Invalid;
+}
+
+static optional<std::unique_ptr<Expression>> convertLiteral(type::Type type, const Convertible& value, Error& error) {
+ return type.match(
+ [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> {
+ auto result = convert<float>(value, error);
+ if (!result) {
+ return {};
+ }
+ return literal(double(*result));
+ },
+ [&] (const type::BooleanType&) -> optional<std::unique_ptr<Expression>> {
+ auto result = convert<bool>(value, error);
+ if (!result) {
+ return {};
+ }
+ return literal(*result);
+ },
+ [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> {
+ auto result = convert<std::string>(value, error);
+ if (!result) {
+ return {};
+ }
+ return literal(*result);
+ },
+ [&] (const type::ColorType&) -> optional<std::unique_ptr<Expression>> {
+ auto result = convert<Color>(value, error);
+ if (!result) {
+ return {};
+ }
+ return literal(*result);
+ },
+ [&] (const type::Array& array) -> optional<std::unique_ptr<Expression>> {
+ if (!isArray(value)) {
+ error = { "value must be an array" };
+ return {};
+ }
+ if (array.N && arrayLength(value) != *array.N) {
+ error = { "value must be an array of length " + util::toString(*array.N) };
+ return {};
+ }
+ return array.itemType.match(
+ [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> {
+ std::vector<expression::Value> result;
+ result.reserve(arrayLength(value));
+ for (std::size_t i = 0; i < arrayLength(value); ++i) {
+ optional<float> number = toNumber(arrayMember(value, i));
+ if (!number) {
+ error = { "value must be an array of numbers" };
+ return {};
+ }
+ result.push_back(double(*number));
+ }
+ return literal(result);
+ },
+ [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> {
+ std::vector<expression::Value> result;
+ result.reserve(arrayLength(value));
+ for (std::size_t i = 0; i < arrayLength(value); ++i) {
+ optional<std::string> string = toString(arrayMember(value, i));
+ if (!string) {
+ error = { "value must be an array of strings" };
+ return {};
+ }
+ result.push_back(*string);
+ }
+ return literal(result);
+ },
+ [&] (const auto&) -> optional<std::unique_ptr<Expression>> {
+ assert(false); // No properties use this type.
+ return {};
+ }
+ );
+ },
+ [&] (const type::NullType&) -> optional<std::unique_ptr<Expression>> {
+ assert(false); // No properties use this type.
+ return {};
+ },
+ [&] (const type::ObjectType&) -> optional<std::unique_ptr<Expression>> {
+ assert(false); // No properties use this type.
+ return {};
+ },
+ [&] (const type::ErrorType&) -> optional<std::unique_ptr<Expression>> {
+ assert(false); // No properties use this type.
+ return {};
+ },
+ [&] (const type::ValueType&) -> optional<std::unique_ptr<Expression>> {
+ assert(false); // No properties use this type.
+ return {};
+ },
+ [&] (const type::CollatorType&) -> optional<std::unique_ptr<Expression>> {
+ assert(false); // No properties use this type.
+ return {};
+ }
+ );
+}
+
+static optional<std::map<double, std::unique_ptr<Expression>>> convertStops(type::Type type,
+ const Convertible& value,
+ Error& error) {
+ auto stopsValue = objectMember(value, "stops");
+ if (!stopsValue) {
+ error = { "function value must specify stops" };
+ return {};
+ }
+
+ if (!isArray(*stopsValue)) {
+ error = { "function stops must be an array" };
+ return {};
+ }
+
+ if (arrayLength(*stopsValue) == 0) {
+ error = { "function must have at least one stop" };
+ return {};
+ }
+
+ std::map<double, std::unique_ptr<Expression>> stops;
+ for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
+ const auto& stopValue = arrayMember(*stopsValue, i);
+
+ if (!isArray(stopValue)) {
+ error = { "function stop must be an array" };
+ return {};
+ }
+
+ if (arrayLength(stopValue) != 2) {
+ error = { "function stop must have two elements" };
+ return {};
+ }
+
+ optional<float> t = convert<float>(arrayMember(stopValue, 0), error);
+ if (!t) {
+ return {};
+ }
+
+ optional<std::unique_ptr<Expression>> e = convertLiteral(type, arrayMember(stopValue, 1), error);
+ if (!e) {
+ return {};
+ }
+
+ stops.emplace(*t, std::move(*e));
+ }
+
+ return { std::move(stops) };
+}
+
+template <class T>
+optional<std::map<T, std::unique_ptr<Expression>>> convertBranches(type::Type type,
+ const Convertible& value,
+ Error& error) {
+ auto stopsValue = objectMember(value, "stops");
+ if (!stopsValue) {
+ error = { "function value must specify stops" };
+ return {};
+ }
+
+ if (!isArray(*stopsValue)) {
+ error = { "function stops must be an array" };
+ return {};
+ }
+
+ if (arrayLength(*stopsValue) == 0) {
+ error = { "function must have at least one stop" };
+ return {};
+ }
+
+ std::map<T, std::unique_ptr<Expression>> stops;
+ for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
+ const auto& stopValue = arrayMember(*stopsValue, i);
+
+ if (!isArray(stopValue)) {
+ error = { "function stop must be an array" };
+ return {};
+ }
+
+ if (arrayLength(stopValue) != 2) {
+ error = { "function stop must have two elements" };
+ return {};
+ }
+
+ optional<T> t = convert<T>(arrayMember(stopValue, 0), error);
+ if (!t) {
+ return {};
+ }
+
+ optional<std::unique_ptr<Expression>> e = convertLiteral(type, arrayMember(stopValue, 1), error);
+ if (!e) {
+ return {};
+ }
+
+ stops.emplace(*t, std::move(*e));
+ }
+
+ return { std::move(stops) };
+}
+
+static optional<double> convertBase(const Convertible& value, Error& error) {
+ auto baseValue = objectMember(value, "base");
+
+ if (!baseValue) {
+ return 1.0;
+ }
+
+ auto base = toNumber(*baseValue);
+ if (!base) {
+ error = { "function base must be a number" };
+ return {};
+ }
+
+ return *base;
+}
+
+static std::unique_ptr<Expression> step(type::Type type, std::unique_ptr<Expression> input, std::map<double, std::unique_ptr<Expression>> stops) {
+ return std::make_unique<Step>(type, std::move(input), std::move(stops));
+}
+
+static std::unique_ptr<Expression> interpolate(type::Type type, Interpolator interpolator, std::unique_ptr<Expression> input, std::map<double, std::unique_ptr<Expression>> stops) {
+ ParsingContext ctx;
+ auto result = createInterpolate(type, std::move(interpolator), std::move(input), std::move(stops), ctx);
+ if (!result) {
+ assert(false);
+ return {};
+ }
+ return std::move(*result);
+}
+
+template <class T>
+std::unique_ptr<Expression> categorical(type::Type type, const std::string& property, std::map<T, std::unique_ptr<Expression>> branches) {
+ std::unordered_map<T, std::shared_ptr<Expression>> convertedBranches;
+ for (auto& b : branches) {
+ convertedBranches[b.first] = std::move(b.second);
+ }
+ return std::make_unique<Match<T>>(type, get(literal(property)), std::move(convertedBranches), error("replaced with default"));
+}
+
+template <>
+std::unique_ptr<Expression> categorical<bool>(type::Type type, const std::string& property, std::map<bool, std::unique_ptr<Expression>> branches) {
+ auto it = branches.find(true);
+ std::unique_ptr<Expression> trueCase = it == branches.end() ?
+ error("replaced with default") :
+ std::move(it->second);
+
+ it = branches.find(false);
+ std::unique_ptr<Expression> falseCase = it == branches.end() ?
+ error("replaced with default") :
+ std::move(it->second);
+
+ std::vector<typename Case::Branch> trueBranch;
+ trueBranch.emplace_back(get(literal(property)), std::move(trueCase));
+
+ return std::make_unique<Case>(type, std::move(trueBranch), std::move(falseCase));
+}
+
+static optional<std::unique_ptr<Expression>> convertIntervalFunction(type::Type type,
+ const Convertible& value,
+ Error& error,
+ std::unique_ptr<Expression> input) {
+ auto stops = convertStops(type, value, error);
+ if (!stops) {
+ return {};
+ }
+ return step(type, std::move(input), std::move(*stops));
+}
+
+static optional<std::unique_ptr<Expression>> convertExponentialFunction(type::Type type,
+ const Convertible& value,
+ Error& error,
+ std::unique_ptr<Expression> input) {
+ auto stops = convertStops(type, value, error);
+ if (!stops) {
+ return {};
+ }
+ auto base = convertBase(value, error);
+ if (!base) {
+ return {};
+ }
+ return interpolate(type, exponential(*base), std::move(input), std::move(*stops));
+}
+
+static optional<std::unique_ptr<Expression>> convertCategoricalFunction(type::Type type,
+ const Convertible& value,
+ Error& err,
+ const std::string& property) {
+ auto stopsValue = objectMember(value, "stops");
+ if (!stopsValue) {
+ err = { "function value must specify stops" };
+ return {};
+ }
+
+ if (!isArray(*stopsValue)) {
+ err = { "function stops must be an array" };
+ return {};
+ }
+
+ if (arrayLength(*stopsValue) == 0) {
+ err = { "function must have at least one stop" };
+ return {};
+ }
+
+ const auto& first = arrayMember(*stopsValue, 0);
+
+ if (!isArray(first)) {
+ err = { "function stop must be an array" };
+ return {};
+ }
+
+ if (arrayLength(first) != 2) {
+ err = { "function stop must have two elements" };
+ return {};
+ }
+
+ if (toBool(arrayMember(first, 0))) {
+ auto branches = convertBranches<bool>(type, value, err);
+ if (!branches) {
+ return {};
+ }
+ return categorical(type, property, std::move(*branches));
+ }
+
+ if (toNumber(arrayMember(first, 0))) {
+ auto branches = convertBranches<int64_t>(type, value, err);
+ if (!branches) {
+ return {};
+ }
+ return categorical(type, property, std::move(*branches));
+ }
+
+ if (toString(arrayMember(first, 0))) {
+ auto branches = convertBranches<std::string>(type, value, err);
+ if (!branches) {
+ return {};
+ }
+ return categorical(type, property, std::move(*branches));
+ }
+
+ err = { "stop domain value must be a number, string, or boolean" };
+ return {};
+}
+
+optional<std::unique_ptr<Expression>> convertCameraFunctionToExpression(type::Type type,
+ const Convertible& value,
+ Error& error) {
+ if (!isObject(value)) {
+ error = { "function must be an object" };
+ return {};
+ }
+
+ switch (functionType(type, value)) {
+ case FunctionType::Interval:
+ return convertIntervalFunction(type, value, error, zoom());
+ case FunctionType::Exponential:
+ return convertExponentialFunction(type, value, error, zoom());
+ default:
+ error = { "unsupported function type" };
+ return {};
+ }
+}
+
+optional<std::unique_ptr<Expression>> convertSourceFunctionToExpression(type::Type type,
+ const Convertible& value,
+ Error& error) {
+ if (!isObject(value)) {
+ error = { "function must be an object" };
+ return {};
+ }
+
+ auto propertyValue = objectMember(value, "property");
+ if (!propertyValue) {
+ error = { "function must specify property" };
+ return {};
+ }
+
+ auto property = toString(*propertyValue);
+ if (!property) {
+ error = { "function property must be a string" };
+ return {};
+ }
+
+ switch (functionType(type, value)) {
+ case FunctionType::Interval:
+ return convertIntervalFunction(type, value, error, number(get(literal(*property))));
+ case FunctionType::Exponential:
+ return convertExponentialFunction(type, value, error, number(get(literal(*property))));
+ case FunctionType::Categorical:
+ return convertCategoricalFunction(type, value, error, *property);
+ case FunctionType::Identity:
+ return type.match(
+ [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> {
+ return string(get(literal(*property)));
+ },
+ [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> {
+ return number(get(literal(*property)));
+ },
+ [&] (const type::BooleanType&) -> optional<std::unique_ptr<Expression>> {
+ return boolean(get(literal(*property)));
+ },
+ [&] (const type::ColorType&) -> optional<std::unique_ptr<Expression>> {
+ return toColor(get(literal(*property)));
+ },
+ [&] (const type::Array& array) -> optional<std::unique_ptr<Expression>> {
+ return std::unique_ptr<Expression>(
+ std::make_unique<ArrayAssertion>(array, get(literal(*property))));
+ },
+ [&] (const auto&) -> optional<std::unique_ptr<Expression>> {
+ assert(false); // No properties use this type.
+ return {};
+ }
+ );
+ default:
+ error = { "unsupported function type" };
+ return {};
+ }
+}
+
+template <class T>
+optional<std::unique_ptr<Expression>> composite(type::Type type,
+ const Convertible& value,
+ Error& error,
+ std::unique_ptr<Expression> (*makeInnerExpression) (type::Type type,
+ double base,
+ const std::string& property,
+ std::map<T, std::unique_ptr<Expression>>)) {
+ auto propertyValue = objectMember(value, "property");
+ if (!propertyValue) {
+ error = { "function must specify property" };
+ return {};
+ }
+
+ auto base = convertBase(value, error);
+ if (!base) {
+ return {};
+ }
+
+ auto propertyString = toString(*propertyValue);
+ if (!propertyString) {
+ error = { "function property must be a string" };
+ return {};
+ }
+
+ auto stopsValue = objectMember(value, "stops");
+
+ // Checked by caller.
+ assert(stopsValue);
+ assert(isArray(*stopsValue));
+
+ std::map<float, std::map<T, std::unique_ptr<Expression>>> map;
+
+ for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
+ const auto& stopValue = arrayMember(*stopsValue, i);
+
+ if (!isArray(stopValue)) {
+ error = { "function stop must be an array" };
+ return {};
+ }
+
+ if (arrayLength(stopValue) != 2) {
+ error = { "function stop must have two elements" };
+ return {};
+ }
+
+ const auto& stopInput = arrayMember(stopValue, 0);
+
+ if (!isObject(stopInput)) {
+ error = { "stop input must be an object" };
+ return {};
+ }
+
+ auto zoomValue = objectMember(stopInput, "zoom");
+ if (!zoomValue) {
+ error = { "stop input must specify zoom" };
+ return {};
+ }
+
+ auto sourceValue = objectMember(stopInput, "value");
+ if (!sourceValue) {
+ error = { "stop input must specify value" };
+ return {};
+ }
+
+ optional<float> z = convert<float>(*zoomValue, error);
+ if (!z) {
+ return {};
+ }
+
+ optional<T> d = convert<T>(*sourceValue, error);
+ if (!d) {
+ return {};
+ }
+
+ optional<std::unique_ptr<Expression>> r = convertLiteral(type, arrayMember(stopValue, 1), error);
+ if (!r) {
+ return {};
+ }
+
+ map[*z].emplace(*d, std::move(*r));
+ }
+
+ std::map<double, std::unique_ptr<Expression>> stops;
+
+ for (auto& e : map) {
+ stops.emplace(e.first, makeInnerExpression(type, *base, *propertyString, std::move(e.second)));
+ }
+
+ if (interpolatable(type)) {
+ return interpolate(type, linear(), zoom(), std::move(stops));
+ } else {
+ return step(type, zoom(), std::move(stops));
+ }
+}
+
+optional<std::unique_ptr<Expression>> convertCompositeFunctionToExpression(type::Type type,
+ const Convertible& value,
+ Error& err) {
+ if (!isObject(value)) {
+ err = { "function must be an object" };
+ return {};
+ }
+
+ auto stopsValue = objectMember(value, "stops");
+ if (!stopsValue) {
+ err = { "function value must specify stops" };
+ return {};
+ }
+
+ if (!isArray(*stopsValue)) {
+ err = { "function stops must be an array" };
+ return {};
+ }
+
+ if (arrayLength(*stopsValue) == 0) {
+ err = { "function must have at least one stop" };
+ return {};
+ }
+
+ const auto& first = arrayMember(*stopsValue, 0);
+
+ if (!isArray(first)) {
+ err = { "function stop must be an array" };
+ return {};
+ }
+
+ if (arrayLength(first) != 2) {
+ err = { "function stop must have two elements" };
+ return {};
+ }
+
+ const auto& stop = arrayMember(first, 0);
+
+ if (!isObject(stop)) {
+ err = { "stop must be an object" };
+ return {};
+ }
+
+ auto sourceValue = objectMember(stop, "value");
+ if (!sourceValue) {
+ err = { "stop must specify value" };
+ return {};
+ }
+
+ if (toBool(*sourceValue)) {
+ switch (functionType(type, value)) {
+ case FunctionType::Categorical:
+ return composite<bool>(type, value, err, [] (type::Type type_, double, const std::string& property, std::map<bool, std::unique_ptr<Expression>> stops) {
+ return categorical<bool>(type_, property, std::move(stops));
+ });
+ default:
+ err = { "unsupported function type" };
+ return {};
+ }
+ }
+
+ if (toNumber(*sourceValue)) {
+ switch (functionType(type, value)) {
+ case FunctionType::Interval:
+ return composite<double>(type, value, err, [] (type::Type type_, double, const std::string& property, std::map<double, std::unique_ptr<Expression>> stops) {
+ return step(type_, number(get(literal(property))), std::move(stops));
+ });
+ case FunctionType::Exponential:
+ return composite<double>(type, value, err, [] (type::Type type_, double base, const std::string& property, std::map<double, std::unique_ptr<Expression>> stops) {
+ return interpolate(type_, exponential(base), number(get(literal(property))), std::move(stops));
+ });
+ case FunctionType::Categorical:
+ return composite<int64_t>(type, value, err, [] (type::Type type_, double, const std::string& property, std::map<int64_t, std::unique_ptr<Expression>> stops) {
+ return categorical<int64_t>(type_, property, std::move(stops));
+ });
+ default:
+ err = { "unsupported function type" };
+ return {};
+ }
+ }
+
+ if (toString(*sourceValue)) {
+ switch (functionType(type, value)) {
+ case FunctionType::Categorical:
+ return composite<std::string>(type, value, err, [] (type::Type type_, double, const std::string& property, std::map<std::string, std::unique_ptr<Expression>> stops) {
+ return categorical<std::string>(type_, property, std::move(stops));
+ });
+ default:
+ err = { "unsupported function type" };
+ return {};
+ }
+ }
+
+ err = { "stop domain value must be a number, string, or boolean" };
+ return {};
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp
index 2298bdf8d3..5532e0a520 100644
--- a/src/mbgl/style/expression/dsl.cpp
+++ b/src/mbgl/style/expression/dsl.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/expression/dsl.hpp>
+#include <mbgl/style/expression/error.hpp>
#include <mbgl/style/expression/literal.hpp>
#include <mbgl/style/expression/assertion.hpp>
#include <mbgl/style/expression/coercion.hpp>
@@ -28,6 +29,10 @@ static std::unique_ptr<Expression> compound(const char* op, Args... args) {
return std::move(*result);
}
+std::unique_ptr<Expression> error(std::string message) {
+ return std::make_unique<Error>(std::move(message));
+}
+
std::unique_ptr<Expression> literal(const char* value) {
return literal(std::string(value));
}
@@ -60,6 +65,10 @@ std::unique_ptr<Expression> string(std::unique_ptr<Expression> value) {
return std::make_unique<Assertion>(type::String, vec(std::move(value)));
}
+std::unique_ptr<Expression> boolean(std::unique_ptr<Expression> value) {
+ return std::make_unique<Assertion>(type::Boolean, vec(std::move(value)));
+}
+
std::unique_ptr<Expression> toColor(const char* value) {
return toColor(literal(value));
}
diff --git a/src/mbgl/style/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp
deleted file mode 100644
index dd179f5376..0000000000
--- a/src/mbgl/style/function/categorical_stops.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#include <mbgl/style/function/categorical_stops.hpp>
-#include <mbgl/style/types.hpp>
-#include <mbgl/util/color.hpp>
-
-#include <array>
-
-namespace mbgl {
-namespace style {
-
-optional<CategoricalValue> categoricalValue(const Value& value) {
- return value.match(
- [] (bool t) { return optional<CategoricalValue>(t); },
- [] (uint64_t t) { return optional<CategoricalValue>(int64_t(t)); },
- [] (int64_t t) { return optional<CategoricalValue>(t); },
- [] (double t) { return optional<CategoricalValue>(int64_t(t)); },
- [] (const std::string& t) { return optional<CategoricalValue>(t); },
- [] (const auto&) { return optional<CategoricalValue>(); }
- );
-}
-
-template <class T>
-optional<T> CategoricalStops<T>::evaluate(const Value& value) const {
- auto v = categoricalValue(value);
- if (!v) {
- return {};
- }
- auto it = stops.find(*v);
- return it == stops.end() ? optional<T>() : it->second;
-}
-
-template class CategoricalStops<float>;
-template class CategoricalStops<Color>;
-template class CategoricalStops<std::array<float, 2>>;
-template class CategoricalStops<std::string>;
-template class CategoricalStops<TextTransformType>;
-template class CategoricalStops<TextJustifyType>;
-template class CategoricalStops<SymbolAnchorType>;
-template class CategoricalStops<LineJoinType>;
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/function/convert.cpp b/src/mbgl/style/function/convert.cpp
deleted file mode 100644
index a3b19f287b..0000000000
--- a/src/mbgl/style/function/convert.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include <mbgl/style/function/convert.hpp>
-
-namespace mbgl {
-namespace style {
-namespace expression {
-
-std::unique_ptr<Expression> Convert::fromIdentityFunction(const std::string& property, type::Type type) {
- return type.match(
- [&] (const type::StringType&) {
- return makeGet(type::String, property);
- },
- [&] (const type::NumberType&) {
- return makeGet(type::Number, property);
- },
- [&] (const type::BooleanType&) {
- return makeGet(type::Boolean, property);
- },
- [&] (const type::ColorType&) {
- std::vector<std::unique_ptr<Expression>> args;
- args.push_back(makeGet(type::String, property));
- return std::make_unique<Coercion>(type::Color, std::move(args));
- },
- [&] (const type::Array& arr) {
- std::vector<std::unique_ptr<Expression>> getArgs;
- getArgs.push_back(makeLiteral(property));
- ParsingContext ctx;
- ParseResult get = createCompoundExpression("get", std::move(getArgs), ctx);
- assert(get);
- assert(ctx.getErrors().size() == 0);
- return std::make_unique<ArrayAssertion>(arr, std::move(*get));
- },
- [&] (const auto&) -> std::unique_ptr<Expression> {
- return makeLiteral(Null);
- }
- );
-}
-
-} // namespace expression
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp
deleted file mode 100644
index 0ac6fda846..0000000000
--- a/src/mbgl/style/function/identity_stops.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include <mbgl/style/function/identity_stops.hpp>
-#include <mbgl/style/types.hpp>
-#include <mbgl/util/enum.hpp>
-#include <mbgl/util/color.hpp>
-
-#include <array>
-
-namespace mbgl {
-namespace style {
-
-template <>
-optional<float> IdentityStops<float>::evaluate(const Value& value) const {
- return numericValue<float>(value);
-}
-
-template <>
-optional<std::string> IdentityStops<std::string>::evaluate(const Value& value) const {
- if (!value.is<std::string>()) {
- return {};
- }
-
- return value.get<std::string>();
-}
-
-template <>
-optional<Color> IdentityStops<Color>::evaluate(const Value& value) const {
- if (!value.is<std::string>()) {
- return {};
- }
-
- return Color::parse(value.get<std::string>());
-}
-
-template <>
-optional<TextTransformType> IdentityStops<TextTransformType>::evaluate(const Value& value) const {
- if (!value.is<std::string>()) {
- return {};
- }
-
- return Enum<TextTransformType>::toEnum(value.get<std::string>());
-}
-
-template <>
-optional<TextJustifyType> IdentityStops<TextJustifyType>::evaluate(const Value& value) const {
- if (!value.is<std::string>()) {
- return {};
- }
-
- return Enum<TextJustifyType>::toEnum(value.get<std::string>());
-}
-
-template <>
-optional<SymbolAnchorType> IdentityStops<SymbolAnchorType>::evaluate(const Value& value) const {
- if (!value.is<std::string>()) {
- return {};
- }
-
- return Enum<SymbolAnchorType>::toEnum(value.get<std::string>());
-}
-
-template <>
-optional<LineJoinType> IdentityStops<LineJoinType>::evaluate(const Value& value) const {
- if (!value.is<std::string>()) {
- return {};
- }
-
- return Enum<LineJoinType>::toEnum(value.get<std::string>());
-}
-
-template <>
-optional<std::array<float, 2>> IdentityStops<std::array<float, 2>>::evaluate(const Value& value) const {
- if (!value.is<std::vector<Value>>()) {
- return {};
- }
-
- const auto& vector = value.get<std::vector<Value>>();
- if (vector.size() != 2 || !numericValue<float>(vector[0]) || !numericValue<float>(vector[1])) {
- return {};
- }
-
- std::array<float, 2> array {{
- *numericValue<float>(vector[0]),
- *numericValue<float>(vector[1])
- }};
- return array;
-}
-
-} // namespace style
-} // namespace mbgl