#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 #include #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 size_t PtrHashFn(const T* ptr) { return std::hash()((size_t)ptr); } struct PtrHash { template size_t operator() (const T* ptr) const { return PtrHashFn(ptr); } }; template bool PtrEqualityFn(const T* lhs, const T* rhs) { return lhs == rhs; // compare raw pointers } struct PtrEquality { template bool operator() (const T* lhs, const T* rhs) const { return PtrEqualityFn(lhs, rhs); } }; // ########################################################################### // Implement compare and hashing operations for AST Nodes // ########################################################################### // TODO: get rid of funtions and use ObjEquality template // Hash the raw pointer instead of object size_t ObjPtrHashFn(const T& obj) { return PtrHashFn(obj.ptr()); } struct ObjPtrHash { template // Hash the raw pointer instead of object size_t operator() (const T& obj) const { return ObjPtrHashFn(obj); } }; template // Hash the object and its content size_t ObjHashFn(const T& obj) { return obj ? obj->hash() : 0; } struct ObjHash { template // Hash the object and its content size_t operator() (const T& obj) const { return ObjHashFn(obj); } }; template // Hash the object behind pointer size_t PtrObjHashFn(const T* obj) { return obj ? obj->hash() : 0; } struct PtrObjHash { template // Hash the object behind pointer size_t operator() (const T* obj) const { return PtrObjHashFn(obj); } }; template // Compare raw pointers to the object bool ObjPtrEqualityFn(const T& lhs, const T& rhs) { return PtrEqualityFn(lhs.ptr(), rhs.ptr()); } struct ObjPtrEquality { template // Compare raw pointers to the object bool operator() (const T& lhs, const T& rhs) const { return ObjPtrEqualityFn(lhs, rhs); } }; template // 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 // Compare the objects behind the pointers bool operator() (const T* lhs, const T* rhs) const { return PtrObjEqualityFn(lhs, rhs); } }; template // Compare the objects and its contents bool ObjEqualityFn(const T& lhs, const T& rhs) { return PtrObjEqualityFn(lhs.ptr(), rhs.ptr()); } struct ObjEquality { template // Compare the objects and its contents bool operator() (const T& lhs, const T& rhs) const { return ObjEqualityFn(lhs, rhs); } }; // ########################################################################### // Implement ordering operations for AST Nodes // ########################################################################### template // 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 // Compare the objects behind pointers bool operator() (const T* lhs, const T* rhs) const { return PtrObjLessThanFn(lhs, rhs); } }; template // Compare the objects and its content bool ObjLessThanFn(const T& lhs, const T& rhs) { return PtrObjLessThanFn(lhs.ptr(), rhs.ptr()); }; struct ObjLessThan { template // Compare the objects and its content bool operator() (const T& lhs, const T& rhs) const { return ObjLessThanFn(lhs, rhs); } }; // ########################################################################### // Some STL helper functions // ########################################################################### // Check if all elements are equal template 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 bool listIsEmpty(T* cnt) { return cnt && cnt->empty(); } // Erase items from vector that match predicate template 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 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