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 #1064

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
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
129 changes: 129 additions & 0 deletions ast.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include "ast.hpp"
#include "context.hpp"
#include "contextualize.hpp"
#include "node.hpp"
#include "sass_util.hpp"
#include "extend.hpp"
#include "to_string.hpp"
#include <set>
#include <algorithm>
Expand Down Expand Up @@ -492,6 +496,131 @@ namespace Sass {
this->mCachedSelector(this->perform(&to_string));
#endif
}


// For every selector in RHS, see if we have /any/ selectors which are a super-selector of it
bool Selector_List::is_superselector_of(Sass::Selector_List *rhs) {
// For every selector in RHS, see if it matches /any/ of our selectors
for(size_t rhs_i = 0, rhs_L = rhs->length(); rhs_i < rhs_L; ++rhs_i) {
Complex_Selector* seq1 = (*rhs)[rhs_i];
bool any = false;
for (size_t lhs_i = 0, lhs_L = length(); lhs_i < lhs_L; ++lhs_i) {
Complex_Selector* seq2 = (*this)[lhs_i];
bool is_superselector = seq2->is_superselector_of(seq1);
if( is_superselector ) {
any = true;
break;
}
}

// Seq1 did not match any of our selectors - whole thing is no good, abort
if(!any) {
return false;
}
}
return true;
}

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debug code?

extends.put(compound_sel->to_str_vec(), make_pair((*extender)[i], compound_sel));
}
}
};


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::StaticSubweave(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;
}



/* not used anymore - remove?
Selector_Placeholder* Selector_List::find_placeholder()
Expand Down
13 changes: 12 additions & 1 deletion ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,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 @@ -633,9 +634,11 @@ namespace Sass {
// by a type tag.
/////////////////////////////////////////////////////////////////////////////
struct Backtrace;
class Contextualize;
typedef Environment<AST_Node*> Env;
typedef const char* Signature;
typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*);
typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Contextualize*, Backtrace*);
// typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Contextualize*, Backtrace*);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove please

typedef const char* Signature;
class Definition : public Has_Block {
public:
Expand Down Expand Up @@ -2081,6 +2084,8 @@ namespace Sass {
size_t length();
bool is_superselector_of(Compound_Selector*);
bool is_superselector_of(Complex_Selector*);
Selector_List* unify_with(Complex_Selector* rhs, Context& ctx);

// virtual Selector_Placeholder* find_placeholder();
Combinator clear_innermost();
void set_innermost(Complex_Selector*, Combinator);
Expand Down Expand Up @@ -2149,6 +2154,8 @@ namespace Sass {
};

typedef deque<Complex_Selector*> ComplexSelectorDeque;

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

///////////////////////////////////
// Comma-separated selector groups.
Expand All @@ -2165,6 +2172,10 @@ namespace Sass {
: Selector(pstate), Vectorized<Complex_Selector*>(s), wspace_(0)
{ }
// virtual Selector_Placeholder* find_placeholder();
bool is_superselector_of(Selector_List* other);
Selector_List* unify_with(Selector_List*, Context&);
void populate_extends(Selector_List*, Context&, ExtensionSubsetMap&);

virtual unsigned long specificity()
{
unsigned long sum = 0;
Expand Down
9 changes: 9 additions & 0 deletions context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,15 @@ namespace Sass {
// Misc Functions
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
6 changes: 3 additions & 3 deletions eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ namespace Sass {
Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
backtrace = &here;

result = func(*env, *old_env, ctx, def->signature(), c->pstate(), backtrace);
result = func(*env, *old_env, ctx, def->signature(), c->pstate(), contextualize, backtrace);

backtrace = here.parent;
env = old_env;
Expand Down Expand Up @@ -624,7 +624,7 @@ namespace Sass {
} else if (sass_value_get_tag(c_val) == SASS_WARNING) {
error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), backtrace);
}
result = cval_to_astnode(c_val, ctx, backtrace, c->pstate());
result = cval_to_astnode(c_val, ctx, backtrace, c->pstate ());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undo this change please


backtrace = here.parent;
sass_delete_value(c_args);
Expand All @@ -650,7 +650,7 @@ namespace Sass {
Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
backtrace = &here;

result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->pstate(), backtrace);
result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->pstate(), contextualize, backtrace);

backtrace = here.parent;
env = old_env;
Expand Down
5 changes: 4 additions & 1 deletion expand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ namespace Sass {
String* old_p = d->property();
String* new_p = static_cast<String*>(old_p->perform(eval->with(env, backtrace)));
Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back();

// Contextualize_Eval* contextual = contextualize_eval->with(selector_stack.back(), env, backtrace);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove please


Expression* value = d->value()->perform(eval->with(p, env, backtrace));
if (value->is_invisible() && !d->is_important()) return 0;
Declaration* decl = new (ctx.mem) Declaration(d->pstate(),
Expand Down Expand Up @@ -493,7 +496,7 @@ namespace Sass {
// { target_vec.push_back((*compound_sel)[i]->perform(&to_string)); }
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;
cerr << "REGISTERING EXTENSION REQUEST: " << (*extender)[i]->perform(&to_string) << " <- " << compound_sel->perform(&to_string) << endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debug code?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is not my own, it's from the code base, but is commented out. I re-comment it out

ctx.subset_map.put(compound_sel->to_str_vec(), make_pair((*extender)[i], compound_sel));
}
}
Expand Down
Loading