From 62eb24a74ec0b24bcef8c94be18bc25d4b3ef38f Mon Sep 17 00:00:00 2001 From: xzyfer Date: Sun, 4 Jan 2015 15:33:28 +1100 Subject: [PATCH] Add support for bubbling feature queries --- ast.hpp | 21 +++++++-------- cssize.cpp | 73 ++++++++++++++++++++++++++++++++++++++--------------- cssize.hpp | 3 ++- inspect.cpp | 2 +- parser.cpp | 1 + 5 files changed, 67 insertions(+), 33 deletions(-) diff --git a/ast.hpp b/ast.hpp index d33a31c7f0..af2f4411ba 100644 --- a/ast.hpp +++ b/ast.hpp @@ -410,8 +410,9 @@ namespace Sass { public: Feature_Block(string path, Position position, Feature_Query* fqs, Block* b) : Has_Block(path, position, b), feature_queries_(fqs), selector_(0) - { } + { statement_type(FEATURE); } bool is_hoistable() { return true; } + bool bubbles() { return true; } ATTACH_OPERATIONS(); }; @@ -427,6 +428,7 @@ namespace Sass { At_Rule(string path, Position position, string kwd, Selector* sel = 0, Block* b = 0) : Has_Block(path, position, b), keyword_(kwd), selector_(sel), value_(0) // set value manually if needed { statement_type(DIRECTIVE); } + bool bubbles() { return true; } ATTACH_OPERATIONS(); }; @@ -1514,15 +1516,9 @@ namespace Sass { bool exclude(string str) { To_String to_string; -DEBUG_PRINTLN(ALL, "feature() => " << (feature_ != 0 ? "true" : "false")); -DEBUG_PRINTLN(ALL, "value() => " << (value_ ? "true" : "false")); bool with = feature() && static_cast(feature())->value().compare("with") == 0; -DEBUG_PRINTLN(ALL, "with => " << with); // List* l = static_cast(value()); string v = value() ? static_cast(value())->value() : "rule"; -DEBUG_PRINTLN(ALL, "v => " << v); -DEBUG_PRINTLN(ALL, "str => " << str); - if (with) { @@ -1556,19 +1552,24 @@ DEBUG_PRINTLN(ALL, "str => " << str); bool exclude_node(Statement* s) { if (s->statement_type() == Statement::DIRECTIVE) { - DEBUG_PRINTLN(ALL, "DIRECTIVE"); return expression()->exclude(static_cast(s)->keyword().erase(0, 1)); } + if (s->statement_type() == Statement::MEDIA) + { + return expression()->exclude("media"); + } if (s->statement_type() == Statement::KEYFRAME) { - DEBUG_PRINTLN(ALL, "KEYFRAME"); return expression()->exclude("keyframes"); } if (s->statement_type() == Statement::RULESET) { - DEBUG_PRINTLN(ALL, "RULESET"); return expression()->exclude("rule"); } + if (s->statement_type() == Statement::FEATURE) + { + return expression()->exclude("supports"); + } return false; } ATTACH_OPERATIONS(); diff --git a/cssize.cpp b/cssize.cpp index 586aac0140..148ead84f5 100644 --- a/cssize.cpp +++ b/cssize.cpp @@ -106,33 +106,42 @@ namespace Sass { return debubble(mm->block(), mm)->block(); } - Statement* Cssize::operator()(At_Root_Block* m) + Statement* Cssize::operator()(Feature_Block* m) { - // # If there aren't any more directives or rules that this @at-root needs to - // # exclude, we can get rid of it and just evaluate the children. - // if @parents.none? {|n| node.exclude_node?(n)} - // results = visit_children_without_parent(node) - // results.each {|c| c.tabs += node.tabs if bubblable?(c)} - // if !results.empty? && bubblable?(results.last) - // results.last.group_end = node.group_end - // end - // return results - // end - - // To_String to_string; - // DEBUG_PRINTLN(ALL, m->perform(&to_string)); + if (!m->block()->length()) + { return m; } + + if (parent()->statement_type() == Statement::RULESET) + { return bubble(m); } + + p_stack.push_back(m); + + Feature_Block* mm = new (ctx.mem) Feature_Block(m->path(), + m->position(), + m->feature_queries(), + m->block()->perform(this)->block()); + mm->tabs(m->tabs()); + + p_stack.pop_back(); + return debubble(mm->block(), mm)->block(); + } + + Statement* Cssize::operator()(At_Root_Block* m) + { bool tmp = false; for (size_t i = 0, L = p_stack.size(); i < L; ++i) { Statement* s = p_stack[i]; tmp |= m->exclude_node(s); } - DEBUG_PRINTLN(ALL, "tmp => " << tmp); - if (!tmp) { Block* bb = m->block()->perform(this)->block(); + // results.each {|c| c.tabs += node.tabs if bubblable?(c)} + // if !results.empty? && bubblable?(results.last) + // results.last.group_end = node.group_end + // end return bb; } @@ -145,6 +154,28 @@ namespace Sass { } inline Statement* Cssize::bubble(At_Root_Block* m) + { + Block* bb = new (ctx.mem) Block(this->parent()->path(), this->parent()->position()); + Has_Block* new_rule = static_cast(this->parent()); + new_rule->block(bb); + new_rule->tabs(this->parent()->tabs()); + + for (size_t i = 0, L = m->block()->length(); i < L; ++i) { + *new_rule->block() << (*m->block())[i]; + } + + Block* wrapper_block = new (ctx.mem) Block(m->block()->path(), m->block()->position()); + *wrapper_block << new_rule; + At_Root_Block* mm = new (ctx.mem) At_Root_Block(m->path(), + m->position(), + wrapper_block, + m->expression()); + + Bubble* bubble = new (ctx.mem) Bubble(mm->path(), mm->position(), mm); + return bubble; + } + + inline Statement* Cssize::bubble(Feature_Block* m) { Ruleset* parent = static_cast(this->parent()); @@ -161,10 +192,10 @@ namespace Sass { Block* wrapper_block = new (ctx.mem) Block(m->block()->path(), m->block()->position()); *wrapper_block << new_rule; - At_Root_Block* mm = new (ctx.mem) At_Root_Block(m->path(), + Feature_Block* mm = new (ctx.mem) Feature_Block(m->path(), m->position(), - wrapper_block, - m->expression()); + m->feature_queries(), + wrapper_block); Bubble* bubble = new (ctx.mem) Bubble(mm->path(), mm->position(), mm); return bubble; @@ -298,11 +329,11 @@ namespace Sass { ss = b->node(); } + if (!ss) continue; + ss->tabs(ss->tabs() + b->tabs()); ss->group_end(b->group_end()); - if (!ss) continue; - Block* bb = new (ctx.mem) Block(children->block()->path(), children->block()->position(), children->block()->length(), diff --git a/cssize.hpp b/cssize.hpp index 3067eb10d2..32c15c3d08 100644 --- a/cssize.hpp +++ b/cssize.hpp @@ -42,7 +42,7 @@ namespace Sass { // Statement* operator()(Propset*); // Statement* operator()(Bubble*); Statement* operator()(Media_Block*); - // Statement* operator()(Feature_Block*); + Statement* operator()(Feature_Block*); Statement* operator()(At_Root_Block*); // Statement* operator()(At_Rule*); // Statement* operator()(Declaration*); @@ -69,6 +69,7 @@ namespace Sass { vector> slice_by_bubble(Statement*); Statement* bubble(At_Root_Block*); Statement* bubble(Media_Block*); + Statement* bubble(Feature_Block*); Statement* debubble(Block* children, Statement* parent = 0); Statement* flatten(Statement*); bool bubblable(Statement*); diff --git a/inspect.cpp b/inspect.cpp index 4da25f5c66..a4de993bad 100644 --- a/inspect.cpp +++ b/inspect.cpp @@ -80,7 +80,7 @@ namespace Sass { void Inspect::operator()(At_Root_Block* at_root_block) { if (ctx) ctx->source_map.add_mapping(at_root_block); - append_to_buffer("@at-rule "); + append_to_buffer("@at-root "); if(at_root_block->expression()) at_root_block->expression()->perform(this); at_root_block->block()->perform(this); } diff --git a/parser.cpp b/parser.cpp index 515dc90e16..8836e7525e 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1767,6 +1767,7 @@ namespace Sass { in_at_root = true; if (peek< exactly<'('> >()) { expr = parse_at_root_expression(); + body = parse_block(); } else if (peek< exactly<'{'> >()) { body = parse_block();