diff --git a/src/ast.hpp b/src/ast.hpp index 5b376052a..4cf99d502 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -131,7 +131,7 @@ namespace Sass { ////////////////////////////////////////////////////////////////////// class Expression : public AST_Node { public: - enum Concrete_Type { + enum Type { NONE, BOOLEAN, NUMBER, @@ -148,21 +148,15 @@ namespace Sass { VARIABLE, NUM_TYPES }; - enum Simple_Type { - SIMPLE, - ATTR_SEL, - PSEUDO_SEL, - WRAPPED_SEL, - }; private: // expressions in some contexts shouldn't be evaluated ADD_PROPERTY(bool, is_delayed) ADD_PROPERTY(bool, is_expanded) ADD_PROPERTY(bool, is_interpolant) - ADD_PROPERTY(Concrete_Type, concrete_type) + ADD_PROPERTY(Type, concrete_type) public: Expression(ParserState pstate, - bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE) + bool d = false, bool e = false, bool i = false, Type ct = NONE) : AST_Node(pstate), is_delayed_(d), is_expanded_(e), @@ -183,7 +177,10 @@ namespace Sass { static std::string type_name() { return ""; } virtual bool is_false() { return false; } // virtual bool is_true() { return !is_false(); } + virtual bool operator< (const Expression& rhs) const { return false; } virtual bool operator== (const Expression& rhs) const { return false; } + inline bool operator>(const Expression& rhs) const { return rhs < *this; } + inline bool operator!=(const Expression& rhs) const { return !(rhs == *this); } virtual bool eq(const Expression& rhs) const { return *this == rhs; }; virtual void set_delayed(bool delayed) { is_delayed(delayed); } virtual bool has_interpolant() const { return is_interpolant(); } @@ -244,6 +241,7 @@ namespace Sass { T& operator[](size_t i) { return elements_[i]; } virtual const T& at(size_t i) const { return elements_.at(i); } virtual T& at(size_t i) { return elements_.at(i); } + const T& get(size_t i) const { return elements_[i]; } const T& operator[](size_t i) const { return elements_[i]; } virtual void append(T element) { @@ -361,7 +359,7 @@ namespace Sass { ///////////////////////////////////////////////////////////////////////// class Statement : public AST_Node { public: - enum Statement_Type { + enum Type { NONE, RULESET, MEDIA, @@ -387,11 +385,11 @@ namespace Sass { IF }; private: - ADD_PROPERTY(Statement_Type, statement_type) + ADD_PROPERTY(Type, statement_type) ADD_PROPERTY(size_t, tabs) ADD_PROPERTY(bool, group_end) public: - Statement(ParserState pstate, Statement_Type st = NONE, size_t t = 0) + Statement(ParserState pstate, Type st = NONE, size_t t = 0) : AST_Node(pstate), statement_type_(st), tabs_(t), group_end_(false) { } Statement(const Statement* ptr) diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index e43cfbe9e..d92e8d7d9 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -239,9 +239,9 @@ namespace Sass { class Placeholder_Selector; typedef Placeholder_Selector* Placeholder_Selector_Ptr; typedef Placeholder_Selector const* Placeholder_Selector_Ptr_Const; - class Element_Selector; - typedef Element_Selector* Element_Selector_Ptr; - typedef Element_Selector const* Element_Selector_Ptr_Const; + class Type_Selector; + typedef Type_Selector* Type_Selector_Ptr; + typedef Type_Selector const* Type_Selector_Ptr_Const; class Class_Selector; typedef Class_Selector* Class_Selector_Ptr; typedef Class_Selector const* Class_Selector_Ptr_Const; @@ -345,7 +345,7 @@ namespace Sass { IMPL_MEM_OBJ(Selector_Schema); IMPL_MEM_OBJ(Simple_Selector); IMPL_MEM_OBJ(Placeholder_Selector); - IMPL_MEM_OBJ(Element_Selector); + IMPL_MEM_OBJ(Type_Selector); IMPL_MEM_OBJ(Class_Selector); IMPL_MEM_OBJ(Id_Selector); IMPL_MEM_OBJ(Attribute_Selector); @@ -365,21 +365,29 @@ namespace Sass { return ex.isNull() ? 0 : ex->hash(); } }; + template + bool OrderFunction(const T& lhs, const T& rhs) { + return !lhs.isNull() && !rhs.isNull() && *lhs < *rhs; + }; struct OrderNodes { template bool operator() (const T& lhs, const T& rhs) const { - return !lhs.isNull() && !rhs.isNull() && *lhs < *rhs; + return OrderFunction(lhs, rhs); } }; - struct CompareNodes { - template - bool operator() (const T& lhs, const T& rhs) const { + template + bool CompareFunction(const T& lhs, const T& rhs) { // code around sass logic issue. 1px == 1 is true // but both items are still different keys in maps if (dynamic_cast(lhs.ptr())) if (dynamic_cast(rhs.ptr())) return lhs->hash() == rhs->hash(); return !lhs.isNull() && !rhs.isNull() && *lhs == *rhs; + } + struct CompareNodes { + template + bool operator() (const T& lhs, const T& rhs) const { + return CompareFunction(lhs, rhs); } }; @@ -423,6 +431,9 @@ namespace Sass { typedef std::pair SubSetMapResult; typedef std::vector SubSetMapResults; + #define OrderSelectors OrderFunction + typedef std::set SelectorSet; + typedef std::deque ComplexSelectorDeque; typedef std::set SimpleSelectorSet; typedef std::set ComplexSelectorSet; diff --git a/src/ast_sel_cmp.cpp b/src/ast_sel_cmp.cpp index 4c3485a6c..658dcc696 100644 --- a/src/ast_sel_cmp.cpp +++ b/src/ast_sel_cmp.cpp @@ -19,13 +19,171 @@ namespace Sass { + /*#########################################################################*/ + /*#########################################################################*/ + + bool Selector_List::operator== (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) { return *this == *sl; } + else if (auto ss = Cast(&rhs)) { return *this == *ss; } + else if (auto cpx = Cast(&rhs)) { return *this == *cpx; } + else if (auto cpd = Cast(&rhs)) { return *this == *cpd; } + else if (auto ls = Cast(&rhs)) { return *this == *ls; } + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Selector_List::operator< (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) { return *this < *sl; } + else if (auto ss = Cast(&rhs)) { return *this < *ss; } + else if (auto cpx = Cast(&rhs)) { return *this < *cpx; } + else if (auto cpd = Cast(&rhs)) { return *this < *cpd; } + else if (auto ls = Cast(&rhs)) { return *this < *ls; } + throw std::runtime_error("invalid selector base classes to compare"); + } + + // Selector lists can be compared to comma lists + bool Selector_List::operator== (const Expression& rhs) const + { + if (auto l = Cast(&rhs)) { return *this == *l; } + if (auto s = Cast(&rhs)) { return *this == *s; } + if (Cast(&rhs) || Cast(&rhs)) { return false; } + throw std::runtime_error("invalid selector base classes to compare"); + } + + // Selector lists can be compared to comma lists + bool Selector_List::operator< (const Expression& rhs) const + { + if (auto l = Cast(&rhs)) { return *this < *l; } + if (auto s = Cast(&rhs)) { return *this < *s; } + if (Cast(&rhs) || Cast(&rhs)) { return true; } + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Complex_Selector::operator== (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) return *this == *sl; + if (auto ss = Cast(&rhs)) return *this == *ss; + if (auto cs = Cast(&rhs)) return *this == *cs; + if (auto ch = Cast(&rhs)) return *this == *ch; + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Complex_Selector::operator< (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) return *this < *sl; + if (auto ss = Cast(&rhs)) return *this < *ss; + if (auto cs = Cast(&rhs)) return *this < *cs; + if (auto ch = Cast(&rhs)) return *this < *ch; + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Compound_Selector::operator== (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) return *this == *sl; + if (auto ss = Cast(&rhs)) return *this == *ss; + if (auto cs = Cast(&rhs)) return *this == *cs; + if (auto ch = Cast(&rhs)) return *this == *ch; + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Compound_Selector::operator< (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) return *this < *sl; + if (auto ss = Cast(&rhs)) return *this < *ss; + if (auto cs = Cast(&rhs)) return *this < *cs; + if (auto ch = Cast(&rhs)) return *this < *ch; + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Selector_Schema::operator== (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) return *this == *sl; + if (auto ss = Cast(&rhs)) return *this == *ss; + if (auto cs = Cast(&rhs)) return *this == *cs; + if (auto ch = Cast(&rhs)) return *this == *ch; + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Selector_Schema::operator< (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) return *this < *sl; + if (auto ss = Cast(&rhs)) return *this < *ss; + if (auto cs = Cast(&rhs)) return *this < *cs; + if (auto ch = Cast(&rhs)) return *this < *ch; + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Simple_Selector::operator== (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) return *this == *sl; + if (auto ss = Cast(&rhs)) return *this == *ss; + if (auto cs = Cast(&rhs)) return *this == *cs; + if (auto ch = Cast(&rhs)) return *this == *ch; + throw std::runtime_error("invalid selector base classes to compare"); + } + + bool Simple_Selector::operator< (const Selector& rhs) const + { + if (auto sl = Cast(&rhs)) return *this < *sl; + if (auto ss = Cast(&rhs)) return *this < *ss; + if (auto cs = Cast(&rhs)) return *this < *cs; + if (auto ch = Cast(&rhs)) return *this < *ch; + throw std::runtime_error("invalid selector base classes to compare"); + } + + /*#########################################################################*/ + /*#########################################################################*/ + + bool Selector_List::operator< (const Selector_List& rhs) const + { + size_t l = rhs.length(); + if (length() < l) l = length(); + for (size_t i = 0; i < l; i ++) { + if (*at(i) < *rhs.at(i)) return true; + } + return false; + } + + bool Selector_List::operator== (const Selector_List& rhs) const + { + // for array access + size_t i = 0, n = 0; + size_t iL = length(); + size_t nL = rhs.length(); + // create temporary vectors to sort them for compare + std::vector l_lst = this->elements(); + std::vector r_lst = rhs.elements(); + std::sort(l_lst.begin(), l_lst.end(), OrderNodes()); + std::sort(r_lst.begin(), r_lst.end(), OrderNodes()); + // process loop + while (true) + { + // first check for valid index + if (i == iL) return iL == nL; + else if (n == nL) return iL == nL; + // access the vector items + Complex_Selector_Ptr l = l_lst[i]; + Complex_Selector_Ptr r = r_lst[n]; + // skip nulls + if (!l) ++i; + else if (!r) ++n; + // do the check + else if (*l != *r) break; + // advance + ++i; ++n; + } + // not equal + return false; + } + bool Compound_Selector::operator< (const Compound_Selector& rhs) const { size_t L = std::min(length(), rhs.length()); for (size_t i = 0; i < L; ++i) { - Simple_Selector_Obj l = (*this)[i]; - Simple_Selector_Obj r = rhs[i]; + Simple_Selector_Ptr l = (*this)[i]; + Simple_Selector_Ptr r = rhs[i]; if (!l && !r) return false; else if (!r) return false; else if (!l) return true; @@ -133,24 +291,6 @@ namespace Sass { // process all tails while (true) { - #ifdef DEBUG - // skip empty ancestor first - if (l && l->is_empty_ancestor()) - { - l_h = NULL; - l = l->tail(); - if (l) l_h = l->head(); - continue; - } - // skip empty ancestor first - if (r && r->is_empty_ancestor()) - { - r_h = NULL; - r = r->tail(); - if (r) r_h = r->head(); - continue; - } - #endif // check the pointers if (!r) return !l; if (!l) return !r; @@ -192,190 +332,325 @@ namespace Sass { return false; } - bool Complex_Selector::operator== (const Selector& rhs) const + /*#########################################################################*/ + /*#########################################################################*/ + + bool Selector_List::operator== (const Complex_Selector& rhs) const { - if (const Selector_List* sl = Cast(&rhs)) return *this == *sl; - if (const Simple_Selector* sp = Cast(&rhs)) return *this == *sp; - if (const Complex_Selector* cs = Cast(&rhs)) return *this == *cs; - if (const Compound_Selector* ch = Cast(&rhs)) return *this == *ch; - throw std::runtime_error("invalid selector base classes to compare"); + size_t len = length(); + if (len > 1) return false; + if (len == 0) return rhs.empty(); + return *at(0) == rhs; } + bool Selector_List::operator< (const Complex_Selector& rhs) const + { + size_t len = length(); + if (len > 1) return false; + if (len == 0) return !rhs.empty(); + return *at(0) < rhs; + } - bool Complex_Selector::operator< (const Selector& rhs) const + bool Selector_List::operator== (const Compound_Selector& rhs) const { - if (const Selector_List* sl = Cast(&rhs)) return *this < *sl; - if (const Simple_Selector* sp = Cast(&rhs)) return *this < *sp; - if (const Complex_Selector* cs = Cast(&rhs)) return *this < *cs; - if (const Compound_Selector* ch = Cast(&rhs)) return *this < *ch; - throw std::runtime_error("invalid selector base classes to compare"); + size_t len = length(); + if (len > 1) return false; + if (len == 0) return rhs.empty(); + return *at(0) == rhs; } - bool Compound_Selector::operator== (const Selector& rhs) const + bool Selector_List::operator< (const Compound_Selector& rhs) const { - if (const Selector_List* sl = Cast(&rhs)) return *this == *sl; - if (const Simple_Selector* sp = Cast(&rhs)) return *this == *sp; - if (const Complex_Selector* cs = Cast(&rhs)) return *this == *cs; - if (const Compound_Selector* ch = Cast(&rhs)) return *this == *ch; - throw std::runtime_error("invalid selector base classes to compare"); + size_t len = length(); + if (len > 1) return false; + if (len == 0) return !rhs.empty(); + return *at(0) < rhs; } - bool Compound_Selector::operator< (const Selector& rhs) const + bool Selector_List::operator== (const Simple_Selector& rhs) const { - if (const Selector_List* sl = Cast(&rhs)) return *this < *sl; - if (const Simple_Selector* sp = Cast(&rhs)) return *this < *sp; - if (const Complex_Selector* cs = Cast(&rhs)) return *this < *cs; - if (const Compound_Selector* ch = Cast(&rhs)) return *this < *ch; - throw std::runtime_error("invalid selector base classes to compare"); + size_t len = length(); + if (len > 1) return false; + if (len == 0) return rhs.empty(); + return *at(0) == rhs; } - bool Selector_Schema::operator== (const Selector& rhs) const + bool Selector_List::operator< (const Simple_Selector& rhs) const { - if (const Selector_List* sl = Cast(&rhs)) return *this == *sl; - if (const Simple_Selector* sp = Cast(&rhs)) return *this == *sp; - if (const Complex_Selector* cs = Cast(&rhs)) return *this == *cs; - if (const Compound_Selector* ch = Cast(&rhs)) return *this == *ch; - throw std::runtime_error("invalid selector base classes to compare"); + size_t len = length(); + if (len > 1) return false; + if (len == 0) return !rhs.empty(); + return *at(0) < rhs; } - bool Selector_Schema::operator< (const Selector& rhs) const + /***************************************************************************/ + /***************************************************************************/ + + bool Complex_Selector::operator== (const Selector_List& rhs) const { - if (const Selector_List* sl = Cast(&rhs)) return *this < *sl; - if (const Simple_Selector* sp = Cast(&rhs)) return *this < *sp; - if (const Complex_Selector* cs = Cast(&rhs)) return *this < *cs; - if (const Compound_Selector* ch = Cast(&rhs)) return *this < *ch; - throw std::runtime_error("invalid selector base classes to compare"); + size_t len = rhs.length(); + if (len > 1) return false; + if (len == 0) return empty(); + return *this == *rhs.at(0); } - bool Simple_Selector::operator== (const Selector& rhs) const + bool Complex_Selector::operator< (const Selector_List& rhs) const { - if (Simple_Selector_Ptr_Const sp = Cast(&rhs)) return *this == *sp; - return false; + size_t len = rhs.length(); + if (len > 1) return true; + if (len == 0) return false; + return *this < *rhs.at(0); } - bool Simple_Selector::operator< (const Selector& rhs) const + bool Complex_Selector::operator== (const Compound_Selector& rhs) const { - if (Simple_Selector_Ptr_Const sp = Cast(&rhs)) return *this < *sp; - return false; + if (tail()) return false; + if (!head()) return rhs.empty(); + return *head() == rhs; } - bool Simple_Selector::operator== (const Simple_Selector& rhs) const + bool Complex_Selector::operator< (const Compound_Selector& rhs) const { - // solve the double dispatch problem by using RTTI information via dynamic cast - if (const Pseudo_Selector* lhs = Cast(this)) {return *lhs == rhs; } - else if (const Wrapped_Selector* lhs = Cast(this)) {return *lhs == rhs; } - else if (const Element_Selector* lhs = Cast(this)) {return *lhs == rhs; } - else if (const Attribute_Selector* lhs = Cast(this)) {return *lhs == rhs; } - else if (name_ == rhs.name_) - { return is_ns_eq(rhs); } - else return false; + if (tail()) return false; + if (!head()) return !rhs.empty(); + return *head() < rhs; } - bool Simple_Selector::operator< (const Simple_Selector& rhs) const + bool Complex_Selector::operator== (const Simple_Selector& rhs) const { - // solve the double dispatch problem by using RTTI information via dynamic cast - if (const Pseudo_Selector* lhs = Cast(this)) {return *lhs < rhs; } - else if (const Wrapped_Selector* lhs = Cast(this)) {return *lhs < rhs; } - else if (const Element_Selector* lhs = Cast(this)) {return *lhs < rhs; } - else if (const Attribute_Selector* lhs = Cast(this)) {return *lhs < rhs; } - if (is_ns_eq(rhs)) - { return name_ < rhs.name_; } - return ns_ < rhs.ns_; + if (tail()) return false; + if (!head()) return rhs.empty(); + return *head() == rhs; } - bool Selector_List::operator== (const Selector& rhs) const + bool Complex_Selector::operator< (const Simple_Selector& rhs) const { - // solve the double dispatch problem by using RTTI information via dynamic cast - if (Selector_List_Ptr_Const sl = Cast(&rhs)) { return *this == *sl; } - else if (Complex_Selector_Ptr_Const cpx = Cast(&rhs)) { return *this == *cpx; } - else if (Compound_Selector_Ptr_Const cpd = Cast(&rhs)) { return *this == *cpd; } - // no compare method - return this == &rhs; + if (tail()) return false; + if (!head()) return !rhs.empty(); + return *head() < rhs; } - // Selector lists can be compared to comma lists - bool Selector_List::operator== (const Expression& rhs) const + /***************************************************************************/ + /***************************************************************************/ + + bool Compound_Selector::operator== (const Selector_List& rhs) const { - // solve the double dispatch problem by using RTTI information via dynamic cast - if (List_Ptr_Const ls = Cast(&rhs)) { return *ls == *this; } - if (Selector_Ptr_Const ls = Cast(&rhs)) { return *this == *ls; } - // compare invalid (maybe we should error?) - return false; + size_t len = rhs.length(); + if (len > 1) return false; + if (len == 0) return empty(); + return *this == *rhs.at(0); } - bool Selector_List::operator== (const Selector_List& rhs) const + bool Compound_Selector::operator< (const Selector_List& rhs) const { - // for array access - size_t i = 0, n = 0; - size_t iL = length(); - size_t nL = rhs.length(); - // create temporary vectors and sort them - std::vector l_lst = this->elements(); - std::vector r_lst = rhs.elements(); - std::sort(l_lst.begin(), l_lst.end(), OrderNodes()); - std::sort(r_lst.begin(), r_lst.end(), OrderNodes()); - // process loop - while (true) - { - // first check for valid index - if (i == iL) return iL == nL; - else if (n == nL) return iL == nL; - // the access the vector items - Complex_Selector_Obj l = l_lst[i]; - Complex_Selector_Obj r = r_lst[n]; - // skip nulls - if (!l) ++i; - else if (!r) ++n; - // do the check - else if (*l != *r) - { return false; } - // advance - ++i; ++n; - } - // there is no break?! + size_t len = rhs.length(); + if (len > 1) return true; + if (len == 0) return false; + return *this < *rhs.at(0); } - bool Selector_List::operator< (const Selector& rhs) const + bool Compound_Selector::operator== (const Complex_Selector& rhs) const { - if (Selector_List_Ptr_Const sp = Cast(&rhs)) return *this < *sp; - return false; + if (rhs.tail()) return false; + if (!rhs.head()) return empty(); + return *this == *rhs.head(); } - bool Selector_List::operator< (const Selector_List& rhs) const + bool Compound_Selector::operator< (const Complex_Selector& rhs) const { - size_t l = rhs.length(); - if (length() < l) l = length(); - for (size_t i = 0; i < l; i ++) { - if (*at(i) < *rhs.at(i)) return true; + if (rhs.tail()) return true; + if (!rhs.head()) return false; + return *this < *rhs.head(); + } + + bool Compound_Selector::operator< (const Simple_Selector& rhs) const + { + size_t len = length(); + if (len > 1) return false; + if (len == 0) return rhs.empty(); + return *at(0) == rhs; + } + + bool Compound_Selector::operator== (const Simple_Selector& rhs) const + { + size_t len = length(); + if (len > 1) return false; + if (len == 0) return !rhs.empty(); + return *at(0) < rhs; + } + + /***************************************************************************/ + /***************************************************************************/ + + bool Simple_Selector::operator== (const Selector_List& rhs) const + { + size_t len = rhs.length(); + if (len > 1) return false; + if (len == 0) return empty(); + return *this == *rhs.at(0); + } + + bool Simple_Selector::operator< (const Selector_List& rhs) const + { + size_t len = rhs.length(); + if (len > 1) return true; + if (len == 0) return false; + return *this < *rhs.at(0); + } + + bool Simple_Selector::operator== (const Complex_Selector& rhs) const + { + if (rhs.tail()) return false; + if (!rhs.head()) return empty(); + return *this == *rhs.head(); + } + + bool Simple_Selector::operator< (const Complex_Selector& rhs) const + { + if (rhs.tail()) return true; + if (!rhs.head()) return false; + return *this < *rhs.head(); + } + + bool Simple_Selector::operator== (const Compound_Selector& rhs) const + { + size_t len = rhs.length(); + if (len > 1) return false; + if (len == 0) return empty(); + return *this == *rhs.at(0); + } + + bool Simple_Selector::operator< (const Compound_Selector& rhs) const + { + size_t len = rhs.length(); + if (len > 1) return true; + if (len == 0) return false; + return *this < *rhs.at(0); + } + + /*#########################################################################*/ + /*#########################################################################*/ + + bool Simple_Selector::operator== (const Simple_Selector& rhs) const + { + switch (simple_type()) { + case ID_SEL: return (const Id_Selector&) *this == rhs; break; + case TYPE_SEL: return (const Type_Selector&) *this == rhs; break; + case CLASS_SEL: return (const Class_Selector&) *this == rhs; break; + case PARENT_SEL: return (const Parent_Selector&) *this == rhs; break; + case PSEUDO_SEL: return (const Pseudo_Selector&) *this == rhs; break; + case WRAPPED_SEL: return (const Wrapped_Selector&) *this == rhs; break; + case ATTRIBUTE_SEL: return (const Attribute_Selector&) *this == rhs; break; + case PLACEHOLDER_SEL: return (const Placeholder_Selector&) *this == rhs; break; } return false; } - bool Attribute_Selector::operator< (const Attribute_Selector& rhs) const + /***************************************************************************/ + /***************************************************************************/ + + bool Id_Selector::operator== (const Simple_Selector& rhs) const { - if (is_ns_eq(rhs)) { - if (name() == rhs.name()) { - if (matcher() == rhs.matcher()) { - bool no_lhs_val = value().isNull(); - bool no_rhs_val = rhs.value().isNull(); - if (no_lhs_val && no_rhs_val) return false; // equal - else if (no_lhs_val) return true; // lhs is null - else if (no_rhs_val) return false; // rhs is null - return *value() < *rhs.value(); // both are given - } else { return matcher() < rhs.matcher(); } - } else { return name() < rhs.name(); } - } else { return ns() < rhs.ns(); } + auto sel = Cast(&rhs); + return sel ? *this == *sel : false; } - bool Attribute_Selector::operator< (const Simple_Selector& rhs) const + bool Type_Selector::operator== (const Simple_Selector& rhs) const { - if (Attribute_Selector_Ptr_Const w = Cast(&rhs)) - { - return *this < *w; + auto sel = Cast(&rhs); + return sel ? *this == *sel : false; + } + + bool Class_Selector::operator== (const Simple_Selector& rhs) const + { + auto sel = Cast(&rhs); + return sel ? *this == *sel : false; + } + + bool Parent_Selector::operator== (const Simple_Selector& rhs) const + { + auto sel = Cast(&rhs); + return sel ? *this == *sel : false; + } + + bool Pseudo_Selector::operator== (const Simple_Selector& rhs) const + { + auto sel = Cast(&rhs); + return sel ? *this == *sel : false; + } + + bool Wrapped_Selector::operator== (const Simple_Selector& rhs) const + { + auto sel = Cast(&rhs); + return sel ? *this == *sel : false; + } + + bool Attribute_Selector::operator== (const Simple_Selector& rhs) const + { + auto sel = Cast(&rhs); + return sel ? *this == *sel : false; + } + + bool Placeholder_Selector::operator== (const Simple_Selector& rhs) const + { + auto sel = Cast(&rhs); + return sel ? *this == *sel : false; + } + + /***************************************************************************/ + /***************************************************************************/ + + bool Id_Selector::operator== (const Id_Selector& rhs) const + { + // ID has no namespacing + return name() == rhs.name(); + } + + bool Type_Selector::operator== (const Type_Selector& rhs) const + { + return is_ns_eq(rhs) && name() == rhs.name(); + } + + bool Class_Selector::operator== (const Class_Selector& rhs) const + { + // Class has no namespacing + return name() == rhs.name(); + } + + bool Parent_Selector::operator== (const Parent_Selector& rhs) const + { + // Parent has no namespacing + return name() == rhs.name(); + } + + bool Pseudo_Selector::operator== (const Pseudo_Selector& rhs) const + { + std::string lname = name(); + std::string rname = rhs.name(); + if (is_pseudo_class_element(lname)) { + if (rname[0] == ':' && rname[1] == ':') { + lname = lname.substr(1, std::string::npos); + } } - if (is_ns_eq(rhs)) - { return name() < rhs.name(); } - return ns() < rhs.ns(); + // right hand is special pseudo (single colon) + if (is_pseudo_class_element(rname)) { + if (lname[0] == ':' && lname[1] == ':') { + lname = lname.substr(1, std::string::npos); + } + } + // Pseudo has no namespacing + if (lname != rname) return false; + String_Obj lhs_ex = expression(); + String_Obj rhs_ex = rhs.expression(); + if (rhs_ex && lhs_ex) return *lhs_ex == *rhs_ex; + else return lhs_ex.ptr() == rhs_ex.ptr(); + } + + bool Wrapped_Selector::operator== (const Wrapped_Selector& rhs) const + { + // Wrapped has no namespacing + if (name() != rhs.name()) return false; + return *(selector()) == *(rhs.selector()); } bool Attribute_Selector::operator== (const Attribute_Selector& rhs) const @@ -398,137 +673,260 @@ namespace Sass { } // not equal return false; + } + bool Placeholder_Selector::operator== (const Placeholder_Selector& rhs) const + { + // Placeholder has no namespacing + return name() == rhs.name(); } - bool Attribute_Selector::operator== (const Simple_Selector& rhs) const + /*#########################################################################*/ + /*#########################################################################*/ + + bool Simple_Selector::operator< (const Simple_Selector& rhs) const { - if (Attribute_Selector_Ptr_Const w = Cast(&rhs)) - { - return is_ns_eq(rhs) && - name() == rhs.name() && - *this == *w; + switch (simple_type()) { + case ID_SEL: return (const Id_Selector&) *this < rhs; break; + case TYPE_SEL: return (const Type_Selector&) *this < rhs; break; + case CLASS_SEL: return (const Class_Selector&) *this < rhs; break; + case PARENT_SEL: return (const Parent_Selector&) *this < rhs; break; + case PSEUDO_SEL: return (const Pseudo_Selector&) *this < rhs; break; + case WRAPPED_SEL: return (const Wrapped_Selector&) *this < rhs; break; + case ATTRIBUTE_SEL: return (const Attribute_Selector&) *this < rhs; break; + case PLACEHOLDER_SEL: return (const Placeholder_Selector&) *this < rhs; break; } return false; } - bool Element_Selector::operator< (const Element_Selector& rhs) const - { - if (is_ns_eq(rhs)) - { return name() < rhs.name(); } - return ns() < rhs.ns(); - } + /***************************************************************************/ + /***************************************************************************/ - bool Element_Selector::operator< (const Simple_Selector& rhs) const + bool Id_Selector::operator< (const Simple_Selector& rhs) const { - if (Element_Selector_Ptr_Const w = Cast(&rhs)) - { - return *this < *w; + switch (rhs.simple_type()) { + case TYPE_SEL: return '#' < 's'; break; + case CLASS_SEL: return '#' < '.'; break; + case PARENT_SEL: return '#' < '&'; break; + case PSEUDO_SEL: return '#' < ':'; break; + case WRAPPED_SEL: return '#' < '('; break; + case ATTRIBUTE_SEL: return '#' < '['; break; + case PLACEHOLDER_SEL: return '#' < '%'; break; + case ID_SEL: /* let if fall through */ break; } - if (is_ns_eq(rhs)) - { return name() < rhs.name(); } - return ns() < rhs.ns(); + const Id_Selector& sel = + (const Id_Selector&) rhs; + return *this < sel; + } + + bool Type_Selector::operator< (const Simple_Selector& rhs) const + { + switch (rhs.simple_type()) { + case ID_SEL: return 'e' < '#'; break; + case CLASS_SEL: return 'e' < '.'; break; + case PARENT_SEL: return 'e' < '&'; break; + case PSEUDO_SEL: return 'e' < ':'; break; + case WRAPPED_SEL: return 'e' < '('; break; + case ATTRIBUTE_SEL: return 'e' < '['; break; + case PLACEHOLDER_SEL: return 'e' < '%'; break; + case TYPE_SEL: /* let if fall through */ break; + } + const Type_Selector& sel = + (const Type_Selector&) rhs; + return *this < sel; + } + + bool Class_Selector::operator< (const Simple_Selector& rhs) const + { + switch (rhs.simple_type()) { + case ID_SEL: return '.' < '#'; break; + case TYPE_SEL: return '.' < 's'; break; + case PARENT_SEL: return '.' < '&'; break; + case PSEUDO_SEL: return '.' < ':'; break; + case WRAPPED_SEL: return '.' < '('; break; + case ATTRIBUTE_SEL: return '.' < '['; break; + case PLACEHOLDER_SEL: return '.' < '%'; break; + case CLASS_SEL: /* let if fall through */ break; + } + const Class_Selector& sel = + (const Class_Selector&) rhs; + return *this < sel; } - bool Element_Selector::operator== (const Element_Selector& rhs) const + bool Pseudo_Selector::operator< (const Simple_Selector& rhs) const { - return is_ns_eq(rhs) && - name() == rhs.name(); + switch (rhs.simple_type()) { + case ID_SEL: return ':' < '#'; break; + case TYPE_SEL: return ':' < 's'; break; + case CLASS_SEL: return ':' < '.'; break; + case PARENT_SEL: return ':' < '&'; break; + case WRAPPED_SEL: return ':' < '('; break; + case ATTRIBUTE_SEL: return ':' < '['; break; + case PLACEHOLDER_SEL: return ':' < '%'; break; + case PSEUDO_SEL: /* let if fall through */ break; + } + const Pseudo_Selector& sel = + (const Pseudo_Selector&) rhs; + return *this < sel; } - bool Element_Selector::operator== (const Simple_Selector& rhs) const + bool Wrapped_Selector::operator< (const Simple_Selector& rhs) const { - if (Element_Selector_Ptr_Const w = Cast(&rhs)) - { - return is_ns_eq(rhs) && - name() == rhs.name() && - *this == *w; + switch (rhs.simple_type()) { + case ID_SEL: return '(' < '#'; break; + case TYPE_SEL: return '(' < 's'; break; + case CLASS_SEL: return '(' < '.'; break; + case PARENT_SEL: return '(' < '&'; break; + case PSEUDO_SEL: return '(' < ':'; break; + case ATTRIBUTE_SEL: return '(' < '['; break; + case PLACEHOLDER_SEL: return '(' < '%'; break; + case WRAPPED_SEL: /* let if fall through */ break; } - return false; + const Wrapped_Selector& sel = + (const Wrapped_Selector&) rhs; + return *this < sel; + } + + bool Parent_Selector::operator< (const Simple_Selector& rhs) const + { + switch (rhs.simple_type()) { + case ID_SEL: return '&' < '#'; break; + case TYPE_SEL: return '&' < 's'; break; + case CLASS_SEL: return '&' < '.'; break; + case PSEUDO_SEL: return '&' < ':'; break; + case WRAPPED_SEL: return '&' < '('; break; + case ATTRIBUTE_SEL: return '&' < '['; break; + case PLACEHOLDER_SEL: return '&' < '%'; break; + case PARENT_SEL: /* let if fall through */ break; + } + const Parent_Selector& sel = + (const Parent_Selector&) rhs; + return *this < sel; } - bool Pseudo_Selector::operator== (const Pseudo_Selector& rhs) const + bool Attribute_Selector::operator< (const Simple_Selector& rhs) const { - if (is_ns_eq(rhs) && name() == rhs.name()) - { - String_Obj lhs_ex = expression(); - String_Obj rhs_ex = rhs.expression(); - if (rhs_ex && lhs_ex) return *lhs_ex == *rhs_ex; - else return lhs_ex.ptr() == rhs_ex.ptr(); + switch (rhs.simple_type()) { + case ID_SEL: return '[' < '#'; break; + case TYPE_SEL: return '[' < 'e'; break; + case CLASS_SEL: return '[' < '.'; break; + case PARENT_SEL: return '[' < '&'; break; + case PSEUDO_SEL: return '[' < ':'; break; + case WRAPPED_SEL: return '[' < '('; break; + case PLACEHOLDER_SEL: return '[' < '%'; break; + case ATTRIBUTE_SEL: /* let if fall through */ break; + } + const Attribute_Selector& sel = + (const Attribute_Selector&) rhs; + return *this < sel; + } + + bool Placeholder_Selector::operator< (const Simple_Selector& rhs) const + { + switch (rhs.simple_type()) { + case ID_SEL: return '%' < '#'; break; + case TYPE_SEL: return '%' < 's'; break; + case CLASS_SEL: return '%' < '.'; break; + case PARENT_SEL: return '%' < '&'; break; + case PSEUDO_SEL: return '%' < ':'; break; + case WRAPPED_SEL: return '%' < '('; break; + case ATTRIBUTE_SEL: return '%' < '['; break; + case PLACEHOLDER_SEL: /* let if fall through */ break; } - else return false; + const Placeholder_Selector& sel = + (const Placeholder_Selector&) rhs; + return *this < sel; } - bool Pseudo_Selector::operator== (const Simple_Selector& rhs) const + /***************************************************************************/ + /***************************************************************************/ + + bool Id_Selector::operator< (const Id_Selector& rhs) const { - if (Pseudo_Selector_Ptr_Const w = Cast(&rhs)) - { - return *this == *w; - } - return is_ns_eq(rhs) && - name() == rhs.name(); + // ID has no namespacing + return name() < rhs.name(); } - bool Pseudo_Selector::operator< (const Pseudo_Selector& rhs) const + bool Type_Selector::operator< (const Type_Selector& rhs) const { - if (is_ns_eq(rhs) && name() == rhs.name()) - { - String_Obj lhs_ex = expression(); - String_Obj rhs_ex = rhs.expression(); - if (rhs_ex && lhs_ex) return *lhs_ex < *rhs_ex; - else return lhs_ex.ptr() < rhs_ex.ptr(); - } if (is_ns_eq(rhs)) - { return name() < rhs.name(); } + { + if (rhs.has_ns_ && has_ns_) + return name() < rhs.name(); + if (!rhs.has_ns_ && !has_ns_) + return name() < rhs.name(); + return true; + } return ns() < rhs.ns(); } - bool Pseudo_Selector::operator< (const Simple_Selector& rhs) const + bool Class_Selector::operator< (const Class_Selector& rhs) const { - if (Pseudo_Selector_Ptr_Const w = Cast(&rhs)) - { - return *this < *w; - } - if (is_ns_eq(rhs)) - { return name() < rhs.name(); } - return ns() < rhs.ns(); + // Class has no namespacing + return name() < rhs.name(); } - bool Wrapped_Selector::operator== (const Wrapped_Selector& rhs) const + bool Parent_Selector::operator< (const Parent_Selector& rhs) const { - if (is_ns_eq(rhs) && name() == rhs.name()) - { return *(selector()) == *(rhs.selector()); } - else return false; + // Parent has no namespacing + return name() < rhs.name(); } - bool Wrapped_Selector::operator== (const Simple_Selector& rhs) const + bool Pseudo_Selector::operator< (const Pseudo_Selector& rhs) const { - if (Wrapped_Selector_Ptr_Const w = Cast(&rhs)) - { - return *this == *w; + std::string lname = name(); + std::string rname = rhs.name(); + if (is_pseudo_class_element(lname)) { + if (rname[0] == ':' && rname[1] == ':') { + lname = lname.substr(1, std::string::npos); + } + } + // right hand is special pseudo (single colon) + if (is_pseudo_class_element(rname)) { + if (lname[0] == ':' && lname[1] == ':') { + lname = lname.substr(1, std::string::npos); + } } - return is_ns_eq(rhs) && - name() == rhs.name(); + // Peudo has no namespacing + if (lname != rname) + { return lname < rname; } + String_Obj lhs_ex = expression(); + String_Obj rhs_ex = rhs.expression(); + if (rhs_ex && lhs_ex) return *lhs_ex < *rhs_ex; + else return lhs_ex.ptr() < rhs_ex.ptr(); } bool Wrapped_Selector::operator< (const Wrapped_Selector& rhs) const { - if (is_ns_eq(rhs) && name() == rhs.name()) - { return *(selector()) < *(rhs.selector()); } - if (is_ns_eq(rhs)) + // Wrapped has no namespacing + if (name() != rhs.name()) { return name() < rhs.name(); } - return ns() < rhs.ns(); + return *(selector()) < *(rhs.selector()); } - bool Wrapped_Selector::operator< (const Simple_Selector& rhs) const + bool Attribute_Selector::operator< (const Attribute_Selector& rhs) const { - if (Wrapped_Selector_Ptr_Const w = Cast(&rhs)) - { - return *this < *w; - } - if (is_ns_eq(rhs)) - { return name() < rhs.name(); } - return ns() < rhs.ns(); + if (is_ns_eq(rhs)) { + if (name() != rhs.name()) + { return name() < rhs.name(); } + if (matcher() != rhs.matcher()) + { return matcher() < rhs.matcher(); } + bool no_lhs_val = value().isNull(); + bool no_rhs_val = rhs.value().isNull(); + if (no_lhs_val && no_rhs_val) return false; // equal + else if (no_lhs_val) return true; // lhs is null + else if (no_rhs_val) return false; // rhs is null + return *value() < *rhs.value(); // both are given + } else { return ns() < rhs.ns(); } } + bool Placeholder_Selector::operator< (const Placeholder_Selector& rhs) const + { + // Placeholder has no namespacing + return name() < rhs.name(); + } + + /*#########################################################################*/ + /*#########################################################################*/ + } \ No newline at end of file diff --git a/src/ast_sel_unify.cpp b/src/ast_sel_unify.cpp index 30e1b6e06..ca752ab1a 100644 --- a/src/ast_sel_unify.cpp +++ b/src/ast_sel_unify.cpp @@ -35,7 +35,7 @@ namespace Sass { { const size_t rsize = rhs->length(); for (size_t i = 0; i < rsize; ++i) - { if (*this == *rhs->at(i)) return rhs; } + { if (*this == *rhs->get(i)) return rhs; } const int lhs_order = this->unification_order(); size_t i = rsize; while (i > 0 && lhs_order < rhs->at(i - 1)->unification_order()) --i; @@ -43,8 +43,7 @@ namespace Sass { return rhs; } - - Simple_Selector_Ptr Element_Selector::unify_with(Simple_Selector_Ptr rhs) + Simple_Selector_Ptr Type_Selector::unify_with(Simple_Selector_Ptr rhs) { // check if ns can be extended // true for no ns or universal @@ -75,7 +74,7 @@ namespace Sass { return this; } - Compound_Selector_Ptr Element_Selector::unify_with(Compound_Selector_Ptr rhs) + Compound_Selector_Ptr Type_Selector::unify_with(Compound_Selector_Ptr rhs) { // TODO: handle namespaces @@ -89,10 +88,10 @@ namespace Sass { // otherwise, this is a tag name if (name() == "*") { - if (typeid(*rhs_0) == typeid(Element_Selector)) + if (typeid(*rhs_0) == typeid(Type_Selector)) { // if rhs is universal, just return this tagname + rhs's qualifiers - Element_Selector_Ptr ts = Cast(rhs_0); + Type_Selector_Ptr ts = Cast(rhs_0); rhs->at(0) = this->unify_with(ts); return rhs; } @@ -107,7 +106,7 @@ namespace Sass { return rhs; } - if (typeid(*rhs_0) == typeid(Element_Selector)) + if (typeid(*rhs_0) == typeid(Type_Selector)) { // if rhs is universal, just return this tagname + rhs's qualifiers if (rhs_0->name() != "*" && rhs_0->ns() != "*" && rhs_0->name() != name()) return 0; diff --git a/src/ast_selectors.cpp b/src/ast_selectors.cpp index b1b7840ee..dc030593c 100644 --- a/src/ast_selectors.cpp +++ b/src/ast_selectors.cpp @@ -7,6 +7,7 @@ #include "emitter.hpp" #include "color_maps.hpp" #include "ast_fwd_decl.hpp" +#include "ast_selectors.hpp" #include #include #include @@ -154,19 +155,17 @@ namespace Sass { return false; } - // would like to replace this without stringification + // replaced compare without stringification // https://github.com/sass/sass/issues/2229 - // SimpleSelectorSet lset, rset; - std::set lset, rset; + SelectorSet lset, rset; if (lbase && rbase) { - if (lbase->to_string() == rbase->to_string()) { - for (size_t i = 1, L = length(); i < L; ++i) - { lset.insert((*this)[i]->to_string()); } - for (size_t i = 1, L = rhs->length(); i < L; ++i) - { rset.insert((*rhs)[i]->to_string()); } - return includes(rset.begin(), rset.end(), lset.begin(), lset.end()); + if (*lbase == *rbase) { + // create ordered sets for includes query + lset.insert(this->begin(), this->end()); + rset.insert(rhs->begin(), rhs->end()); + return std::includes(rset.begin(), rset.end(), lset.begin(), lset.end(), OrderSelectors); } return false; } @@ -203,8 +202,7 @@ namespace Sass { }} } } - // match from here on as strings - lset.insert(wlhs->to_string()); + lset.insert(wlhs); } for (size_t n = 0, nL = rhs->length(); n < nL; ++n) @@ -227,15 +225,16 @@ namespace Sass { } } } - rset.insert(r->to_string()); + rset.insert(r); } //for (auto l : lset) { cerr << "l: " << l << endl; } //for (auto r : rset) { cerr << "r: " << r << endl; } if (lset.empty()) return true; + // return true if rset contains all the elements of lset - return includes(rset.begin(), rset.end(), lset.begin(), lset.end()); + return std::includes(rset.begin(), rset.end(), lset.begin(), lset.end(), OrderSelectors); } @@ -361,7 +360,7 @@ namespace Sass { Compound_Selector_Obj rh = last()->head(); size_t i; size_t L = h->length(); - if (Cast(h->first())) { + if (Cast(h->first())) { if (Class_Selector_Ptr cs = Cast(rh->last())) { Class_Selector_Ptr sqs = SASS_MEMORY_COPY(cs); sqs->name(sqs->name() + (*h)[0]->name()); @@ -376,8 +375,8 @@ namespace Sass { (*rh)[rh->length()-1] = sqs; rh->pstate(h->pstate()); for (i = 1; i < L; ++i) rh->append((*h)[i]); - } else if (Element_Selector_Ptr ts = Cast(rh->last())) { - Element_Selector_Ptr tss = SASS_MEMORY_COPY(ts); + } else if (Type_Selector_Ptr ts = Cast(rh->last())) { + Type_Selector_Ptr tss = SASS_MEMORY_COPY(ts); tss->name(tss->name() + (*h)[0]->name()); tss->pstate((*h)[0]->pstate()); (*rh)[rh->length()-1] = tss; @@ -899,11 +898,11 @@ namespace Sass { IMPLEMENT_AST_OPERATORS(Attribute_Selector); IMPLEMENT_AST_OPERATORS(Compound_Selector); IMPLEMENT_AST_OPERATORS(Complex_Selector); - IMPLEMENT_AST_OPERATORS(Element_Selector); + IMPLEMENT_AST_OPERATORS(Type_Selector); IMPLEMENT_AST_OPERATORS(Class_Selector); IMPLEMENT_AST_OPERATORS(Id_Selector); IMPLEMENT_AST_OPERATORS(Pseudo_Selector); IMPLEMENT_AST_OPERATORS(Wrapped_Selector); IMPLEMENT_AST_OPERATORS(Selector_List); -} \ No newline at end of file +} diff --git a/src/ast_selectors.hpp b/src/ast_selectors.hpp index 4e993035c..a81a697a7 100644 --- a/src/ast_selectors.hpp +++ b/src/ast_selectors.hpp @@ -139,6 +139,18 @@ namespace Sass { // Abstract base class for simple selectors. //////////////////////////////////////////// class Simple_Selector : public Selector { + public: + enum Simple_Type { + ID_SEL, + TYPE_SEL, + CLASS_SEL, + PSEUDO_SEL, + PARENT_SEL, + WRAPPED_SEL, + ATTRIBUTE_SEL, + PLACEHOLDER_SEL, + }; + public: ADD_CONSTREF(std::string, ns) ADD_CONSTREF(std::string, name) ADD_PROPERTY(Simple_Type, simple_type) @@ -147,7 +159,6 @@ namespace Sass { Simple_Selector(ParserState pstate, std::string n = "") : Selector(pstate), ns_(""), name_(n), has_ns_(false) { - simple_type(SIMPLE); size_t pos = n.find('|'); // found some namespace if (pos != std::string::npos) { @@ -161,7 +172,7 @@ namespace Sass { ns_(ptr->ns_), name_(ptr->name_), has_ns_(ptr->has_ns_) - { simple_type(SIMPLE); } + { } std::string ns_name() const { std::string name(""); @@ -179,6 +190,9 @@ namespace Sass { } return hash_; } + bool empty() const { + return ns().empty() && name().empty(); + } // namespace compare functions bool is_ns_eq(const Simple_Selector& r) const; // namespace query functions @@ -218,15 +232,20 @@ namespace Sass { virtual bool is_superselector_of(Compound_Selector_Ptr_Const sub) const { return false; } + bool operator<(const Selector& rhs) const final override; bool operator==(const Selector& rhs) const final override; + virtual bool operator<(const Selector_List& rhs) const; + virtual bool operator==(const Selector_List& rhs) const; + virtual bool operator<(const Complex_Selector& rhs) const; + virtual bool operator==(const Complex_Selector& rhs) const; + virtual bool operator<(const Compound_Selector& rhs) const; + virtual bool operator==(const Compound_Selector& rhs) const; + virtual bool operator<(const Simple_Selector& rhs) const; virtual bool operator==(const Simple_Selector& rhs) const; - inline bool operator!=(const Simple_Selector& rhs) const { return !(*this == rhs); } - bool operator<(const Selector& rhs) const final override; - virtual bool operator<(const Simple_Selector& rhs) const; - // default implementation should work for most of the simple selectors (otherwise overload) ATTACH_VIRTUAL_AST_OPERATIONS(Simple_Selector); ATTACH_CRTP_PERFORM_METHODS(); + }; inline Simple_Selector::~Simple_Selector() { } @@ -242,10 +261,10 @@ namespace Sass { public: Parent_Selector(ParserState pstate, bool r = true) : Simple_Selector(pstate, "&"), real_(r) - { /* has_reference(true); */ } + { simple_type(PARENT_SEL); } Parent_Selector(const Parent_Selector* ptr) : Simple_Selector(ptr), real_(ptr->real_) - { /* has_reference(true); */ } + { simple_type(PARENT_SEL); } bool is_real_parent_ref() const { return real(); }; bool has_parent_ref() const override { return true; }; bool has_real_parent_ref() const override { return is_real_parent_ref(); }; @@ -259,6 +278,10 @@ namespace Sass { } std::string type() const override { return "selector"; } static std::string type_name() { return "selector"; } + bool operator<(const Simple_Selector& rhs) const final override; + bool operator==(const Simple_Selector& rhs) const final override; + bool operator<(const Parent_Selector& rhs) const; + bool operator==(const Parent_Selector& rhs) const; ATTACH_AST_OPERATIONS(Parent_Selector) ATTACH_CRTP_PERFORM_METHODS() }; @@ -271,10 +294,10 @@ namespace Sass { public: Placeholder_Selector(ParserState pstate, std::string n) : Simple_Selector(pstate, n) - { } + { simple_type(PLACEHOLDER_SEL); } Placeholder_Selector(const Placeholder_Selector* ptr) : Simple_Selector(ptr) - { } + { simple_type(PLACEHOLDER_SEL); } unsigned long specificity() const override { return Constants::Specificity_Base; @@ -287,21 +310,25 @@ namespace Sass { return true; } virtual ~Placeholder_Selector() {}; + bool operator<(const Simple_Selector& rhs) const final override; + bool operator==(const Simple_Selector& rhs) const final override; + bool operator<(const Placeholder_Selector& rhs) const; + bool operator==(const Placeholder_Selector& rhs) const; ATTACH_AST_OPERATIONS(Placeholder_Selector) ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////////////////////////// - // Element selectors (and the universal selector) -- e.g., div, span, *. + // Type selectors (and the universal selector) -- e.g., div, span, *. ///////////////////////////////////////////////////////////////////// - class Element_Selector final : public Simple_Selector { + class Type_Selector final : public Simple_Selector { public: - Element_Selector(ParserState pstate, std::string n) + Type_Selector(ParserState pstate, std::string n) : Simple_Selector(pstate, n) - { } - Element_Selector(const Element_Selector* ptr) + { simple_type(TYPE_SEL); } + Type_Selector(const Type_Selector* ptr) : Simple_Selector(ptr) - { } + { simple_type(TYPE_SEL); } unsigned long specificity() const override { if (name() == "*") return 0; @@ -313,11 +340,11 @@ namespace Sass { } Simple_Selector_Ptr unify_with(Simple_Selector_Ptr); Compound_Selector_Ptr unify_with(Compound_Selector_Ptr) override; - bool operator==(const Simple_Selector& rhs) const override; - bool operator==(const Element_Selector& rhs) const; - bool operator<(const Simple_Selector& rhs) const override; - bool operator<(const Element_Selector& rhs) const; - ATTACH_AST_OPERATIONS(Element_Selector) + bool operator<(const Simple_Selector& rhs) const final override; + bool operator==(const Simple_Selector& rhs) const final override; + bool operator<(const Type_Selector& rhs) const; + bool operator==(const Type_Selector& rhs) const; + ATTACH_AST_OPERATIONS(Type_Selector) ATTACH_CRTP_PERFORM_METHODS() }; @@ -328,10 +355,10 @@ namespace Sass { public: Class_Selector(ParserState pstate, std::string n) : Simple_Selector(pstate, n) - { } + { simple_type(CLASS_SEL); } Class_Selector(const Class_Selector* ptr) : Simple_Selector(ptr) - { } + { simple_type(CLASS_SEL); } unsigned long specificity() const override { return Constants::Specificity_Class; @@ -341,6 +368,10 @@ namespace Sass { return Constants::UnificationOrder_Class; } Compound_Selector_Ptr unify_with(Compound_Selector_Ptr) override; + bool operator<(const Simple_Selector& rhs) const final override; + bool operator==(const Simple_Selector& rhs) const final override; + bool operator<(const Class_Selector& rhs) const; + bool operator==(const Class_Selector& rhs) const; ATTACH_AST_OPERATIONS(Class_Selector) ATTACH_CRTP_PERFORM_METHODS() }; @@ -352,10 +383,10 @@ namespace Sass { public: Id_Selector(ParserState pstate, std::string n) : Simple_Selector(pstate, n) - { } + { simple_type(ID_SEL); } Id_Selector(const Id_Selector* ptr) : Simple_Selector(ptr) - { } + { simple_type(ID_SEL); } unsigned long specificity() const override { return Constants::Specificity_ID; @@ -365,6 +396,10 @@ namespace Sass { return Constants::UnificationOrder_Id; } Compound_Selector_Ptr unify_with(Compound_Selector_Ptr) override; + bool operator<(const Simple_Selector& rhs) const final override; + bool operator==(const Simple_Selector& rhs) const final override; + bool operator<(const Id_Selector& rhs) const; + bool operator==(const Id_Selector& rhs) const; ATTACH_AST_OPERATIONS(Id_Selector) ATTACH_CRTP_PERFORM_METHODS() }; @@ -380,13 +415,13 @@ namespace Sass { public: Attribute_Selector(ParserState pstate, std::string n, std::string m, String_Obj v, char o = 0) : Simple_Selector(pstate, n), matcher_(m), value_(v), modifier_(o) - { simple_type(ATTR_SEL); } + { simple_type(ATTRIBUTE_SEL); } Attribute_Selector(const Attribute_Selector* ptr) : Simple_Selector(ptr), matcher_(ptr->matcher_), value_(ptr->value_), modifier_(ptr->modifier_) - { simple_type(ATTR_SEL); } + { simple_type(ATTRIBUTE_SEL); } size_t hash() const override { if (hash_ == 0) { @@ -404,10 +439,10 @@ namespace Sass { { return Constants::UnificationOrder_Attribute; } - bool operator==(const Simple_Selector& rhs) const override; - bool operator==(const Attribute_Selector& rhs) const; - bool operator<(const Simple_Selector& rhs) const override; + bool operator<(const Simple_Selector& rhs) const final override; + bool operator==(const Simple_Selector& rhs) const final override; bool operator<(const Attribute_Selector& rhs) const; + bool operator==(const Attribute_Selector& rhs) const; ATTACH_AST_OPERATIONS(Attribute_Selector) ATTACH_CRTP_PERFORM_METHODS() }; @@ -471,10 +506,10 @@ namespace Sass { return Constants::UnificationOrder_PseudoElement; return Constants::UnificationOrder_PseudoClass; } - bool operator==(const Simple_Selector& rhs) const override; - bool operator==(const Pseudo_Selector& rhs) const; - bool operator<(const Simple_Selector& rhs) const override; + bool operator<(const Simple_Selector& rhs) const final override; + bool operator==(const Simple_Selector& rhs) const final override; bool operator<(const Pseudo_Selector& rhs) const; + bool operator==(const Pseudo_Selector& rhs) const; Compound_Selector_Ptr unify_with(Compound_Selector_Ptr) override; ATTACH_AST_OPERATIONS(Pseudo_Selector) ATTACH_CRTP_PERFORM_METHODS() @@ -505,10 +540,10 @@ namespace Sass { return Constants::UnificationOrder_Wrapped; } bool find ( bool (*f)(AST_Node_Obj) ) override; - bool operator==(const Simple_Selector& rhs) const override; - bool operator==(const Wrapped_Selector& rhs) const; - bool operator<(const Simple_Selector& rhs) const override; + bool operator<(const Simple_Selector& rhs) const final override; + bool operator==(const Simple_Selector& rhs) const final override; bool operator<(const Wrapped_Selector& rhs) const; + bool operator==(const Wrapped_Selector& rhs) const; void cloneChildren() override; ATTACH_AST_OPERATIONS(Wrapped_Selector) ATTACH_CRTP_PERFORM_METHODS() @@ -564,7 +599,7 @@ namespace Sass { Simple_Selector_Ptr base() const { if (length() == 0) return 0; // ToDo: why is this needed? - if (Cast((*this)[0])) + if (Cast((*this)[0])) return (*this)[0]; return 0; } @@ -607,11 +642,17 @@ namespace Sass { } bool find ( bool (*f)(AST_Node_Obj) ) override; + bool operator<(const Selector& rhs) const override; bool operator==(const Selector& rhs) const override; + bool operator<(const Selector_List& rhs) const; + bool operator==(const Selector_List& rhs) const; + bool operator<(const Complex_Selector& rhs) const; + bool operator==(const Complex_Selector& rhs) const; bool operator<(const Compound_Selector& rhs) const; bool operator==(const Compound_Selector& rhs) const; - inline bool operator!=(const Compound_Selector& rhs) const { return !(*this == rhs); } + bool operator<(const Simple_Selector& rhs) const; + bool operator==(const Simple_Selector& rhs) const; ComplexSelectorSet& sources() { return sources_; } void clearSources() { sources_.clear(); } @@ -658,6 +699,11 @@ namespace Sass { head_(ptr->head_), tail_(ptr->tail_), reference_(ptr->reference_) {}; + bool empty() const { + return (!tail() || tail()->empty()) + && (!head() || head()->empty()) + && combinator_ == ANCESTOR_OF; + } bool has_parent_ref() const override; bool has_real_parent_ref() const override; @@ -733,11 +779,18 @@ namespace Sass { return false; } bool find ( bool (*f)(AST_Node_Obj) ) override; + bool operator<(const Selector& rhs) const override; bool operator==(const Selector& rhs) const override; + bool operator<(const Selector_List& rhs) const; + bool operator==(const Selector_List& rhs) const; bool operator<(const Complex_Selector& rhs) const; bool operator==(const Complex_Selector& rhs) const; - inline bool operator!=(const Complex_Selector& rhs) const { return !(*this == rhs); } + bool operator<(const Compound_Selector& rhs) const; + bool operator==(const Compound_Selector& rhs) const; + bool operator<(const Simple_Selector& rhs) const; + bool operator==(const Simple_Selector& rhs) const; + const ComplexSelectorSet sources() { //s = Set.new @@ -866,7 +919,14 @@ namespace Sass { bool operator==(const Selector& rhs) const override; bool operator<(const Selector_List& rhs) const; bool operator==(const Selector_List& rhs) const; + bool operator<(const Complex_Selector& rhs) const; + bool operator==(const Complex_Selector& rhs) const; + bool operator<(const Compound_Selector& rhs) const; + bool operator==(const Compound_Selector& rhs) const; + bool operator<(const Simple_Selector& rhs) const; + bool operator==(const Simple_Selector& rhs) const; // Selector Lists can be compared to comma lists + bool operator<(const Expression& rhs) const override; bool operator==(const Expression& rhs) const override; void cloneChildren() override; ATTACH_AST_OPERATIONS(Selector_List) diff --git a/src/ast_values.hpp b/src/ast_values.hpp index 21285c3c0..2c029a268 100644 --- a/src/ast_values.hpp +++ b/src/ast_values.hpp @@ -39,7 +39,7 @@ namespace Sass { class PreValue : public Expression { public: PreValue(ParserState pstate, - bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE) + bool d = false, bool e = false, bool i = false, Type ct = NONE) : Expression(pstate, d, e, i, ct) { } PreValue(const PreValue* ptr) @@ -55,7 +55,7 @@ namespace Sass { class Value : public PreValue { public: Value(ParserState pstate, - bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE) + bool d = false, bool e = false, bool i = false, Type ct = NONE) : PreValue(pstate, d, e, i, ct) { } Value(const Value* ptr) @@ -530,7 +530,7 @@ namespace Sass { static std::string type_name() { return "string"; } virtual ~String() = 0; virtual void rtrim() = 0; - virtual bool operator<(const Expression& rhs) const { + virtual bool operator<(const Expression& rhs) const override { return this->to_string() < rhs.to_string(); }; ATTACH_VIRTUAL_AST_OPERATIONS(String); diff --git a/src/debugger.hpp b/src/debugger.hpp index d1af42639..ec774bcda 100644 --- a/src/debugger.hpp +++ b/src/debugger.hpp @@ -235,9 +235,9 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; - } else if (Cast(node)) { - Element_Selector_Ptr selector = Cast(node); - std::cerr << ind << "Element_Selector " << selector; + } else if (Cast(node)) { + Type_Selector_Ptr selector = Cast(node); + std::cerr << ind << "Type_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " <<" << selector->ns_name() << ">>"; @@ -682,21 +682,21 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << ind << "Expression " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; switch (expression->concrete_type()) { - case Expression::Concrete_Type::NONE: std::cerr << " [NONE]"; break; - case Expression::Concrete_Type::BOOLEAN: std::cerr << " [BOOLEAN]"; break; - case Expression::Concrete_Type::NUMBER: std::cerr << " [NUMBER]"; break; - case Expression::Concrete_Type::COLOR: std::cerr << " [COLOR]"; break; - case Expression::Concrete_Type::STRING: std::cerr << " [STRING]"; break; - case Expression::Concrete_Type::LIST: std::cerr << " [LIST]"; break; - case Expression::Concrete_Type::MAP: std::cerr << " [MAP]"; break; - case Expression::Concrete_Type::SELECTOR: std::cerr << " [SELECTOR]"; break; - case Expression::Concrete_Type::NULL_VAL: std::cerr << " [NULL_VAL]"; break; - case Expression::Concrete_Type::C_WARNING: std::cerr << " [C_WARNING]"; break; - case Expression::Concrete_Type::C_ERROR: std::cerr << " [C_ERROR]"; break; - case Expression::Concrete_Type::FUNCTION: std::cerr << " [FUNCTION]"; break; - case Expression::Concrete_Type::NUM_TYPES: std::cerr << " [NUM_TYPES]"; break; - case Expression::Concrete_Type::VARIABLE: std::cerr << " [VARIABLE]"; break; - case Expression::Concrete_Type::FUNCTION_VAL: std::cerr << " [FUNCTION_VAL]"; break; + case Expression::Type::NONE: std::cerr << " [NONE]"; break; + case Expression::Type::BOOLEAN: std::cerr << " [BOOLEAN]"; break; + case Expression::Type::NUMBER: std::cerr << " [NUMBER]"; break; + case Expression::Type::COLOR: std::cerr << " [COLOR]"; break; + case Expression::Type::STRING: std::cerr << " [STRING]"; break; + case Expression::Type::LIST: std::cerr << " [LIST]"; break; + case Expression::Type::MAP: std::cerr << " [MAP]"; break; + case Expression::Type::SELECTOR: std::cerr << " [SELECTOR]"; break; + case Expression::Type::NULL_VAL: std::cerr << " [NULL_VAL]"; break; + case Expression::Type::C_WARNING: std::cerr << " [C_WARNING]"; break; + case Expression::Type::C_ERROR: std::cerr << " [C_ERROR]"; break; + case Expression::Type::FUNCTION: std::cerr << " [FUNCTION]"; break; + case Expression::Type::NUM_TYPES: std::cerr << " [NUM_TYPES]"; break; + case Expression::Type::VARIABLE: std::cerr << " [VARIABLE]"; break; + case Expression::Type::FUNCTION_VAL: std::cerr << " [FUNCTION_VAL]"; break; case Expression::Type::PARENT: std::cerr << " [PARENT]"; break; } std::cerr << std::endl; diff --git a/src/eval.cpp b/src/eval.cpp index 306088f06..44e0e49e1 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -745,8 +745,8 @@ namespace Sass { AST_Node_Obj lu = lhs; AST_Node_Obj ru = rhs; - Expression::Concrete_Type l_type; - Expression::Concrete_Type r_type; + Expression::Type l_type; + Expression::Type r_type; // Is one of the operands an interpolant? String_Schema_Obj s1 = Cast(b->left()); diff --git a/src/eval.hpp b/src/eval.hpp index 741472e81..3ba431a85 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -87,7 +87,7 @@ namespace Sass { Id_Selector_Ptr operator()(Id_Selector_Ptr s) { return s; }; Class_Selector_Ptr operator()(Class_Selector_Ptr s) { return s; }; Pseudo_Selector_Ptr operator()(Pseudo_Selector_Ptr s) { return s; }; - Element_Selector_Ptr operator()(Element_Selector_Ptr s) { return s; }; + Type_Selector_Ptr operator()(Type_Selector_Ptr s) { return s; }; Attribute_Selector_Ptr operator()(Attribute_Selector_Ptr s) { return s; }; Placeholder_Selector_Ptr operator()(Placeholder_Selector_Ptr s) { return s; }; diff --git a/src/extend.cpp b/src/extend.cpp index e2a1309db..86c201aa4 100644 --- a/src/extend.cpp +++ b/src/extend.cpp @@ -283,7 +283,7 @@ namespace Sass { static bool parentSuperselector(Complex_Selector_Ptr pOne, Complex_Selector_Ptr pTwo) { // TODO: figure out a better way to create a Complex_Selector from scratch // TODO: There's got to be a better way. This got ugly quick... - Element_Selector_Obj fakeParent = SASS_MEMORY_NEW(Element_Selector, ParserState("[FAKE]"), "temp"); + Type_Selector_Obj fakeParent = SASS_MEMORY_NEW(Type_Selector, ParserState("[FAKE]"), "temp"); Compound_Selector_Obj fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[FAKE]"), 1 /*size*/); fakeHead->elements().push_back(fakeParent); Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, fakeHead /*head*/, {} /*tail*/); @@ -643,7 +643,7 @@ namespace Sass { static bool parentSuperselector(const Node& one, const Node& two) { // TODO: figure out a better way to create a Complex_Selector from scratch // TODO: There's got to be a better way. This got ugly quick... - Element_Selector_Obj fakeParent = SASS_MEMORY_NEW(Element_Selector, ParserState("[FAKE]"), "temp"); + Type_Selector_Obj fakeParent = SASS_MEMORY_NEW(Type_Selector, ParserState("[FAKE]"), "temp"); Compound_Selector_Obj fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[FAKE]"), 1 /*size*/); fakeHead->elements().push_back(fakeParent); Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, fakeHead /*head*/, {} /*tail*/); @@ -1943,7 +1943,7 @@ namespace Sass { // special case for ruby ass if (sl->empty()) { // this seems inconsistent but it is how ruby sass seems to remove parentheses - cpy_head->append(SASS_MEMORY_NEW(Element_Selector, hs->pstate(), ws->name())); + cpy_head->append(SASS_MEMORY_NEW(Type_Selector, hs->pstate(), ws->name())); } // has wrapped not selectors else if (ws->name() == ":not") { diff --git a/src/fn_selectors.cpp b/src/fn_selectors.cpp index 31388612a..37663a40c 100644 --- a/src/fn_selectors.cpp +++ b/src/fn_selectors.cpp @@ -128,7 +128,7 @@ namespace Sass { } // Cannot be a Universal selector - Element_Selector_Obj pType = Cast(childSeq->head()->first()); + Type_Selector_Obj pType = Cast(childSeq->head()->first()); if(pType && pType->name() == "*") { std::string msg("Can't append \""); msg += childSeq->to_string(); diff --git a/src/inspect.cpp b/src/inspect.cpp index b56fd89aa..2fb04a78c 100644 --- a/src/inspect.cpp +++ b/src/inspect.cpp @@ -924,7 +924,7 @@ namespace Sass { } - void Inspect::operator()(Element_Selector_Ptr s) + void Inspect::operator()(Type_Selector_Ptr s) { append_token(s->ns_name(), s); } diff --git a/src/inspect.hpp b/src/inspect.hpp index 774290d3f..223be17ce 100644 --- a/src/inspect.hpp +++ b/src/inspect.hpp @@ -79,7 +79,7 @@ namespace Sass { // selectors virtual void operator()(Selector_Schema_Ptr); virtual void operator()(Placeholder_Selector_Ptr); - virtual void operator()(Element_Selector_Ptr); + virtual void operator()(Type_Selector_Ptr); virtual void operator()(Class_Selector_Ptr); virtual void operator()(Id_Selector_Ptr); virtual void operator()(Attribute_Selector_Ptr); diff --git a/src/operation.hpp b/src/operation.hpp index 977a5d1c5..71e13dcf9 100644 --- a/src/operation.hpp +++ b/src/operation.hpp @@ -103,7 +103,7 @@ namespace Sass { // selectors virtual T operator()(Selector_Schema_Ptr x) = 0; virtual T operator()(Placeholder_Selector_Ptr x) = 0; - virtual T operator()(Element_Selector_Ptr x) = 0; + virtual T operator()(Type_Selector_Ptr x) = 0; virtual T operator()(Class_Selector_Ptr x) = 0; virtual T operator()(Id_Selector_Ptr x) = 0; virtual T operator()(Attribute_Selector_Ptr x) = 0; @@ -184,7 +184,7 @@ namespace Sass { // selectors T operator()(Selector_Schema_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Placeholder_Selector_Ptr x) { return static_cast(this)->fallback(x); } - T operator()(Element_Selector_Ptr x) { return static_cast(this)->fallback(x); } + T operator()(Type_Selector_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Class_Selector_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Id_Selector_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Attribute_Selector_Ptr x) { return static_cast(this)->fallback(x); } diff --git a/src/parser.cpp b/src/parser.cpp index 3cdf0a99e..04937034a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -851,7 +851,7 @@ namespace Sass { // parse type selector else if (lex< re_type_selector >(false)) { - seq->append(SASS_MEMORY_NEW(Element_Selector, pstate, lexed)); + seq->append(SASS_MEMORY_NEW(Type_Selector, pstate, lexed)); } // peek for abort conditions else if (peek< spaces >()) break; @@ -886,7 +886,7 @@ namespace Sass { return SASS_MEMORY_NEW(Id_Selector, pstate, lexed); } else if (lex< alternatives < variable, number, static_reference_combinator > >()) { - return SASS_MEMORY_NEW(Element_Selector, pstate, lexed); + return SASS_MEMORY_NEW(Type_Selector, pstate, lexed); } else if (peek< pseudo_not >()) { return parse_negated_selector();