diff --git a/ast.hpp b/ast.hpp index bc2578bfcc..ca1c5b2484 100644 --- a/ast.hpp +++ b/ast.hpp @@ -2008,11 +2008,12 @@ namespace Sass { //////////////////////////////////////////////////////////////////////////// class Complex_Selector : public Selector { public: - enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO }; + enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO, REFERENCE }; private: ADD_PROPERTY(Combinator, combinator) ADD_PROPERTY(Compound_Selector*, head) ADD_PROPERTY(Complex_Selector*, tail) + ADD_PROPERTY(String*, reference); public: bool contains_placeholder() { if (head() && head()->contains_placeholder()) return true; @@ -2023,7 +2024,7 @@ namespace Sass { Combinator c = ANCESTOR_OF, Compound_Selector* h = 0, Complex_Selector* t = 0) - : Selector(pstate), combinator_(c), head_(h), tail_(t) + : Selector(pstate), combinator_(c), head_(h), tail_(t), reference_(0) { if ((h && h->has_reference()) || (t && t->has_reference())) has_reference(true); if ((h && h->has_placeholder()) || (t && t->has_placeholder())) has_placeholder(true); diff --git a/debugger.hpp b/debugger.hpp index 9eca6a2929..34db59bb72 100644 --- a/debugger.hpp +++ b/debugger.hpp @@ -123,7 +123,9 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) case Complex_Selector::PRECEDES: del = "~"; break; case Complex_Selector::ADJACENT_TO: del = "+"; break; case Complex_Selector::ANCESTOR_OF: del = " "; break; + case Complex_Selector::REFERENCE: del = "//"; break; } + // if (del = "/") del += selector->reference()->perform(&to_string) + "/"; cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl; debug_ast(selector->head(), ind + " " /* + "[" + del + "]" */, env); if (selector->tail()) { diff --git a/eval.cpp b/eval.cpp index 923c37154a..49c6769353 100644 --- a/eval.cpp +++ b/eval.cpp @@ -1397,8 +1397,10 @@ namespace Sass { bool parentized = false; Complex_Selector* tail = s->tail(); Compound_Selector* head = s->head(); + String* reference = s->reference(); Complex_Selector::Combinator combinator = s->combinator(); Selector_List* sl = new (ctx.mem) Selector_List(s->pstate()); + if (reference) reference = (String*) reference->perform(this); if (head) { // check if we have a parent selector reference (expands to list) @@ -1420,6 +1422,7 @@ namespace Sass { cp = new (ctx.mem) Complex_Selector(s->pstate()); cp->head(head); cp->tail(tt); cp->combinator(combinator); + cp->reference(reference); last->tail(cp); } else { last->tail(tt); @@ -1435,6 +1438,7 @@ namespace Sass { Complex_Selector* ns = (*pr)[n]->cloneFully(ctx); Complex_Selector* last = ns->last(); ns->combinator(combinator); + ns->reference(reference); for (size_t i = 1, iL = head->length(); i < iL; ++i) { // add simple selectors *last->head() << (*head)[i]; diff --git a/extend.cpp b/extend.cpp index e0213ea2fc..3f99f3cb02 100644 --- a/extend.cpp +++ b/extend.cpp @@ -76,6 +76,7 @@ namespace Sass { case Complex_Selector::PARENT_OF: os << "\">\""; break; case Complex_Selector::PRECEDES: os << "\"~\""; break; case Complex_Selector::ADJACENT_TO: os << "\"+\""; break; + case Complex_Selector::REFERENCE: os << "\"/\""; break; } return os; diff --git a/inspect.cpp b/inspect.cpp index 90bd3bed81..0205b6aa96 100644 --- a/inspect.cpp +++ b/inspect.cpp @@ -927,6 +927,13 @@ namespace Sass { append_string("+"); append_optional_space(); break; + case Complex_Selector::REFERENCE: + append_mandatory_space(); + append_string("/"); + c->reference()->perform(this); + append_string("/"); + append_mandatory_space(); + break; case Complex_Selector::PRECEDES: if (is_empty) append_optional_space(); else append_mandatory_space(); diff --git a/listize.cpp b/listize.cpp index 7967c09f2c..3fc909de63 100644 --- a/listize.cpp +++ b/listize.cpp @@ -45,6 +45,9 @@ namespace Sass { if (hh) *l << hh; } + To_String to_string; + string reference = ! sel->reference() ? "" + : sel->reference()->perform(&to_string); switch(sel->combinator()) { case Complex_Selector::PARENT_OF: @@ -53,6 +56,9 @@ namespace Sass { case Complex_Selector::ADJACENT_TO: *l << new (ctx.mem) String_Quoted(sel->pstate(), "+"); break; + case Complex_Selector::REFERENCE: + *l << new (ctx.mem) String_Quoted(sel->pstate(), "/" + reference + "/"); + break; case Complex_Selector::PRECEDES: *l << new (ctx.mem) String_Quoted(sel->pstate(), "~"); break; diff --git a/node.cpp b/node.cpp index d16d02abae..309c84d29f 100644 --- a/node.cpp +++ b/node.cpp @@ -142,6 +142,7 @@ namespace Sass { case Complex_Selector::PARENT_OF: os << "\">\""; break; case Complex_Selector::PRECEDES: os << "\"~\""; break; case Complex_Selector::ADJACENT_TO: os << "\"+\""; break; + case Complex_Selector::REFERENCE: os << "\"/\""; break; } } else if (node.isNil()) { diff --git a/parser.cpp b/parser.cpp index 80a52015c7..752a936b84 100644 --- a/parser.cpp +++ b/parser.cpp @@ -151,7 +151,7 @@ namespace Sass { // loop until end of string while (position < end) { - // parse comment blocks + // we should be able to refactor this parse_block_comments(); lex < css_whitespace >(); @@ -715,6 +715,7 @@ namespace Sass { Complex_Selector* Parser::parse_complex_selector(bool in_root) { + String* reference = 0; lex < block_comment >(); // parse the left hand side Compound_Selector* lhs = 0; @@ -732,6 +733,13 @@ namespace Sass { if (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO; else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES; else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF; + else if (lex< sequence < exactly<'/'>, negate < exactly < '*' > > > >()) { + // comments are allowed, but not spaces? + combinator = Complex_Selector::REFERENCE; + if (!lex < identifier >()) return 0; // ToDo: error msg? + reference = new (ctx.mem) String_Quoted(pstate, lexed); + if (!lex < exactly < '/' > >()) return 0; // ToDo: error msg? + } else /* if (lex< zero >()) */ combinator = Complex_Selector::ANCESTOR_OF; if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return 0; @@ -740,6 +748,7 @@ namespace Sass { // source position of a complex selector points to the combinator // ToDo: make sure we update pstate for ancestor of (lex < zero >()); Complex_Selector* sel = new (ctx.mem) Complex_Selector(pstate, combinator, lhs); + if (combinator == Complex_Selector::REFERENCE) sel->reference(reference); // has linfeed after combinator? sel->has_line_break(peek_newline()); // sel->has_line_feed(has_line_feed); @@ -937,7 +946,7 @@ namespace Sass { ParserState p = pstate; if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector", pstate); string name(lexed); - if (lex_css< exactly<']'> >()) return new (ctx.mem) Attribute_Selector(p, name, "", 0); + if (lex_css< alternatives < exactly<']'>, exactly<'/'> > >()) return new (ctx.mem) Attribute_Selector(p, name, "", 0); if (!lex_css< alternatives< exact_match, class_match, dash_match, prefix_match, suffix_match, substring_match > >()) { error("invalid operator in attribute selector for " + name, pstate); @@ -955,7 +964,7 @@ namespace Sass { error("expected a string constant or identifier in attribute selector for " + name, pstate); } - if (!lex_css< exactly<']'> >()) error("unterminated attribute selector for " + name, pstate); + if (!lex_css< alternatives < exactly<']'>, exactly<'/'> > >()) error("unterminated attribute selector for " + name, pstate); return new (ctx.mem) Attribute_Selector(p, name, matcher, value); } @@ -2133,6 +2142,11 @@ namespace Sass { // match `/deep/` selector (pass-trough) // there is no functionality for it yet exactly, + sequence < + exactly <'/'>, + identifier, + exactly <'/'> + >, // match selector ops /[*&%,()\[\]]/ class_char < selector_lookahead_ops >, // match selector combinators /[>+~]/