Skip to content

Commit

Permalink
Fix parent selector bug in evaluation step
Browse files Browse the repository at this point in the history
  • Loading branch information
mgreter committed Jul 13, 2015
1 parent 4767390 commit 3af051e
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 40 deletions.
51 changes: 51 additions & 0 deletions ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,9 +572,44 @@ namespace Sass {
return ss;
}

Complex_Selector* Complex_Selector::parentize(Context& ctx)
{
// create a new complex selector to return a processed copy
return this;
Complex_Selector* ss = new (ctx.mem) Complex_Selector(this->pstate());
ss->has_line_feed(this->has_line_feed());
ss->combinator(this->combinator());
if (this->tail()) {
ss->tail(this->tail()->parentize(ctx));
}
if (Compound_Selector* head = this->head()) {
// now add everything expect parent selectors to head
ss->head(new (ctx.mem) Compound_Selector(head->pstate()));
for (size_t i = 0, L = head->length(); i < L; ++i) {
if (!dynamic_cast<Parent_Selector*>((*head)[i])) {
*ss->head() << (*head)[i];
}
}
// if (ss->head()->empty()) ss->head(0);
}
// return copy
return ss;
}

Selector_List* Selector_List::parentize(Context& ctx)
{
Selector_List* ss = new (ctx.mem) Selector_List(pstate());
for (size_t i = 0, L = length(); i < L; ++i) {
*ss << (*this)[i]->parentize(ctx);
}
// return selector
return ss;
}

