#ifndef SASS_AST_HELPERS_H
#define SASS_AST_HELPERS_H
// sass.hpp must go before all system headers to get the
// __EXTENSIONS__ fix on Solaris.
#include "sass.hpp"
#include <algorithm>
#include <functional>
#include "util_string.hpp"
namespace Sass {
// ###########################################################################
// ###########################################################################
// easier to search with name
const bool DELAYED = true;
// ToDo: should this really be hardcoded
// Note: most methods follow precision option
const double NUMBER_EPSILON = 1e-12;
// macro to test if numbers are equal within a small error margin
#define NEAR_EQUAL(lhs, rhs) std::fabs(lhs - rhs) < NUMBER_EPSILON
// ###########################################################################
// We define various functions and functors here.
// Functions satisfy the BinaryPredicate requirement
// Functors are structs used for e.g. unordered_map
// ###########################################################################
// ###########################################################################
// Implement compare and hashing operations for raw pointers
// ###########################################################################
template <class T>
size_t PtrHashFn(const T* ptr) {
return std::hash<std::size_t>()((size_t)ptr);
}
struct PtrHash {
template <class T>
size_t operator() (const T* ptr) const {
return PtrHashFn(ptr);
}
};
template <class T>
bool PtrEqualityFn(const T* lhs, const T* rhs) {
return lhs == rhs; // compare raw pointers
}
struct PtrEquality {
template <class T>
bool operator() (const T* lhs, const T* rhs) const {
return PtrEqualityFn<T>(lhs, rhs);
}
};
// ###########################################################################
// Implement compare and hashing operations for AST Nodes
// ###########################################################################
// TODO: get rid of functions and use ObjEquality<T>
template <class T>
// Hash the raw pointer instead of object
size_t ObjPtrHashFn(const T& obj) {
return PtrHashFn(obj.ptr());
}
struct ObjPtrHash {
template <class T>
// Hash the raw pointer instead of object
size_t operator() (const T& obj) const {
return ObjPtrHashFn(obj);
}
};
template <class T>
// Hash the object and its content
size_t ObjHashFn(const T& obj) {
return obj ? obj->hash() : 0;
}
struct ObjHash {
template <class T>
// Hash the object and its content
size_t operator() (const T& obj) const {
return ObjHashFn(obj);
}
};
template <class T>
// Hash the object behind pointer
size_t PtrObjHashFn(const T* obj) {
return obj ? obj->hash() : 0;
}
struct PtrObjHash {
template <class T>
// Hash the object behind pointer
size_t operator() (const T* obj) const {
return PtrObjHashFn(obj);
}
};
template <class T>
// Compare raw pointers to the object
bool ObjPtrEqualityFn(const T& lhs, const T& rhs) {
return PtrEqualityFn(lhs.ptr(), rhs.ptr());
}
struct ObjPtrEquality {
template <class T>
// Compare raw pointers to the object
bool operator() (const T& lhs, const T& rhs) const {
return ObjPtrEqualityFn<T>(lhs, rhs);
}
};
template <class T>
// Compare the objects behind the pointers
bool PtrObjEqualityFn(const T* lhs, const T* rhs) {
if (lhs == nullptr) return rhs == nullptr;
else if (rhs == nullptr) return false;
else return *lhs == *rhs;
}
struct PtrObjEquality {
template <class T>
// Compare the objects behind the pointers
bool operator() (const T* lhs, const T* rhs) const {
return PtrObjEqualityFn<T>(lhs, rhs);
}
};
template <class T>
// Compare the objects and its contents
bool ObjEqualityFn(const T& lhs, const T& rhs) {
return PtrObjEqualityFn(lhs.ptr(), rhs.ptr());
}
struct ObjEquality {
template <class T>
// Compare the objects and its contents
bool operator() (const T& lhs, const T& rhs) const {
return ObjEqualityFn<T>(lhs, rhs);
}
};
// ###########################################################################
// Special compare function only for hashes.
// We need to make sure to not have objects equal that
// have different hashes. This is currently an issue,
// since `1px` is equal to `1` but have different hashes.
// This goes away once we remove unitless equality.
// ###########################################################################
template <class T>
// Compare the objects and its hashes
bool ObjHashEqualityFn(const T& lhs, const T& rhs) {
if (lhs == nullptr) return rhs == nullptr;
else if (rhs == nullptr) return false;
else return lhs->hash() == rhs->hash();
}
struct ObjHashEquality {
template <class T>
// Compare the objects and its contents and hashes
bool operator() (const T& lhs, const T& rhs) const {
return ObjEqualityFn<T>(lhs, rhs) &&
ObjHashEqualityFn(lhs, rhs);
}
};
// ###########################################################################
// Implement ordering operations for AST Nodes
// ###########################################################################
template <class T>
// Compare the objects behind pointers
bool PtrObjLessThanFn(const T* lhs, const T* rhs) {
if (lhs == nullptr) return rhs != nullptr;
else if (rhs == nullptr) return false;
else return *lhs < *rhs;
}
struct PtrObjLessThan {
template <class T>
// Compare the objects behind pointers
bool operator() (const T* lhs, const T* rhs) const {
return PtrObjLessThanFn<T>(lhs, rhs);
}
};
template <class T>
// Compare the objects and its content
bool ObjLessThanFn(const T& lhs, const T& rhs) {
return PtrObjLessThanFn(lhs.ptr(), rhs.ptr());
};
struct ObjLessThan {
template <class T>
// Compare the objects and its content
bool operator() (const T& lhs, const T& rhs) const {
return ObjLessThanFn<T>(lhs, rhs);
}
};
// ###########################################################################
// Some STL helper functions
// ###########################################################################
// Check if all elements are equal
template <class X, class Y,
typename XT = typename X::value_type,
typename YT = typename Y::value_type>
bool ListEquality(const X& lhs, const Y& rhs,
bool(*cmp)(const XT*, const YT*))
{
return lhs.size() == rhs.size() &&
std::equal(lhs.begin(), lhs.end(),
rhs.begin(), cmp);
}
// Return if Vector is empty
template <class T>
bool listIsEmpty(T* cnt) {
return cnt && cnt->empty();
}
// Erase items from vector that match predicate
template<class T, class UnaryPredicate>
void listEraseItemIf(T& vec, UnaryPredicate* predicate)
{
vec.erase(std::remove_if(vec.begin(), vec.end(), predicate), vec.end());
}
// Check that every item in `lhs` is also in `rhs`
// Note: this works by comparing the raw pointers
template <typename T>
bool listIsSubsetOrEqual(const T& lhs, const T& rhs) {
for (const auto& item : lhs) {
if (std::find(rhs.begin(), rhs.end(), item) == rhs.end())
return false;
}
return true;
}
// ##########################################################################
// Returns whether [name] is the name of a pseudo-element
// that can be written with pseudo-class syntax (CSS2 vs CSS3):
// `:before`, `:after`, `:first-line`, or `:first-letter`
// ##########################################################################
inline bool isFakePseudoElement(const sass::string& name)
{
return Util::equalsLiteral("after", name)
|| Util::equalsLiteral("before", name)
|| Util::equalsLiteral("first-line", name)
|| Util::equalsLiteral("first-letter", name);
}
// ##########################################################################
// Names of pseudo selectors that take selectors as arguments,
// and that are subselectors of their arguments.
// For example, `.foo` is a superselector of `:matches(.foo)`.
// ##########################################################################
inline bool isSubselectorPseudo(const sass::string& norm)
{
return Util::equalsLiteral("any", norm)
|| Util::equalsLiteral("matches", norm)
|| Util::equalsLiteral("nth-child", norm)
|| Util::equalsLiteral("nth-last-child", norm);
}
// EO isSubselectorPseudo
// ###########################################################################
// Pseudo-class selectors that take unadorned selectors as arguments.
// ###########################################################################
inline bool isSelectorPseudoClass(const sass::string& test)
{
return Util::equalsLiteral("not", test)
|| Util::equalsLiteral("matches", test)
|| Util::equalsLiteral("current", test)
|| Util::equalsLiteral("any", test)
|| Util::equalsLiteral("has", test)
|| Util::equalsLiteral("host", test)
|| Util::equalsLiteral("host-context", test);
}
// EO isSelectorPseudoClass
// ###########################################################################
// Pseudo-element selectors that take unadorned selectors as arguments.
// ###########################################################################
inline bool isSelectorPseudoElement(const sass::string& test)
{
return Util::equalsLiteral("slotted", test);
}
// EO isSelectorPseudoElement
// ###########################################################################
// Pseudo-element selectors that has binominals
// ###########################################################################
inline bool isSelectorPseudoBinominal(const sass::string& test)
{
return Util::equalsLiteral("nth-child", test)
|| Util::equalsLiteral("nth-last-child", test);
}
// isSelectorPseudoBinominal
// ###########################################################################
// ###########################################################################
}
#endif