Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit 3af051e

Browse files
committed
Fix parent selector bug in evaluation step
1 parent 4767390 commit 3af051e

File tree

5 files changed

+124
-40
lines changed

5 files changed

+124
-40
lines changed

ast.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,9 +572,44 @@ namespace Sass {
572572
return ss;
573573
}
574574

575+
Complex_Selector* Complex_Selector::parentize(Context& ctx)
576+
{
577+
// create a new complex selector to return a processed copy
578+
return this;
579+
Complex_Selector* ss = new (ctx.mem) Complex_Selector(this->pstate());
580+
ss->has_line_feed(this->has_line_feed());
581+
ss->combinator(this->combinator());
582+
if (this->tail()) {
583+
ss->tail(this->tail()->parentize(ctx));
584+
}
585+
if (Compound_Selector* head = this->head()) {
586+
// now add everything expect parent selectors to head
587+
ss->head(new (ctx.mem) Compound_Selector(head->pstate()));
588+
for (size_t i = 0, L = head->length(); i < L; ++i) {
589+
if (!dynamic_cast<Parent_Selector*>((*head)[i])) {
590+
*ss->head() << (*head)[i];
591+
}
592+
}
593+
// if (ss->head()->empty()) ss->head(0);
594+
}
595+
// return copy
596+
return ss;
597+
}
598+
599+
Selector_List* Selector_List::parentize(Context& ctx)
600+
{
601+
Selector_List* ss = new (ctx.mem) Selector_List(pstate());
602+
for (size_t i = 0, L = length(); i < L; ++i) {
603+
*ss << (*this)[i]->parentize(ctx);
604+
}
605+
// return selector
606+
return ss;
607+
}
608+
575609
Selector_List* Complex_Selector::parentize(Selector_List* ps, Context& ctx)
576610
{
577611
Selector_List* ss = new (ctx.mem) Selector_List(pstate());
612+
if (ps == 0) { *ss << this->parentize(ctx); return ss; }
578613
for (size_t i = 0, L = ps->length(); i < L; ++i) {
579614
*ss << this->parentize((*ps)[i], ctx);
580615
}
@@ -584,10 +619,13 @@ namespace Sass {
584619

585620
Complex_Selector* Complex_Selector::parentize(Complex_Selector* parent, Context& ctx)
586621
{
622+
if (!parent) return parentize(ctx);
587623
Complex_Selector* pr = 0;
588624
Compound_Selector* head = this->head();
589625
// create a new complex selector to return a processed copy
590626
Complex_Selector* ss = new (ctx.mem) Complex_Selector(pstate());
627+
ss->has_line_feed(has_line_feed());
628+
ss->has_line_break(has_line_break());
591629

592630
// Points to last complex selector
593631
// Moved when resolving parent refs
@@ -680,7 +718,20 @@ namespace Sass {
680718
return cpy;
681719
}
682720

721+
Selector_List* Selector_List::clone(Context& ctx) const
722+
{
723+
Selector_List* cpy = new (ctx.mem) Selector_List(*this);
724+
return cpy;
725+
}
683726

727+
Selector_List* Selector_List::cloneFully(Context& ctx) const
728+
{
729+
Selector_List* cpy = new (ctx.mem) Selector_List(pstate());
730+
for (size_t i = 0, L = length(); i < L; ++i) {
731+
*cpy << (*this)[i]->cloneFully(ctx);
732+
}
733+
return cpy;
734+
}
684735

685736
/* not used anymore - remove?
686737
Selector_Placeholder* Selector::find_placeholder()

ast.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,7 @@ namespace Sass {
20422042
return s;
20432043
};
20442044
size_t length();
2045+
Complex_Selector* parentize(Context& ctx);
20452046
Selector_List* parentize(Selector_List* parents, Context& ctx);
20462047
Complex_Selector* parentize(Complex_Selector* parent, Context& ctx);
20472048
virtual bool is_superselector_of(Compound_Selector* sub, string wrapping = "");
@@ -2136,6 +2137,7 @@ namespace Sass {
21362137
// basically unwraps parsed selectors
21372138
void remove_parent_selectors();
21382139
// virtual Selector_Placeholder* find_placeholder();
2140+
Selector_List* parentize(Context& ctx);
21392141
Selector_List* parentize(Selector_List* parents, Context& ctx);
21402142
Selector_List* parentize(Complex_Selector* parent, Context& ctx);
21412143
virtual bool is_superselector_of(Compound_Selector* sub, string wrapping = "");
@@ -2155,6 +2157,8 @@ namespace Sass {
21552157
}
21562158
return sum;
21572159
}
2160+
Selector_List* clone(Context&) const; // does not clone Compound_Selector*s
2161+
Selector_List* cloneFully(Context&) const; // clones Compound_Selector*s
21582162
// vector<Complex_Selector*> members() { return elements_; }
21592163
ATTACH_OPERATIONS()
21602164
};

debugger.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,6 @@ inline void debug_node(Node* node, string ind = "")
585585
case Complex_Selector::ADJACENT_TO: cerr << "{+} "; break;
586586
case Complex_Selector::PARENT_OF: cerr << "{>} "; break;
587587
case Complex_Selector::PRECEDES: cerr << "{~} "; break;
588-
case Complex_Selector::REFERENCE: cerr << "{@} "; break;
589588
case Complex_Selector::ANCESTOR_OF: cerr << "{ } "; break;
590589
}
591590
cerr << endl;

eval.cpp

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,55 +1399,83 @@ namespace Sass {
13991399
Compound_Selector* head = s->head();
14001400
Complex_Selector::Combinator combinator = s->combinator();
14011401
Selector_List* sl = new (ctx.mem) Selector_List(s->pstate());
1402-
14031402
if (head) {
14041403
// check if we have a parent selector reference (expands to list)
1405-
if (head->length() > 0 && dynamic_cast<Parent_Selector*>((*head)[0])) {
1404+
if (head->length() > 1 && dynamic_cast<Parent_Selector*>((*head)[0])) {
14061405
// do we have any parents to interpolate
1407-
Selector_List* pr = selector();
1408-
if (pr && pr->length() > 0) {
1409-
for (size_t n = 0, nL = pr->length(); n < nL; ++n) {
1410-
if (tail) {
1411-
vector<Selector_List*> rv;
1412-
Selector_List* tails = operator()(tail);
1413-
for (size_t m = 0, mL = tails->length(); m < mL; ++m) {
1414-
Complex_Selector* ns = (*pr)[n]->cloneFully(ctx);
1415-
if (s->has_line_feed()) ns->has_line_feed(true);
1416-
Complex_Selector* tt = (*tails)[m];
1417-
Complex_Selector* last = ns->last();
1418-
if (combinator != Complex_Selector::ANCESTOR_OF) {
1419-
Complex_Selector* cp = 0;
1420-
cp = new (ctx.mem) Complex_Selector(s->pstate());
1421-
cp->head(head); cp->tail(tt);
1422-
cp->combinator(combinator);
1423-
last->tail(cp);
1424-
} else {
1425-
last->tail(tt);
1426-
}
1427-
for (size_t i = 1, iL = head->length(); i < iL; ++i) {
1428-
// add simple selectors
1429-
*last->head() << (*head)[i];
1430-
}
1431-
*sl << ns;
1432-
}
1433-
// EO foreach parentized tail
1434-
} else {
1435-
Complex_Selector* ns = (*pr)[n]->cloneFully(ctx);
1436-
Complex_Selector* last = ns->last();
1437-
ns->combinator(combinator);
1438-
for (size_t i = 1, iL = head->length(); i < iL; ++i) {
1439-
// add simple selectors
1440-
*last->head() << (*head)[i];
1406+
if (Selector_List* pr = selector()) {
1407+
// parent will be prefixed
1408+
Selector_List* ns = pr->cloneFully(ctx);
1409+
// the tail can be re-attached unchanged
1410+
for (size_t n = 0, nL = ns->length(); n < nL; ++n) {
1411+
Complex_Selector* lst_t = (*ns)[n]->last();
1412+
Compound_Selector* lst_h = lst_t->head();
1413+
for (size_t i = 1, L = head->length(); i < L; ++i) *lst_h << (*head)[i];
1414+
lst_t->tail(tail); // now connect old tail back to new intermediate
1415+
lst_t->combinator(combinator); // and dont forget the combinator
1416+
// if (s->has_line_feed()) lst_t->has_line_feed(true); // and dont forget the combinator
1417+
}
1418+
return ns;
1419+
}
1420+
else {
1421+
Complex_Selector* cpy = s->cloneFully(ctx);
1422+
cpy->head(new (ctx.mem) Compound_Selector(head->pstate()));
1423+
for (size_t i = 1, L = head->length(); i < L; ++i)
1424+
*cpy->head() << (*head)[i];
1425+
*sl << s;
1426+
return sl;
1427+
}
1428+
}
1429+
1430+
// have a simple
1431+
if (head->length() == 1 && dynamic_cast<Parent_Selector*>((*head)[0])) {
1432+
// do we have any parents to interpolate
1433+
if (Selector_List* pr = selector()) {
1434+
// parent will be prefixed
1435+
Selector_List* ns = pr->cloneFully(ctx);
1436+
// the tail can be re-attached unchanged
1437+
for (size_t n = 0, nL = ns->length(); n < nL; ++n) {
1438+
Complex_Selector* lst = (*ns)[n]->last();
1439+
lst->tail(tail);
1440+
if (combinator != Complex_Selector::ANCESTOR_OF) {
1441+
if (lst->combinator()!= Complex_Selector::ANCESTOR_OF) {
1442+
Complex_Selector* ins = s->clone(ctx);
1443+
ins->head(0);
1444+
ins->tail(tail);
1445+
lst->tail(ins);
1446+
} else {
1447+
lst->combinator(combinator);
14411448
}
1442-
*sl << ns;
14431449
}
1450+
if (s->has_line_feed()) lst->has_line_feed(true);
1451+
if (s->has_line_break()) lst->has_line_break(true);
14441452
}
1445-
parentized = true;
1453+
return ns;
1454+
}
1455+
else {
1456+
Complex_Selector* ss = s->cloneFully(ctx);
1457+
// check if complex selector can be eliminated
1458+
if (s->combinator() == Complex_Selector::ANCESTOR_OF)
1459+
{
1460+
if (s->has_line_feed()) tail->has_line_feed(true);
1461+
if (s->has_line_break()) tail->has_line_break(true);
1462+
*sl << tail;
1463+
}
1464+
else
1465+
{
1466+
*sl << ss;
1467+
}
1468+
return sl;
14461469
}
14471470

14481471
}
14491472

14501473
}
1474+
else
1475+
{
1476+
*sl << s;
1477+
return sl;
1478+
}
14511479

14521480
if (parentized == false) {
14531481
if (s->tail()) {

parser.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,7 @@ namespace Sass {
665665
{
666666
bool reloop = true;
667667
bool had_linefeed = false;
668+
Complex_Selector* sel = 0;
668669
To_String to_string(&ctx);
669670
Selector_List* group = new (ctx.mem) Selector_List(pstate);
670671

@@ -678,7 +679,7 @@ namespace Sass {
678679

679680

680681
// now parse the complex selector
681-
Complex_Selector* sel = parse_complex_selector(in_root);
682+
sel = parse_complex_selector(in_root);
682683

683684
if (!sel) return group;
684685

@@ -704,6 +705,7 @@ namespace Sass {
704705
}
705706
// update for end position
706707
group->update_pstate(pstate);
708+
if (sel) sel->last()->has_line_break(false);
707709
return group;
708710
}
709711
// EO parse_selector_list

0 commit comments

Comments
 (0)