Selector_List* Complex_Selector::parentize(Selector_List* ps, Context& ctx)
{
Selector_List* ss = new (ctx.mem) Selector_List(pstate());
if (ps == 0) { *ss << this->parentize(ctx); return ss; }
for (size_t i = 0, L = ps->length(); i < L; ++i) {
*ss << this->parentize((*ps)[i], ctx);
}
Expand All @@ -584,10 +619,13 @@ namespace Sass {

Complex_Selector* Complex_Selector::parentize(Complex_Selector* parent, Context& ctx)
{
if (!parent) return parentize(ctx);
Complex_Selector* pr = 0;
Compound_Selector* head = this->head();
// create a new complex selector to return a processed copy
Complex_Selector* ss = new (ctx.mem) Complex_Selector(pstate());
ss->has_line_feed(has_line_feed());
ss->has_line_break(has_line_break());

// Points to last complex selector
// Moved when resolving parent refs
Expand Down Expand Up @@ -680,7 +718,20 @@ namespace Sass {
return cpy;
}

Selector_List* Selector_List::clone(Context& ctx) const
{
Selector_List* cpy = new (ctx.mem) Selector_List(*this);
return cpy;
}

Selector_List* Selector_List::cloneFully(Context& ctx) const
{
Selector_List* cpy = new (ctx.mem) Selector_List(pstate());
for (size_t i = 0, L = length(); i < L; ++i) {
*cpy << (*this)[i]->cloneFully(ctx);
}
return cpy;
}

/* not used anymore - remove?
Selector_Placeholder* Selector::find_placeholder()
Expand Down
4 changes: 4 additions & 0 deletions ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2042,6 +2042,7 @@ namespace Sass {
return s;
};
size_t length();
Complex_Selector* parentize(Context& ctx);
Selector_List* parentize(Selector_List* parents, Context& ctx);
Complex_Selector* parentize(Complex_Selector* parent, Context& ctx);
virtual bool is_superselector_of(Compound_Selector* sub, string wrapping = "");
Expand Down Expand Up @@ -2136,6 +2137,7 @@ namespace Sass {
// basically unwraps parsed selectors
void remove_parent_selectors();
// virtual Selector_Placeholder* find_placeholder();
Selector_List* parentize(Context& ctx);
Selector_List* parentize(Selector_List* parents, Context& ctx);
Selector_List* parentize(Complex_Selector* parent, Context& ctx);
virtual bool is_superselector_of(Compound_Selector* sub, string wrapping = "");
Expand All @@ -2155,6 +2157,8 @@ namespace Sass {
}
return sum;
}
Selector_List* clone(Context&) const; // does not clone Compound_Selector*s
Selector_List* cloneFully(Context&) const; // clones Compound_Selector*s
// vector<Complex_Selector*> members() { return elements_; }
ATTACH_OPERATIONS()
};
Expand Down
1 change: 0 additions & 1 deletion debugger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,6 @@ inline void debug_node(Node* node, string ind = "")
case Complex_Selector::ADJACENT_TO: cerr << "{+} "; break;
case Complex_Selector::PARENT_OF: cerr << "{>} "; break;
case Complex_Selector::PRECEDES: cerr << "{~} "; break;
case Complex_Selector::REFERENCE: cerr << "{@} "; break;
case Complex_Selector::ANCESTOR_OF: cerr << "{ } "; break;
}
cerr << endl;
Expand Down
104 changes: 66 additions & 38 deletions eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1399,55 +1399,83 @@ namespace Sass {
Compound_Selector* head = s->head();
Complex_Selector::Combinator combinator = s->combinator();
Selector_List* sl = new (ctx.mem) Selector_List(s->pstate());

if (head) {
// check if we have a parent selector reference (expands to list)
if (head->length() > 0 && dynamic_cast<Parent_Selector*>((*head)[0])) {
if (head->length() > 1 && dynamic_cast<Parent_Selector*>((*head)[0])) {
// do we have any parents to interpolate
Selector_List* pr = selector();
if (pr && pr->length() > 0) {
for (size_t n = 0, nL = pr->length(); n < nL; ++n) {
if (tail) {
vector<Selector_List*> rv;
Selector_List* tails = operator()(tail);
for (size_t m = 0, mL = tails->length(); m < mL; ++m) {
Complex_Selector* ns = (*pr)[n]->cloneFully(ctx);
if (s->has_line_feed()) ns->has_line_feed(true);
Complex_Selector* tt = (*tails)[m];
Complex_Selector* last = ns->last();
if (combinator != Complex_Selector::ANCESTOR_OF) {
Complex_Selector* cp = 0;
cp = new (ctx.mem) Complex_Selector(s->pstate());
cp->head(head); cp->tail(tt);
cp->combinator(combinator);
last->tail(cp);
} else {
last->tail(tt);
}
for (size_t i = 1, iL = head->length(); i < iL; ++i) {
// add simple selectors
*last->head() << (*head)[i];
}
*sl << ns;
}
// EO foreach parentized tail
} else {
Complex_Selector* ns = (*pr)[n]->cloneFully(ctx);
Complex_Selector* last = ns->last();
ns->combinator(combinator);
for (size_t i = 1, iL = head->length(); i < iL; ++i) {
// add simple selectors
*last->head() << (*head)[i];
if (Selector_List* pr = selector()) {
// parent will be prefixed
Selector_List* ns = pr->cloneFully(ctx);
// the tail can be re-attached unchanged
for (size_t n = 0, nL = ns->length(); n < nL; ++n) {
Complex_Selector* lst_t = (*ns)[n]->last();
Compound_Selector* lst_h = lst_t->head();
for (size_t i = 1, L = head->length(); i < L; ++i) *lst_h << (*head)[i];
lst_t->tail(tail); // now connect old tail back to new intermediate
lst_t->combinator(combinator); // and dont forget the combinator
// if (s->has_line_feed()) lst_t->has_line_feed(true); // and dont forget the combinator
}
return ns;
}
else {
Complex_Selector* cpy = s->cloneFully(ctx);
cpy->head(new (ctx.mem) Compound_Selector(head->pstate()));
for (size_t i = 1, L = head->length(); i < L; ++i)
*cpy->head() << (*head)[i];
*sl << s;
return sl;
}
}

// have a simple
if (head->length() == 1 && dynamic_cast<Parent_Selector*>((*head)[0])) {
// do we have any parents to interpolate
if (Selector_List* pr = selector()) {
// parent will be prefixed
Selector_List* ns = pr->cloneFully(ctx);
// the tail can be re-attached unchanged
for (size_t n = 0, nL = ns->length(); n < nL; ++n) {
Complex_Selector* lst = (*ns)[n]->last();
lst->tail(tail);
if (combinator != Complex_Selector::ANCESTOR_OF) {
if (lst->combinator()!= Complex_Selector::ANCESTOR_OF) {
Complex_Selector* ins = s->clone(ctx);
ins->head(0);
ins->tail(tail);
lst->tail(ins);
} else {
lst->combinator(combinator);
}
*sl << ns;
}
if (s->has_line_feed()) lst->has_line_feed(true);
if (s->has_line_break()) lst->has_line_break(true);
}
parentized = true;
return ns;
}
else {
Complex_Selector* ss = s->cloneFully(ctx);
// check if complex selector can be eliminated
if (s->combinator() == Complex_Selector::ANCESTOR_OF)
{
if (s->has_line_feed()) tail->has_line_feed(true);
if (s->has_line_break()) tail->has_line_break(true);
*sl << tail;
}
else
{
*sl << ss;
}
return sl;
}

}

}
else
{
*sl << s;
return sl;
}

if (parentized == false) {
if (s->tail()) {
Expand Down
4 changes: 3 additions & 1 deletion parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ namespace Sass {
{
bool reloop = true;
bool had_linefeed = false;
Complex_Selector* sel = 0;
To_String to_string(&ctx);
Selector_List* group = new (ctx.mem) Selector_List(pstate);

Expand All @@ -678,7 +679,7 @@ namespace Sass {


// now parse the complex selector
Complex_Selector* sel = parse_complex_selector(in_root);
sel = parse_complex_selector(in_root);

if (!sel) return group;

Expand All @@ -704,6 +705,7 @@ namespace Sass {
}
// update for end position
group->update_pstate(pstate);
if (sel) sel->last()->has_line_break(false);
return group;
}
// EO parse_selector_list
Expand Down

0 comments on commit 3af051e

Please sign in to comment.