Permalink
Browse files

Working on selector normalization and ordering.

  • Loading branch information...
1 parent 4e8099a commit 2e2d97a8483ea88c6b0feec57333a45f8ae9b041 Aaron Leung committed Oct 11, 2012
Showing with 175 additions and 16 deletions.
  1. +1 −1 Makefile
  2. +1 −1 Makefile.am
  3. +3 −2 Makefile.in
  4. +11 −2 eval_apply.cpp
  5. +49 −10 node.cpp
  6. +97 −0 selector.cpp
  7. +13 −0 selector.hpp
View
@@ -5,7 +5,7 @@ SOURCES = \
constants.cpp context.cpp functions.cpp document.cpp \
document_parser.cpp eval_apply.cpp node.cpp \
node_factory.cpp node_emitters.cpp prelexer.cpp \
- sass_interface.cpp
+ selector.cpp sass_interface.cpp
OBJECTS = $(SOURCES:.cpp=.o)
all: $(OBJECTS)
View
@@ -4,7 +4,7 @@ lib_LTLIBRARIES = libsass.la
libsass_la_SOURCES = context.cpp functions.cpp document.cpp \
constants.cpp document_parser.cpp eval_apply.cpp node.cpp \
node_factory.cpp node_emitters.cpp prelexer.cpp \
- sass_interface.cpp
+ selector.cpp sass_interface.cpp
libsass_la_LDFLAGS = -no-undefined -version-info 0:0:0
include_HEADERS = sass_interface.h
View
@@ -86,7 +86,7 @@ LTLIBRARIES = $(lib_LTLIBRARIES)
libsass_la_LIBADD =
am_libsass_la_OBJECTS = context.lo functions.lo document.lo \
constants.lo document_parser.lo eval_apply.lo node.lo node_factory.lo \
- node_emitters.lo prelexer.lo sass_interface.lo
+ node_emitters.lo prelexer.lo selector.lo sass_interface.lo
libsass_la_OBJECTS = $(am_libsass_la_OBJECTS)
libsass_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
@@ -247,7 +247,7 @@ lib_LTLIBRARIES = libsass.la
libsass_la_SOURCES = context.cpp functions.cpp document.cpp \
constants.cpp document_parser.cpp eval_apply.cpp node.cpp \
node_factory.cpp node_emitters.cpp prelexer.cpp \
- sass_interface.cpp
+ selector.cpp sass_interface.cpp
libsass_la_LDFLAGS = -no-undefined -version-info 0:0:0
include_HEADERS = sass_interface.h
@@ -355,6 +355,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_emitters.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_factory.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prelexer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selector.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sass_interface.Plo@am__quote@
.cpp.o:
View
@@ -1,4 +1,5 @@
#include "eval_apply.hpp"
+#include "selector.hpp"
#include "constants.hpp"
#include "prelexer.hpp"
#include "document.hpp"
@@ -106,6 +107,8 @@ namespace Sass {
// }
// expand the body with the newly expanded selector as the prefix
+ cerr << "ORIGINAL SELECTOR:\t" << expr[2].to_string() << endl;
+ cerr << "NORMALIZED SELECTOR:\t" << normalize_selector(expr[2], new_Node).to_string() << endl << endl;
expand(expr[1], expr.back(), env, f_env, new_Node, ctx);
} break;
@@ -1112,8 +1115,11 @@ namespace Sass {
for (multimap<Node, Node>::iterator request = extension_requests.lower_bound(sel);
request != extension_requests.upper_bound(sel);
++request) {
- group << generate_extension(expr[2], request->second, new_Node);
+ Node ext(generate_extension(expr[2], request->second, new_Node));
+ if (ext.type() == Node::selector_group) group += ext;
+ else group << ext;
}
+ group = remove_duplicate_selectors(group, new_Node);
group.has_been_extended() = true;
expr[2] = group;
}
@@ -1132,13 +1138,16 @@ namespace Sass {
for (multimap<Node, Node>::iterator request = extension_requests.lower_bound(sel);
request != extension_requests.upper_bound(sel);
++request) {
- new_group << generate_extension(group[i], request->second, new_Node);
+ Node ext(generate_extension(group[i], request->second, new_Node));
+ if (ext.type() == Node::selector_group) new_group += ext;
+ else new_group << ext;
}
group[i].has_been_extended() = true;
}
}
if (new_group.size() > 0) {
group.has_been_extended() = true;
+ new_group = remove_duplicate_selectors(new_group, new_Node);
new_group.has_been_extended() = true;
expr[2] = new_group;
}
View
@@ -61,6 +61,19 @@ namespace Sass {
string Node::unquote() const
{
+ Type t = type();
+ switch (type())
+ {
+ case string_constant:
+ case identifier: {
+ return token().unquote();
+ } break;
+
+ default: {
+ // do nothing; fall though to the rest
+ } break;
+ }
+
string intermediate(to_string());
if (!intermediate.empty() && (intermediate[0] == '"' || intermediate[0] == '\'')) {
return intermediate.substr(1, intermediate.length() - 2);
@@ -74,8 +87,11 @@ namespace Sass {
{
Type t = type(), u = rhs.type();
- if ((t == identifier || t == string_constant || t == string_schema || t == concatenation) &&
- (u == identifier || u == string_constant || u == string_schema || u == concatenation)) {
+ // if ((t == identifier || t == string_constant || t == string_schema || t == concatenation) &&
+ // (u == identifier || u == string_constant || u == string_schema || u == concatenation)) {
+ // return unquote() == rhs.unquote();
+ // }
+ if (is_string() && rhs.is_string()) {
return unquote() == rhs.unquote();
}
else if (t != u) {
@@ -126,8 +142,25 @@ namespace Sass {
return boolean_value() == rhs.boolean_value();
} break;
+ case selector: {
+ if (has_children() && rhs.has_children() && (size() == rhs.size())) {
+ for (size_t i = 0, S = size(); i < S; ++i) {
+ if (at(i) == rhs[i]) continue;
+ else return false;
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+ } break;
+
+ case simple_selector: {
+ if (token() == rhs.token()) return true;
+ } break;
+
default: {
- return true;
+ return false;
} break;
}
return false;
@@ -163,12 +196,16 @@ namespace Sass {
}
// comparing identifiers and strings (treat them as comparable)
- else if ((lhs_type == identifier || lhs_type == string_constant || lhs_type == value) &&
- (rhs_type == identifier || lhs_type == string_constant || rhs_type == value)) {
- return token().unquote() < rhs.token().unquote();
+ else if (is_string() && rhs.is_string()) {
+ return unquote() < rhs.unquote();
}
- // COMPARING SELECTORS -- IMPORTANT FOR INHERITANCE
+ // else if ((lhs_type == identifier || lhs_type == string_constant || lhs_type == value) &&
+ // (rhs_type == identifier || lhs_type == string_constant || rhs_type == value)) {
+ // return token().unquote() < rhs.token().unquote();
+ // }
+
+ // COMPARING SELECTORS -- IMPORTANT FOR ORDERING AND NORMALIZING
else if ((type() >= selector_group && type() <=selector_schema) &&
(rhs.type() >= selector_group && rhs.type() <=selector_schema)) {
@@ -183,13 +220,15 @@ namespace Sass {
return token() < rhs.token();
} break;
+ // assumes selectors are normalized by the time they're compared
case selector:
- case attribute_selector: {
+ case simple_selector_sequence:
+ case attribute_selector:
+ case functional_pseudo:
+ case pseudo_not: {
return lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
} break;
-
-
default: {
return false;
} break;
View
@@ -0,0 +1,97 @@
+#include <set>
+
+#include "selector.hpp"
+
+namespace Sass {
+ using namespace std;
+
+ Node normalize_selector(Node s, Node_Factory& new_Node)
+ {
+ switch (s.type())
+ {
+ case Node::selector_group: {
+ Node normalized(new_Node(Node::selector_group, s.path(), s.line(), 1));
+ set<Node> normalizer;
+ for (size_t i = 0, S = s.size(); i < S; ++i)
+ normalizer.insert(normalize_selector(s[i], new_Node));
+ for (set<Node>::iterator i = normalizer.begin(); i != normalizer.end(); ++i)
+ normalized << *i;
+ return normalized;
+ } break;
+
+ case Node::selector: {
+ Node normalized(new_Node(Node::selector, s.path(), s.line(), s.size()));
+ for (size_t i = 0, S = s.size(); i < S; ++i)
+ normalized << normalize_selector(s[i], new_Node);
+ return normalized;
+ } break;
+
+ case Node::simple_selector_sequence: {
+ Node normalized(new_Node(Node::simple_selector_sequence, s.path(), s.line(), 1));
+ set<Node> normalizer;
+ size_t i = 0;
+ if (!selector_is_qualifier(s[0])) {
+ normalized << s[0];
+ i = 1;
+ }
+ for (size_t S = s.size(); i < S; ++i)
+ normalizer.insert(normalize_selector(s[i], new_Node));
+ for (set<Node>::iterator i = normalizer.begin(); i != normalizer.end(); ++i)
+ normalized << *i;
+ return normalized;
+ } break;
+
+ default: {
+ return s;
+ } break;
+ }
+ return s;
+ }
+
+ // Remove duplicate selectors from a selector group. Used when extending.
+ Node remove_duplicate_selectors(Node group, Node_Factory& new_Node)
+ {
+ if (group.type() != Node::selector_group) return group;
+
+ Node filtered(new_Node(Node::selector_group, group.path(), group.line(), 1));
+ for (size_t i = 0, S = group.size(); i < S; ++i) {
+ bool found_dup = false;
+ for (size_t j = 0; j < filtered.size(); ++j) {
+ if (group[i] == filtered[j]) {
+ found_dup = true;
+ break;
+ }
+ }
+ if (!found_dup) filtered << group[i];
+ }
+
+ return filtered;
+ }
+
+ bool selector_is_qualifier(Node s)
+ {
+ switch (s.type())
+ {
+ case Node::pseudo:
+ case Node::pseudo_negation:
+ case Node::functional_pseudo:
+ case Node::attribute_selector: {
+ return true;
+ } break;
+
+ case Node::simple_selector: {
+ if ((*s.token().begin == '.') || (*s.token().begin == '#')) return true;
+ } break;
+
+ default: {
+ return false;
+ } break;
+ }
+ return false;
+ }
+
+ // Node selector_is_specialization_of(Node s, Node t)
+ // {
+
+ // }
+}
View
@@ -0,0 +1,13 @@
+#ifndef SASS_NODE
+#include "node.hpp"
+#endif
+
+#ifndef SASS_NODE_FACTORY
+#include "node_factory.hpp"
+#endif
+
+namespace Sass {
+ Node normalize_selector(Node s, Node_Factory& new_Node);
+ Node remove_duplicate_selectors(Node group, Node_Factory& new_Node);
+ bool selector_is_qualifier(Node s);
+}

0 comments on commit 2e2d97a

Please sign in to comment.