Skip to content

Commit cba7bdc

Browse files
committed
Merge pull request #1599 from mgreter/bugfix/issue_1590
Improve parent selector handling
2 parents aa4dbbf + 4276b96 commit cba7bdc

File tree

7 files changed

+55
-9
lines changed

7 files changed

+55
-9
lines changed

src/ast.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,16 @@ namespace Sass {
235235
return this == &rhs;
236236
}
237237

238+
// Selector lists can be compared to comma lists
239+
bool Selector_List::operator==(const Expression& rhs) const
240+
{
241+
// solve the double dispatch problem by using RTTI information via dynamic cast
242+
if (const List* ls = dynamic_cast<const List*>(&rhs)) { return *this == *ls; }
243+
if (const Selector* ls = dynamic_cast<const Selector*>(&rhs)) { return *this == *ls; }
244+
// compare invalid (maybe we should error?)
245+
return false;
246+
}
247+
238248
bool Selector_List::operator== (const Selector_List& rhs) const
239249
{
240250
// for array access
@@ -258,10 +268,10 @@ namespace Sass {
258268
// skip nulls
259269
if (!l) ++i;
260270
else if (!r) ++n;
261-
// do the check now
271+
// do the check
262272
else if (*l != *r)
263273
{ return false; }
264-
// advance now
274+
// advance
265275
++i; ++n;
266276
}
267277
// no mismatch

src/ast.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ namespace Sass {
191191
T last() { return elements_.back(); }
192192
T first() { return elements_.front(); }
193193
T& operator[](size_t i) { return elements_[i]; }
194+
virtual const T& at(size_t i) const { return elements_.at(i); }
194195
const T& operator[](size_t i) const { return elements_[i]; }
195196
Vectorized& operator<<(T element)
196197
{
@@ -2251,6 +2252,7 @@ namespace Sass {
22512252
Selector_List(ParserState pstate, size_t s = 0)
22522253
: Selector(pstate), Vectorized<Complex_Selector*>(s), wspace_(0)
22532254
{ }
2255+
std::string type() { return "list"; }
22542256
// remove parent selector references
22552257
// basically unwraps parsed selectors
22562258
void remove_parent_selectors();
@@ -2276,6 +2278,8 @@ namespace Sass {
22762278
Selector_List* cloneFully(Context&) const; // clones Compound_Selector*s
22772279
virtual bool operator==(const Selector& rhs) const;
22782280
virtual bool operator==(const Selector_List& rhs) const;
2281+
// Selector Lists can be compared to comma lists
2282+
virtual bool operator==(const Expression& rhs) const;
22792283
ATTACH_OPERATIONS()
22802284
};
22812285

src/bind.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ namespace Sass {
3939
size_t ia = 0, LA = as->length();
4040
while (ia < LA) {
4141
Argument* a = (*as)[ia];
42-
// this is only needed for selectors
43-
a->value(a->value()->perform(&listize));
4442
if (ip >= LP) {
4543
// skip empty rest arguments
4644
if (a->is_rest_argument()) {

src/emitter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ namespace Sass {
146146
{
147147
if (output_style() == COMPRESSED) return;
148148
if (output_style() == COMPACT) return;
149+
if (in_declaration && in_comma_array) return;
149150
if (scheduled_linefeed && indentation)
150151
scheduled_linefeed = 1;
151152
std::string indent = "";
@@ -208,6 +209,7 @@ namespace Sass {
208209

209210
void Emitter::append_optional_linefeed()
210211
{
212+
if (in_declaration && in_comma_array) return;
211213
if (output_style() == COMPACT) {
212214
append_mandatory_space();
213215
} else {

src/eval.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ namespace Sass {
761761
value = SASS_MEMORY_NEW(ctx.mem, Null, value->pstate());
762762
}
763763
else if (value->concrete_type() == Expression::SELECTOR) {
764-
value = value->perform(this)->perform(&listize);
764+
value = value->perform(this); // ->perform(&listize);
765765
}
766766

767767
// std::cerr << "\ttype is now: " << typeid(*value).name() << std::endl << std::endl;

src/functions.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,12 +1188,13 @@ namespace Sass {
11881188
Signature length_sig = "length($list)";
11891189
BUILT_IN(length)
11901190
{
1191+
if (Selector_List* sl = dynamic_cast<Selector_List*>(env["$list"])) {
1192+
return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)sl->length());
1193+
}
11911194
Expression* v = ARG("$list", Expression);
11921195
if (v->concrete_type() == Expression::MAP) {
11931196
Map* map = dynamic_cast<Map*>(env["$list"]);
1194-
return SASS_MEMORY_NEW(ctx.mem, Number,
1195-
pstate,
1196-
(double)(map ? map->length() : 1));
1197+
return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)(map ? map->length() : 1));
11971198
}
11981199
if (v->concrete_type() == Expression::SELECTOR) {
11991200
if (Compound_Selector* h = dynamic_cast<Compound_Selector*>(v)) {
@@ -1214,9 +1215,19 @@ namespace Sass {
12141215
Signature nth_sig = "nth($list, $n)";
12151216
BUILT_IN(nth)
12161217
{
1218+
Number* n = ARG("$n", Number);
12171219
Map* m = dynamic_cast<Map*>(env["$list"]);
1220+
if (Selector_List* sl = dynamic_cast<Selector_List*>(env["$list"])) {
1221+
size_t len = m ? m->length() : sl->length();
1222+
bool empty = m ? m->empty() : sl->empty();
1223+
if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate);
1224+
double index = std::floor(n->value() < 0 ? len + n->value() : n->value() - 1);
1225+
if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate);
1226+
// return (*sl)[static_cast<int>(index)];
1227+
Listize listize(ctx);
1228+
return (*sl)[static_cast<int>(index)]->perform(&listize);
1229+
}
12181230
List* l = dynamic_cast<List*>(env["$list"]);
1219-
Number* n = ARG("$n", Number);
12201231
if (n->value() == 0) error("argument `$n` of `" + std::string(sig) + "` must be non-zero", pstate);
12211232
// if the argument isn't a list, then wrap it in a singleton list
12221233
if (!m && !l) {
@@ -1307,6 +1318,10 @@ namespace Sass {
13071318
{
13081319
List* l = dynamic_cast<List*>(env["$list"]);
13091320
Expression* v = ARG("$val", Expression);
1321+
if (Selector_List* sl = dynamic_cast<Selector_List*>(env["$list"])) {
1322+
Listize listize(ctx);
1323+
l = dynamic_cast<List*>(sl->perform(&listize));
1324+
}
13101325
String_Constant* sep = ARG("$separator", String_Constant);
13111326
if (!l) {
13121327
l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);

src/inspect.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,10 @@ namespace Sass {
738738
in_wrapped = true;
739739
append_token(s->name(), s);
740740
append_string("(");
741+
bool was_comma_array = in_comma_array;
742+
in_comma_array = false;
741743
s->selector()->perform(this);
744+
in_comma_array = was_comma_array;
742745
append_string(")");
743746
in_wrapped = was;
744747
}
@@ -816,6 +819,14 @@ namespace Sass {
816819
void Inspect::operator()(Selector_List* g)
817820
{
818821
if (g->empty()) return;
822+
823+
bool was_comma_array = in_comma_array;
824+
if (!in_declaration && in_comma_array) {
825+
append_string("(");
826+
}
827+
828+
if (in_declaration) in_comma_array = true;
829+
819830
for (size_t i = 0, L = g->length(); i < L; ++i) {
820831
if (!in_wrapped && i == 0) append_indentation();
821832
if ((*g)[i] == 0) continue;
@@ -825,6 +836,12 @@ namespace Sass {
825836
append_comma_separator();
826837
}
827838
}
839+
840+
in_comma_array = was_comma_array;
841+
if (!in_declaration && in_comma_array) {
842+
append_string(")");
843+
}
844+
828845
}
829846

830847
void Inspect::fallback_impl(AST_Node* n)

0 commit comments

Comments
 (0)