Skip to content

Commit

Permalink
Split Selector_Qualifier AST node into Class_Selector and Id_Selector
Browse files Browse the repository at this point in the history
This better matches the Ruby Sass implementation.
  • Loading branch information
xzyfer committed May 28, 2016
1 parent 97e6200 commit d675a84
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 31 deletions.
31 changes: 19 additions & 12 deletions src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ namespace Sass {
(*cpy)[0] = this->unify_with(ts, ctx);
return cpy;
}
else if (dynamic_cast<Selector_Qualifier*>(rhs_0)) {
else if (dynamic_cast<Class_Selector*>(rhs_0) || dynamic_cast<Id_Selector*>(rhs_0)) {
// qualifier is `.class`, so we can prefix with `ns|*.class`
SimpleSequence_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, rhs->pstate());
if (has_ns() && !rhs_0->has_ns()) {
Expand Down Expand Up @@ -501,17 +501,19 @@ namespace Sass {
return cpy;
}

SimpleSequence_Selector* Selector_Qualifier::unify_with(SimpleSequence_Selector* rhs, Context& ctx)
SimpleSequence_Selector* Class_Selector::unify_with(SimpleSequence_Selector* rhs, Context& ctx)
{
if (name()[0] == '#')
rhs->has_line_break(has_line_break());
return Simple_Selector::unify_with(rhs, ctx);
}

SimpleSequence_Selector* Id_Selector::unify_with(SimpleSequence_Selector* rhs, Context& ctx)
{
for (size_t i = 0, L = rhs->length(); i < L; ++i)
{
for (size_t i = 0, L = rhs->length(); i < L; ++i)
{
Simple_Selector* rhs_i = (*rhs)[i];
if (typeid(*rhs_i) == typeid(Selector_Qualifier) &&
static_cast<Selector_Qualifier*>(rhs_i)->name()[0] == '#' &&
static_cast<Selector_Qualifier*>(rhs_i)->name() != name())
return 0;
Simple_Selector* rhs_i = (*rhs)[i];
if (typeid(*rhs_i) == typeid(Id_Selector) && static_cast<Id_Selector*>(rhs_i)->name() != name()) {
return 0;
}
}
rhs->has_line_break(has_line_break());
Expand Down Expand Up @@ -1037,8 +1039,13 @@ namespace Sass {
SimpleSequence_Selector* rh = last()->head();
size_t i = 0, L = h->length();
if (dynamic_cast<Element_Selector*>(h->first())) {
if (Selector_Qualifier* sq = dynamic_cast<Selector_Qualifier*>(rh->last())) {
Selector_Qualifier* sqs = new Selector_Qualifier(*sq);
if (Class_Selector* sq = dynamic_cast<Class_Selector*>(rh->last())) {
Class_Selector* sqs = new Class_Selector(*sq);
sqs->name(sqs->name() + (*h)[0]->name());
(*rh)[rh->length()-1] = sqs;
for (i = 1; i < L; ++i) *rh << (*h)[i];
} else if (Id_Selector* sq = dynamic_cast<Id_Selector*>(rh->last())) {
Id_Selector* sqs = new Id_Selector(*sq);
sqs->name(sqs->name() + (*h)[0]->name());
(*rh)[rh->length()-1] = sqs;
for (i = 1; i < L; ++i) *rh << (*h)[i];
Expand Down
33 changes: 25 additions & 8 deletions src/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2066,23 +2066,40 @@ namespace Sass {
};

////////////////////////////////////////////////
// Selector qualifiers -- i.e., classes and ids.
// Class selectors -- i.e., .foo.
////////////////////////////////////////////////
class Selector_Qualifier : public Simple_Selector {
class Class_Selector : public Simple_Selector {
public:
Selector_Qualifier(ParserState pstate, std::string n)
Class_Selector(ParserState pstate, std::string n)
: Simple_Selector(pstate, n)
{ }
virtual bool unique() const
{
if (name()[0] == '#') return true;
else return false;
return false;
}
virtual unsigned long specificity()
{
return Constants::Specificity_Class;
}
virtual SimpleSequence_Selector* unify_with(SimpleSequence_Selector*, Context&);
ATTACH_OPERATIONS()
};

////////////////////////////////////////////////
// ID selectors -- i.e., #foo.
////////////////////////////////////////////////
class Id_Selector : public Simple_Selector {
public:
Id_Selector(ParserState pstate, std::string n)
: Simple_Selector(pstate, n)
{ }
virtual bool unique() const
{
return true;
}
virtual unsigned long specificity()
{
if (name()[0] == '#') return Constants::Specificity_ID;
if (name()[0] == '.') return Constants::Specificity_Class;
else return Constants::Specificity_Element;
return Constants::Specificity_ID;
}
virtual SimpleSequence_Selector* unify_with(SimpleSequence_Selector*, Context&);
ATTACH_OPERATIONS()
Expand Down
3 changes: 2 additions & 1 deletion src/ast_fwd_decl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ namespace Sass {
class Selector_Schema;
class Placeholder_Selector;
class Element_Selector;
class Selector_Qualifier;
class Class_Selector;
class Id_Selector;
class Attribute_Selector;
class Pseudo_Selector;
class Wrapped_Selector;
Expand Down
17 changes: 14 additions & 3 deletions src/debugger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,20 @@ inline void debug_ast(AST_Node* node, std::string ind, Env* env)
std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
std::cerr << std::endl;
debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env);
} else if (dynamic_cast<Selector_Qualifier*>(node)) {
Selector_Qualifier* selector = dynamic_cast<Selector_Qualifier*>(node);
std::cerr << ind << "Selector_Qualifier " << selector;
} else if (dynamic_cast<Class_Selector*>(node)) {
Class_Selector* selector = dynamic_cast<Class_Selector*>(node);
std::cerr << ind << "Class_Selector " << selector;
std::cerr << " (" << pstate_source_position(node) << ")";
std::cerr << " <" << selector->hash() << ">";
std::cerr << " <<" << selector->ns_name() << ">>";
std::cerr << (selector->is_optional() ? " [is_optional]": " -");
std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
std::cerr << (selector->has_line_break() ? " [line-break]": " -");
std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
std::cerr << std::endl;
} else if (dynamic_cast<Id_Selector*>(node)) {
Id_Selector* selector = dynamic_cast<Id_Selector*>(node);
std::cerr << ind << "Id_Selector " << selector;
std::cerr << " (" << pstate_source_position(node) << ")";
std::cerr << " <" << selector->hash() << ">";
std::cerr << " <<" << selector->ns_name() << ">>";
Expand Down
3 changes: 2 additions & 1 deletion src/eval.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ namespace Sass {
Element_Selector* operator()(Element_Selector* s) { return s; };
Pseudo_Selector* operator()(Pseudo_Selector* s) { return s; };
Wrapped_Selector* operator()(Wrapped_Selector* s) { return s; };
Selector_Qualifier* operator()(Selector_Qualifier* s) { return s; };
Class_Selector* operator()(Class_Selector* s) { return s; };
Id_Selector* operator()(Id_Selector* s) { return s; };
Placeholder_Selector* operator()(Placeholder_Selector* s) { return s; };
// actual evaluated selectors
CommaSequence_Selector* operator()(Selector_Schema*);
Expand Down
9 changes: 8 additions & 1 deletion src/inspect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,14 @@ namespace Sass {
append_token(s->ns_name(), s);
}

void Inspect::operator()(Selector_Qualifier* s)
void Inspect::operator()(Class_Selector* s)
{
append_token(s->ns_name(), s);
if (s->has_line_break()) append_optional_linefeed();
if (s->has_line_break()) append_indentation();
}

void Inspect::operator()(Id_Selector* s)
{
append_token(s->ns_name(), s);
if (s->has_line_break()) append_optional_linefeed();
Expand Down
3 changes: 2 additions & 1 deletion src/inspect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ namespace Sass {
virtual void operator()(Selector_Schema*);
virtual void operator()(Placeholder_Selector*);
virtual void operator()(Element_Selector*);
virtual void operator()(Selector_Qualifier*);
virtual void operator()(Class_Selector*);
virtual void operator()(Id_Selector*);
virtual void operator()(Attribute_Selector*);
virtual void operator()(Pseudo_Selector*);
virtual void operator()(Wrapped_Selector*);
Expand Down
6 changes: 4 additions & 2 deletions src/operation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ namespace Sass {
virtual T operator()(Selector_Schema* x) = 0;
virtual T operator()(Placeholder_Selector* x) = 0;
virtual T operator()(Element_Selector* x) = 0;
virtual T operator()(Selector_Qualifier* x) = 0;
virtual T operator()(Class_Selector* x) = 0;
virtual T operator()(Id_Selector* x) = 0;
virtual T operator()(Attribute_Selector* x) = 0;
virtual T operator()(Pseudo_Selector* x) = 0;
virtual T operator()(Wrapped_Selector* x) = 0;
Expand Down Expand Up @@ -154,7 +155,8 @@ namespace Sass {
T operator()(Selector_Schema* x) { return static_cast<D*>(this)->fallback(x); }
T operator()(Placeholder_Selector* x) { return static_cast<D*>(this)->fallback(x); }
T operator()(Element_Selector* x) { return static_cast<D*>(this)->fallback(x); }
T operator()(Selector_Qualifier* x) { return static_cast<D*>(this)->fallback(x); }
T operator()(Class_Selector* x) { return static_cast<D*>(this)->fallback(x); }
T operator()(Id_Selector* x) { return static_cast<D*>(this)->fallback(x); }
T operator()(Attribute_Selector* x) { return static_cast<D*>(this)->fallback(x); }
T operator()(Pseudo_Selector* x) { return static_cast<D*>(this)->fallback(x); }
T operator()(Wrapped_Selector* x) { return static_cast<D*>(this)->fallback(x); }
Expand Down
7 changes: 5 additions & 2 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,8 +799,11 @@ namespace Sass {
Simple_Selector* Parser::parse_simple_selector()
{
lex < css_comments >(false);
if (lex< alternatives < id_name, class_name > >()) {
return SASS_MEMORY_NEW(ctx.mem, Selector_Qualifier, pstate, lexed);
if (lex< class_name >()) {
return SASS_MEMORY_NEW(ctx.mem, Class_Selector, pstate, lexed);
}
else if (lex< id_name >()) {
return SASS_MEMORY_NEW(ctx.mem, Id_Selector, pstate, lexed);
}
else if (lex< quoted_string >()) {
return SASS_MEMORY_NEW(ctx.mem, Element_Selector, pstate, unquote(lexed));
Expand Down

0 comments on commit d675a84

Please sign in to comment.