Skip to content

Commit

Permalink
Implement selector-nest function [WIP]
Browse files Browse the repository at this point in the history
  • Loading branch information
mgreter committed Jun 4, 2015
1 parent 81a373b commit 006a63b
Show file tree
Hide file tree
Showing 5 changed files with 328 additions and 31 deletions.
235 changes: 215 additions & 20 deletions ast.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ast.hpp"
#include "context.hpp"
#include "debugger.hpp"
#include "to_string.hpp"
#include <set>
#include <algorithm>
Expand Down Expand Up @@ -220,18 +221,90 @@ namespace Sass {
return Simple_Selector::unify_with(rhs, ctx);
}

bool Compound_Selector::is_superselector_of(Compound_Selector* rhs)
bool Wrapped_Selector::is_superselector_of(Wrapped_Selector* sub)
{
if (this->name() != sub->name()) return false;
if (this->name() == ":current") return false;
if (Selector_List* rhs_list = dynamic_cast<Selector_List*>(sub->selector())) {
if (Selector_List* lhs_list = dynamic_cast<Selector_List*>(selector())) {
return lhs_list->is_superselector_of(rhs_list);
}
cerr << "INVALID INTERNAL STATE\n";
} else {
cerr << "INVALID INTERNAL STATE\n";
}
return false;
}

bool Simple_Selector::is_superselector_of(Compound_Selector* sub)
{
cerr << "doda\n";
return false;
}

bool Pseudo_Selector::is_superselector_of(Compound_Selector* compound)
{
cerr << "is_sup pseudo Compound_Selector\n";
return false;
}
bool Pseudo_Selector::is_superselector_of(Complex_Selector* complex)
{
cerr << "is_sup pseudo Complex_Selector\n";
return false;
}
bool Pseudo_Selector::is_superselector_of(Selector_List* list)
{
cerr << "is_sup pseudo Selector_List\n";
return false;
}

bool Compound_Selector::is_superselector_of(Selector_List* rhs, string wrapped)
{
//cerr << "DAHJKA\n";
for (Complex_Selector* item : rhs->elements()) {
if (is_superselector_of(item, wrapped)) return true;
}
return false;
}

bool Compound_Selector::is_superselector_of(Complex_Selector* rhs, string wrapped)
{
if (rhs->head()) return is_superselector_of(rhs->head(), wrapped);
return false;
}

