Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Selector Functions #1261

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions ast.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "ast.hpp"
#include "context.hpp"
#include "node.hpp"
#include "extend.hpp"
#include "to_string.hpp"
#include <set>
#include <algorithm>
Expand Down Expand Up @@ -420,6 +422,43 @@ namespace Sass {
// catch-all
return false;
}

Selector_List* Complex_Selector::unify_with(Complex_Selector* other, Context& ctx) {
To_String to_string;

Compound_Selector* thisBase = base();
Compound_Selector* rhsBase = other->base();

if( thisBase == 0 || rhsBase == 0 ) return 0;

// Not sure about this check, but closest way I could check to see if this is a ruby 'SimpleSequence' equivalent
if( tail()->combinator() != Combinator::ANCESTOR_OF || other->tail()->combinator() != Combinator::ANCESTOR_OF ) return 0;

Compound_Selector* unified = rhsBase->unify_with(thisBase, ctx);
if( unified == 0 ) return 0;

Node lhsNode = complexSelectorToNode(this, ctx);
Node rhsNode = complexSelectorToNode(other, ctx);

// Create a temp Complex_Selector, turn it into a Node, and combine it with the existing RHS node
Complex_Selector* fakeComplexSelector = new (ctx.mem) Complex_Selector(ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, unified, NULL);
Node unifiedNode = complexSelectorToNode(fakeComplexSelector, ctx);
rhsNode.plus(unifiedNode);

Node node = Extend::subweave(lhsNode, rhsNode, ctx);

Selector_List* result = new (ctx.mem) Selector_List(pstate());
for (NodeDeque::iterator iter = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
Node childNode = *iter;
childNode = Node::naiveTrim(childNode, ctx);

Complex_Selector* childNodeAsComplexSelector = nodeToComplexSelector(childNode, ctx);
if( childNodeAsComplexSelector ) { (*result) << childNodeAsComplexSelector; }
}

return result->length() ? result : 0;
}


size_t Complex_Selector::length()
{
Expand Down Expand Up @@ -558,6 +597,69 @@ namespace Sass {
}
return false;
}

Selector_List* Selector_List::unify_with(Selector_List* rhs, Context& ctx) {

vector<Complex_Selector*> unified_complex_selectors;
// Unify all of children with RHS's children, storing the results in `unified_complex_selectors`
for (size_t lhs_i = 0, lhs_L = length(); lhs_i < lhs_L; ++lhs_i) {
Complex_Selector* seq1 = (*this)[lhs_i];
for(size_t rhs_i = 0, rhs_L = rhs->length(); rhs_i < rhs_L; ++rhs_i) {
Complex_Selector* seq2 = (*rhs)[rhs_i];

Selector_List* result = seq1->unify_with(seq2, ctx);
if( result ) {
for(size_t i = 0, L = result->length(); i < L; ++i) {
unified_complex_selectors.push_back( (*result)[i] );
}
}
}
}

// Creates the final Selector_List by combining all the complex selectors
Selector_List* final_result = new (ctx.mem) Selector_List(pstate());
for (auto itr = unified_complex_selectors.begin(); itr != unified_complex_selectors.end(); ++itr) {
*final_result << *itr;
}

return final_result;
}

void Selector_List::populate_extends(Selector_List* extendee, Context& ctx, ExtensionSubsetMap& extends) {
To_String to_string;

Selector_List* extender = this;
for (auto complex_sel : extendee->elements()) {
Complex_Selector* c = complex_sel;


// Ignore any parent selectors, until we find the first non Selector_Reference head
Compound_Selector* compound_sel = c->head();
Complex_Selector* pIter = complex_sel;
while (pIter) {
Compound_Selector* pHead = pIter->head();
if (pHead && dynamic_cast<Selector_Reference*>(pHead->elements()[0]) == NULL) {
compound_sel = pHead;
break;
}

pIter = pIter->tail();
}

if (!pIter->head() || pIter->tail()) {
error("nested selectors may not be extended", c->pstate());
}

compound_sel->is_optional(extendee->is_optional());

for (size_t i = 0, L = extender->length(); i < L; ++i) {
// let's test this out
cerr << "REGISTERING EXTENSION REQUEST: " << (*extender)[i]->perform(&to_string) << " <- " << compound_sel->perform(&to_string) << endl;
extends.put(compound_sel->to_str_vec(), make_pair((*extender)[i], compound_sel));
}
}
};


