From 158a5af1d77ffcf0a5657ee0bcbb55e8a269424b Mon Sep 17 00:00:00 2001 From: Eric Kimn Date: Thu, 5 Feb 2015 05:15:28 -0800 Subject: [PATCH] Support parent selector & in values / and/or interpolations #548 --- ast.hpp | 7 ++++--- eval.cpp | 5 +++++ eval.hpp | 1 + expand.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- parser.cpp | 4 ++++ prelexer.cpp | 3 +++ prelexer.hpp | 1 + 7 files changed, 66 insertions(+), 4 deletions(-) diff --git a/ast.hpp b/ast.hpp index 7281b384a9..d2ca9af6a4 100644 --- a/ast.hpp +++ b/ast.hpp @@ -85,6 +85,7 @@ namespace Sass { STRING, LIST, MAP, + SELECTOR, NULL_VAL, NUM_TYPES }; @@ -1685,13 +1686,13 @@ namespace Sass { ///////////////////////////////////////// // Abstract base class for CSS selectors. ///////////////////////////////////////// - class Selector : public AST_Node { + class Selector : public Expression { ADD_PROPERTY(bool, has_reference); ADD_PROPERTY(bool, has_placeholder); public: Selector(ParserState pstate, bool r = false, bool h = false) - : AST_Node(pstate), has_reference_(r), has_placeholder_(h) - { } + : Expression(pstate), has_reference_(r), has_placeholder_(h) + { concrete_type(SELECTOR); } virtual ~Selector() = 0; virtual Selector_Placeholder* find_placeholder(); virtual int specificity() { return Constants::SPECIFICITY_BASE; } diff --git a/eval.cpp b/eval.cpp index cf4979c749..c0e9d97358 100644 --- a/eval.cpp +++ b/eval.cpp @@ -809,6 +809,11 @@ namespace Sass { e->is_interpolated()); } + Expression* Eval::operator()(Selector_Reference* e) + { + return e; + } + Expression* Eval::operator()(Null* n) { return n; diff --git a/eval.hpp b/eval.hpp index e3a2fed59c..3ea0252543 100644 --- a/eval.hpp +++ b/eval.hpp @@ -55,6 +55,7 @@ namespace Sass { Expression* operator()(String_Constant*); Expression* operator()(Media_Query*); Expression* operator()(Media_Query_Expression*); + Expression* operator()(Selector_Reference*); Expression* operator()(At_Root_Expression*); Expression* operator()(Feature_Query*); Expression* operator()(Feature_Query_Condition*); diff --git a/expand.cpp b/expand.cpp index e9e7d25514..5016ede01e 100644 --- a/expand.cpp +++ b/expand.cpp @@ -212,7 +212,54 @@ namespace Sass { if (!a->is_guarded() || v->concrete_type() == Expression::NULL_VAL) (*env)[var] = a->value()->perform(eval->with(env, backtrace)); } else { - env->current_frame()[var] = a->value()->perform(eval->with(env, backtrace)); + Selector_Reference* v = static_cast (a->value ()); + if (v->concrete_type () == Expression::SELECTOR) { + bool old_in_at_root = in_at_root; + in_at_root = false; + Contextualize* contextual = contextualize->with ( + selector_stack.back (), env, backtrace); + if (old_in_at_root && !v->has_reference ()) + contextual = contextualize->with (at_root_selector_stack.back (), + env, backtrace); + + Selector* sel_ctx = v->perform (contextual); + + Inspect isp (0); + sel_ctx->perform (&isp); + string str = isp.get_buffer (); + str += ";"; + + Parser p (ctx, ParserState ("[REPARSE]", 0)); + p.source = str.c_str (); + p.position = str.c_str (); + p.end = str.c_str () + strlen (str.c_str ()); + Selector_List* sel_lst = p.parse_selector_group (); + sel_lst->pstate (isp.source_map.remap (sel_lst->pstate ())); + + for (size_t i = 0; i < sel_lst->length (); i++) { + Complex_Selector* pIter = (*sel_lst)[i]; + while (pIter) { + Compound_Selector* pHead = pIter->head (); + pIter->pstate (isp.source_map.remap (pIter->pstate ())); + if (pHead) { + pHead->pstate (isp.source_map.remap (pHead->pstate ())); + (*pHead)[0]->pstate ( + isp.source_map.remap ((*pHead)[0]->pstate ())); + } + pIter = pIter->tail (); + } + } + sel_ctx = sel_lst; + + selector_stack.push_back (sel_ctx); + selector_stack.pop_back (); + in_at_root = old_in_at_root; + old_in_at_root = false; + env->current_frame ()[var] = sel_ctx; + } + else { + env->current_frame()[var] = a->value()->perform(eval->with(env, backtrace)); + } } return 0; } diff --git a/parser.cpp b/parser.cpp index c03abc8048..de133130ce 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1219,6 +1219,10 @@ namespace Sass { if (lex< sequence< exactly<'%'>, optional< percentage > > >()) { return new (ctx.mem) String_Constant(pstate, lexed); } + if (lex< ampersand >()) + { + return new (ctx.mem) Selector_Reference(pstate); + } error("error reading values after " + lexed.to_string(), pstate); // unreachable statement diff --git a/prelexer.cpp b/prelexer.cpp index d63180e256..f385912dd6 100644 --- a/prelexer.cpp +++ b/prelexer.cpp @@ -404,6 +404,9 @@ namespace Sass { const char* percentage(const char* src) { return sequence< number, exactly<'%'> >(src); } + const char* ampersand(const char* src) { + return exactly<'&'>(src); + } const char* em(const char* src) { return sequence< number, exactly >(src); diff --git a/prelexer.hpp b/prelexer.hpp index 3c08003ae6..3351bf8348 100644 --- a/prelexer.hpp +++ b/prelexer.hpp @@ -408,6 +408,7 @@ namespace Sass { const char* coefficient(const char* src); const char* binomial(const char* src); const char* percentage(const char* src); + const char* ampersand(const char* src); const char* dimension(const char* src); const char* hex(const char* src); const char* hexa(const char* src);