bool Compound_Selector::is_superselector_of(Compound_Selector* rhs, string wrapping)
{
To_String to_string;

Simple_Selector* lbase = base();
Compound_Selector* lhs = this;
Simple_Selector* lbase = lhs->base();
Simple_Selector* rbase = rhs->base();

// Check if pseudo-elements are the same between the selectors

/*
if (elements().size() == 1 && rhs->elements().size() == 1 &&
dynamic_cast<Parent_Selector*>(rhs->elements()[0]) != 0 &&
dynamic_cast<Parent_Selector*>(this->elements()[0]) != 0) {
//cerr << "is super\n";
return true;
}
*/
//debug_ast(lhs, "lhs: ");
//debug_ast(rhs, "rhs: ");
//cerr << elements().size() << endl;
//cerr << rhs->elements().size() << endl;
/*
for (auto item : elements()) {
if (!item->is_superselector_of(rhs)) return false;
}
//cerr << "is super\n";
return true;
*/
set<string> lpsuedoset, rpsuedoset;
for (size_t i = 0, L = length(); i < L; ++i)
{
// debug_ast((*this)[i]);
if ((*this)[i]->is_pseudo_element()) {
string pseudo((*this)[i]->perform(&to_string));
pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
Expand All @@ -253,27 +326,103 @@ namespace Sass {
// Check the Simple_Selectors

set<string> lset, rset;

size_t i = 0;
size_t L = 0;
size_t n = 0;
// if (length() < rhs->length())
if (!lbase) // no lbase; just see if the left-hand qualifiers are a subset of the right-hand selector
{
for (size_t i = 0, L = length(); i < L; ++i)
/*
for (i = 0, L = length(); i < L; ++i)
{
Simple_Selector* lhs = (*this)[i];
// if (lhs && !lhs->is_superselector_of(rhs)) return false;
}
// return true;
*/
for (i = 0, L = length(); i < L; ++i)
{
Selector* lhs = (*this)[i];
Simple_Selector* rhs2 = rhs->elements().size() > i ? (*rhs)[i] : 0;
// very special case for wrapped matches selector
if (Wrapped_Selector* wrapped = dynamic_cast<Wrapped_Selector*>(lhs)) {
if (wrapped->name() == ":not") {
if (Selector_List* not_list = dynamic_cast<Selector_List*>(wrapped->selector())) {
if (!wrapping.empty() && wrapping == wrapped->name()) {;
if (not_list->is_superselector_of(rhs, wrapped->name())) return false;
} else {
if (not_list->is_superselector_of(rhs, wrapped->name())) return false;
}
} else {
cerr << "do not\n";
}
}
if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
lhs = wrapped->selector();
if (Selector_List* list = dynamic_cast<Selector_List*>(wrapped->selector())) {
if (Compound_Selector* comp = dynamic_cast<Compound_Selector*>(rhs)) {
if (list->is_superselector_of(comp)) return true;
if (!wrapping.empty() && wrapping != wrapped->name()) return false;
if (wrapping.empty() || wrapping != wrapped->name()) {;
if (list->is_superselector_of(comp, wrapped->name())) return true;
}
}
}
}
if (Wrapped_Selector* wrapped_r = dynamic_cast<Wrapped_Selector*>(rhs2)) {
if (!wrapping.empty()) {
// cerr << "MORE \n";
}
if (wrapped->name() == wrapped_r->name()) {
if (wrapped->is_superselector_of(wrapped_r)) {
// lset.insert(lhs->perform(&to_string));
// rset.insert(wrapped_r->perform(&to_string));
continue;
rset.insert(lhs->perform(&to_string));

}}
}
}
// match from here on as strings
lset.insert(lhs->perform(&to_string));
// rset.insert((*rhs)[i]->perform(&to_string));
}
for (size_t i = 0, L = rhs->length(); i < L; ++i)
{ rset.insert((*rhs)[i]->perform(&to_string)); }
//debug_ast(this);
for (n = 0, L = rhs->length(); n < L; ++n)
{
auto r = (*rhs)[n];
if (Wrapped_Selector* wrapped = dynamic_cast<Wrapped_Selector*>(r)) {
if (wrapped->name() == ":not") {
if (Selector_List* ls = dynamic_cast<Selector_List*>(wrapped->selector())) {
ls->remove_parent_selectors();
if (!wrapping.empty() && wrapping == wrapped->name()) {;
if (is_superselector_of(ls, wrapped->name())) return false;
} else {
if (is_superselector_of(ls, wrapped->name())) return false;
}
}
}
if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
if (!wrapping.empty()) {
if (wrapping != wrapped->name()) return false;
// cerr << "DID THIS\n";
}
if (Selector_List* ls = dynamic_cast<Selector_List*>(wrapped->selector())) {
ls->remove_parent_selectors();
return (is_superselector_of(ls, wrapped->name()));
// continue;
} else {
// cerr << "ASDADASDASD\n";
}
}
}
rset.insert(r->perform(&to_string));
}

//for (auto l : lset) { cerr << "l: " << l << endl; }
//for (auto r : rset) { cerr << "r: " << r << endl; }

if (lset.size() == 0) return true;
// return true if rset contains all the elements of lset
return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
}
else { // there's an lbase
Expand Down Expand Up @@ -353,12 +502,12 @@ namespace Sass {
return *pLeft < *pRight;
}

bool Complex_Selector::is_superselector_of(Compound_Selector* rhs)
bool Complex_Selector::is_superselector_of(Compound_Selector* rhs, string wrapping)
{
return base()->is_superselector_of(rhs);
return base()->is_superselector_of(rhs, wrapping);
}

bool Complex_Selector::is_superselector_of(Complex_Selector* rhs)
bool Complex_Selector::is_superselector_of(Complex_Selector* rhs, string wrapping)
{
Complex_Selector* lhs = this;
To_String to_string;
Expand All @@ -377,7 +526,7 @@ namespace Sass {
{ return false; }

if (l_len == 1)
{ return lhs->head()->is_superselector_of(rhs->base()); }
{ return lhs->head()->is_superselector_of(rhs->base(), wrapping); }

// we have to look one tail deeper, since we cary the
// combinator around for it (which is important here)
Expand All @@ -394,7 +543,7 @@ namespace Sass {
for (size_t i = 0, L = rhs->length(); i < L; ++i) {
if (i == L-1)
{ return false; }
if (lhs->head()->is_superselector_of(marker->head()))
if (lhs->head()->is_superselector_of(marker->head(), wrapping))
{ found = true; break; }
marker = marker->tail();
}
Expand Down Expand Up @@ -458,6 +607,49 @@ namespace Sass {
return cpy;
}

Complex_Selector* Complex_Selector::parentize(Complex_Selector* parent, Context& ctx)
{
Complex_Selector* pr = 0;
Compound_Selector* head = this->head();
Complex_Selector* trailing = this->tail();
// create a new complex selector to return a processed copy
Complex_Selector* ss = new (ctx.mem) Complex_Selector(pstate());
// Points to last complex selector
// Moved when resolving parent refs
Complex_Selector* cur = ss;

// check if compound selector has exactly one parent reference
// if so we need to connect the parent to the current selector
// then we also need to add the remaining simple selector to the new "parent"
if (head) {
// create a new compound and move originals if needed
// we may add the simple selector to the same selector
// with parent refs we may put them in different places
ss->head(new (ctx.mem) Compound_Selector(head->pstate()));
// process simple selectors sequence
for (size_t i = 0; i < head->size(); ++i) {
// we have a parent selector in a simple selector list
// mix parent complex selector into the compound list
if (dynamic_cast<Parent_Selector*>((*head)[i])) {
// clone the parent selector
pr = parent->cloneFully(ctx);
// assign head and tail
cur->head(pr->head());
cur->tail(pr->tail());
// move forward
cur = pr->last();
} else {
// just add simple selector
*cur->head() << (*head)[i];
}
}
}
// parentize and assign trailing complex selector
if (trailing) cur->tail(trailing->parentize(parent, ctx));
// return selector
return ss;
}

Complex_Selector* Complex_Selector::innermost()
{
if (!tail()) return this;
Expand Down Expand Up @@ -544,41 +736,44 @@ namespace Sass {

// it's a superselector if every selector of the right side
// list is a superselector of the given left side selector
bool Complex_Selector::is_superselector_of(Selector_List *sub)
bool Complex_Selector::is_superselector_of(Selector_List *sub, string wrapping)
{
// Check every rhs selector against left hand list
for(size_t i = 0, L = sub->length(); i < L; ++i) {
if (!is_superselector_of((*sub)[i])) return false;
if (!is_superselector_of((*sub)[i], wrapping)) return false;
}
return true;
}

// it's a superselector if every selector of the right side
// list is a superselector of the given left side selector
bool Selector_List::is_superselector_of(Selector_List *sub)
bool Selector_List::is_superselector_of(Selector_List *sub, string wrapping)
{
// cerr << "do Selector_List " << wrapping << "\n";
// Check every rhs selector against left hand list
for(size_t i = 0, L = sub->length(); i < L; ++i) {
if (!is_superselector_of((*sub)[i])) return false;
if (!is_superselector_of((*sub)[i], wrapping)) return false;
}
return true;
}

// it's a superselector if every selector on the right side
// is a superselector of any one of the left side selectors
bool Selector_List::is_superselector_of(Compound_Selector *sub)
bool Selector_List::is_superselector_of(Compound_Selector *sub, string wrapping)
{
// cerr << "do Compound_Selector " << wrapping << "\n";
// Check every lhs selector against right hand
for(size_t i = 0, L = length(); i < L; ++i) {
if ((*this)[i]->is_superselector_of(sub)) return true;
if ((*this)[i]->is_superselector_of(sub, wrapping)) return true;
}
return false;
}

// it's a superselector if every selector on the right side
// is a superselector of any one of the left side selectors
bool Selector_List::is_superselector_of(Complex_Selector *sub)
bool Selector_List::is_superselector_of(Complex_Selector *sub, string wrapping)
{
// cerr << "do Complex_Selector " << wrapping << "\n";
// Check every lhs selector against right hand
for(size_t i = 0, L = length(); i < L; ++i) {
if ((*this)[i]->is_superselector_of(sub)) return true;
Expand Down
Loading

0 comments on commit 006a63b

Please sign in to comment.