From 61b6d568762b78993d7a8dafe891ea67dd15d9d9 Mon Sep 17 00:00:00 2001 From: xzyfer Date: Sun, 11 Oct 2015 17:55:39 +1100 Subject: [PATCH] Fix regression is allowing `@extend`ing across media queries This PR fixes a regression is allowing `@extend`ing across media queries. Still needs a bit of work. Regressed in 9f5ef6da0e8ec9287cd800bf98174f049591b286 Fixes #1562 Spec https://github.com/sass/sass-spec/pull/538 --- src/ast.cpp | 3 +++ src/eval.cpp | 1 + src/expand.cpp | 6 +++++- src/parser.cpp | 19 +++++++++++++++++-- src/parser.hpp | 3 ++- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index 871bf6e2dd..5a52bd4414 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -1121,6 +1121,7 @@ namespace Sass { Complex_Selector* Complex_Selector::clone(Context& ctx) const { Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this); + cpy->media_block(this->media_block()); if (tail()) cpy->tail(tail()->clone(ctx)); return cpy; } @@ -1143,12 +1144,14 @@ namespace Sass { Compound_Selector* Compound_Selector::clone(Context& ctx) const { Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *this); + cpy->media_block(this->media_block()); return cpy; } Selector_List* Selector_List::clone(Context& ctx) const { Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, *this); + cpy->media_block(this->media_block()); return cpy; } diff --git a/src/eval.cpp b/src/eval.cpp index b14d017ef5..13323912c6 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1395,6 +1395,7 @@ namespace Sass { { std::vector rv; Selector_List* sl = SASS_MEMORY_NEW(ctx.mem, Selector_List, s->pstate()); + sl->media_block(s->media_block()); for (size_t i = 0, iL = s->length(); i < iL; ++i) { rv.push_back(operator()((*s)[i])); } diff --git a/src/expand.cpp b/src/expand.cpp index 1db33ec796..a485462db5 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -550,9 +550,13 @@ namespace Sass { dynamic_cast((*sel->head())[0]))) { Compound_Selector* hh = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, (*extender)[i]->pstate()); + hh->media_block((*extender)[i]->media_block()); Complex_Selector* ssel = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, (*extender)[i]->pstate()); + ssel->media_block((*extender)[i]->media_block()); if (sel->has_line_feed()) ssel->has_line_feed(true); - *hh << SASS_MEMORY_NEW(ctx.mem, Parent_Selector, (*extender)[i]->pstate()); + Parent_Selector* ps = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, (*extender)[i]->pstate()); + ps->media_block((*extender)[i]->media_block()); + *hh << ps; ssel->tail(sel); ssel->head(hh); sel = ssel; diff --git a/src/parser.cpp b/src/parser.cpp index 08d163e2a7..e6e04859ea 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -609,6 +609,7 @@ namespace Sass { String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate); // the selector schema is pretty much just a wrapper for the string schema Selector_Schema* selector_schema = SASS_MEMORY_NEW(ctx.mem, Selector_Schema, pstate, schema); + selector_schema->media_block(last_media_block); // process until end while (i < end_of_selector) { @@ -693,6 +694,7 @@ namespace Sass { Complex_Selector* sel = 0; To_String to_string(&ctx); Selector_List* group = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate); + group->media_block(last_media_block); do { reloop = false; @@ -774,6 +776,8 @@ 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 = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pstate, combinator, lhs); + sel->media_block(last_media_block); + if (combinator == Complex_Selector::REFERENCE) sel->reference(reference); // has linfeed after combinator? sel->has_line_break(peek_newline()); @@ -795,13 +799,18 @@ namespace Sass { if (!sel->has_reference() && !in_at_root && !in_root) { // create the objects to wrap parent selector reference Parent_Selector* parent = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate); + parent->media_block(last_media_block); Compound_Selector* head = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pstate); + head->media_block(last_media_block); // add simple selector (*head) << parent; // selector may not have any head yet if (!sel->head()) { sel->head(head); } // otherwise we need to create a new complex selector and set the old one as its tail - else { sel = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pstate, Complex_Selector::ANCESTOR_OF, head, sel); } + else { + sel = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pstate, Complex_Selector::ANCESTOR_OF, head, sel); + sel->media_block(last_media_block); + } // peek for linefeed and remember result on head // if (peek_newline()) head->has_line_break(true); } @@ -818,6 +827,7 @@ namespace Sass { { // init an empty compound selector wrapper Compound_Selector* seq = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pstate); + seq->media_block(last_media_block); // skip initial white-space lex< css_whitespace >(); @@ -892,7 +902,9 @@ namespace Sass { return parse_attribute_selector(); } else if (lex< placeholder >()) { - return SASS_MEMORY_NEW(ctx.mem, Selector_Placeholder, pstate, lexed); + Selector_Placeholder* sel = SASS_MEMORY_NEW(ctx.mem, Selector_Placeholder, pstate, lexed); + sel->media_block(last_media_block); + return sel; } // failed return 0; @@ -1912,7 +1924,10 @@ namespace Sass { Media_Block* media_block = SASS_MEMORY_NEW(ctx.mem, Media_Block, pstate, 0, 0); media_block->media_queries(parse_media_queries()); + Media_Block* prev_media_block = last_media_block; + last_media_block = media_block; media_block->block(parse_css_block()); + last_media_block = prev_media_block; return media_block; } diff --git a/src/parser.hpp b/src/parser.hpp index 6639f4577d..92b665915f 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -32,6 +32,7 @@ namespace Sass { Context& ctx; std::vector block_stack; std::vector stack; + Media_Block* last_media_block; const char* source; const char* position; const char* end; @@ -45,7 +46,7 @@ namespace Sass { bool in_at_root; Parser(Context& ctx, const ParserState& pstate) - : ParserState(pstate), ctx(ctx), block_stack(0), stack(0), + : ParserState(pstate), ctx(ctx), block_stack(0), stack(0), last_media_block(0), source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate(pstate), indentation(0) { in_at_root = false; stack.push_back(nothing); }