From a262eede94a80aa79d2b1eee05b667d5855a7005 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Mon, 15 Jun 2015 22:24:26 +0200 Subject: [PATCH] Implement initial parts for reference combinators --- ast.hpp | 5 +++-- debugger.hpp | 2 ++ eval.cpp | 4 ++++ extend.cpp | 1 + inspect.cpp | 7 +++++++ listize.cpp | 6 ++++++ node.cpp | 1 + parser.cpp | 18 ++++++++++++++++-- 8 files changed, 40 insertions(+), 4 deletions(-) diff --git a/ast.hpp b/ast.hpp index 97227fead8..ca1b42aeb9 100644 --- a/ast.hpp +++ b/ast.hpp @@ -2052,11 +2052,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; @@ -2067,7 +2068,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 0fc344347a..e9e6462e1d 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 60d7f978fe..6ede753b41 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->size(); 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 90068ba5ad..b59ed12b45 100644 --- a/inspect.cpp +++ b/inspect.cpp @@ -930,6 +930,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 8c0e669c64..8cfae231ed 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_Constant(sel->pstate(), "+"); break; + case Complex_Selector::REFERENCE: + *l << new (ctx.mem) String_Constant(sel->pstate(), "/" + reference + "/"); + break; case Complex_Selector::PRECEDES: *l << new (ctx.mem) String_Constant(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 2fb1c8f9b9..28f0853b0f 100644 --- a/parser.cpp +++ b/parser.cpp @@ -683,6 +683,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; @@ -700,6 +701,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_Constant(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; @@ -708,6 +716,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); @@ -905,7 +914,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); @@ -923,7 +932,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); } @@ -2067,6 +2076,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 /[>+~]/