/* not used anymore - remove?
Selector_Placeholder* Selector_List::find_placeholder()
Expand Down
10 changes: 10 additions & 0 deletions ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ namespace Sass {
size_t length() const { return elements_.size(); }
bool empty() const { return elements_.empty(); }
T last() { return elements_.back(); }
T first() { return elements_.front(); }
T& operator[](size_t i) { return elements_[i]; }
const T& operator[](size_t i) const { return elements_[i]; }
Vectorized& operator<<(T element)
Expand Down Expand Up @@ -2006,6 +2007,9 @@ namespace Sass {
bool is_superselector_of(Complex_Selector* sub);
bool is_superselector_of(Selector_List* sub);
// virtual Selector_Placeholder* find_placeholder();

Selector_List* unify_with(Complex_Selector* rhs, Context& ctx);

Combinator clear_innermost();
void set_innermost(Complex_Selector*, Combinator);
virtual unsigned long specificity() const
Expand Down Expand Up @@ -2074,6 +2078,8 @@ namespace Sass {

typedef deque<Complex_Selector*> ComplexSelectorDeque;

typedef Subset_Map<string, pair<Complex_Selector*, Compound_Selector*> > ExtensionSubsetMap;

///////////////////////////////////
// Comma-separated selector groups.
///////////////////////////////////
Expand All @@ -2092,6 +2098,10 @@ namespace Sass {
bool is_superselector_of(Compound_Selector* sub);
bool is_superselector_of(Complex_Selector* sub);
bool is_superselector_of(Selector_List* sub);

Selector_List* unify_with(Selector_List*, Context&);
void populate_extends(Selector_List*, Context&, ExtensionSubsetMap&);

virtual unsigned long specificity()
{
unsigned long sum = 0;
Expand Down
7 changes: 7 additions & 0 deletions context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,14 @@ namespace Sass {
register_function(ctx, inspect_sig, inspect, env);
register_function(ctx, unique_id_sig, unique_id, env);
// Selector functions
register_function(ctx, selector_nest_sig, selector_nest, env);
register_function(ctx, selector_append_sig, selector_append, env);
register_function(ctx, selector_extend_sig, selector_extend, env);
register_function(ctx, selector_replace_sig, selector_replace, env);
register_function(ctx, selector_unify_sig, selector_unify, env);
register_function(ctx, is_superselector_sig, is_superselector, env);
register_function(ctx, simple_selectors_sig, simple_selectors, env);
register_function(ctx, selector_parse_sig, selector_parse, env);
}

void register_c_functions(Context& ctx, Env* env, Sass_Function_List descrs)
Expand Down
13 changes: 8 additions & 5 deletions extend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,7 @@ namespace Sass {
result
end
*/
static Node subweave(Node& one, Node& two, Context& ctx) {
Node Extend::subweave(Node& one, Node& two, Context& ctx) {
// Check for the simple cases
if (one.collection()->size() == 0) {
Node out = Node::createCollection();
Expand Down Expand Up @@ -1423,7 +1423,7 @@ namespace Sass {
for (NodeDeque::iterator beforesIter = befores.collection()->begin(), beforesEndIter = befores.collection()->end(); beforesIter != beforesEndIter; beforesIter++) {
Node& before = *beforesIter;

Node sub = subweave(before, current, ctx);
Node sub = Extend::subweave(before, current, ctx);

DEBUG_PRINTLN(WEAVE, "SUB: " << sub)

Expand Down Expand Up @@ -1854,7 +1854,7 @@ namespace Sass {
/*
This is the equivalent of ruby's CommaSequence.do_extend.
*/
static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subsetMap, bool& extendedSomething) {
Selector_List* Extend::extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subsetMap, bool isReplace, bool& extendedSomething) {

To_String to_string(&ctx);

Expand Down Expand Up @@ -1886,7 +1886,10 @@ namespace Sass {
}
}

for (NodeDeque::iterator iterator = extendedSelectors.collection()->begin(), iteratorEnd = extendedSelectors.collection()->end(); iterator != iteratorEnd; ++iterator) {
for (NodeDeque::iterator iterator = extendedSelectors.collection()->begin(), iteratorBegin = extendedSelectors.collection()->begin(), iteratorEnd = extendedSelectors.collection()->end(); iterator != iteratorEnd; ++iterator) {
// When it is a replace, skip the first one, unless there is only one
if(isReplace && iterator == iteratorBegin && extendedSelectors.collection()->size() > 1 ) continue;

Node& childNode = *iterator;
*pNewSelectors << nodeToComplexSelector(childNode, ctx);
}
Expand Down Expand Up @@ -1943,7 +1946,7 @@ namespace Sass {
}

bool extendedSomething = false;
Selector_List* pNewSelectorList = extendSelectorList(static_cast<Selector_List*>(pObject->selector()), ctx, subsetMap, extendedSomething);
Selector_List* pNewSelectorList = Extend::extendSelectorList(static_cast<Selector_List*>(pObject->selector()), ctx, subsetMap, false, extendedSomething);

if (extendedSomething && pNewSelectorList) {
DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << static_cast<Selector_List*>(pObject->selector())->perform(&to_string))
Expand Down
4 changes: 4 additions & 0 deletions extend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace Sass {
using namespace std;

class Context;
class Node;

typedef Subset_Map<string, pair<Complex_Selector*, Compound_Selector*> > ExtensionSubsetMap;

Expand All @@ -38,6 +39,9 @@ namespace Sass {

template <typename U>
void fallback(U x) { return fallback_impl(x); }

static Node subweave(Node& one, Node& two, Context& ctx);
static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subsetMap, bool isReplace, bool& extendedSomething);
};

}
Expand Down
Loading