From 15bf6500cec17d6a69eea1760ce6836b2d70e26e Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Fri, 19 Feb 2016 22:21:50 +0100 Subject: [PATCH] Fix regression and issues with list and schema parsing Fixes #1901 Spec sass/sass-spec#731 --- src/ast.cpp | 5 +++++ src/ast.hpp | 1 + src/eval.cpp | 14 +++++++++++--- src/inspect.cpp | 5 ++++- src/parser.cpp | 46 ++++++++++++++++++++++++++++++++-------------- src/parser.hpp | 8 +++++++- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index 0b6248d4b6..9d2683f070 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -949,6 +949,7 @@ namespace Sass { Selector_List* Selector_List::parentize(Selector_List* ps, Context& ctx) { + if (!this->has_parent_ref()) return this; Selector_List* ss = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate()); for (size_t pi = 0, pL = ps->length(); pi < pL; ++pi) { Selector_List* list = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate()); @@ -1897,6 +1898,10 @@ namespace Sass { return false; } + bool String_Constant::is_invisible() const { + return value_.empty() && quote_mark_ == 0; + } + bool String_Constant::operator== (const Expression& rhs) const { if (const String_Quoted* qstr = dynamic_cast(&rhs)) { diff --git a/src/ast.hpp b/src/ast.hpp index 4663765e84..d2ce5a383f 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -1514,6 +1514,7 @@ namespace Sass { { } std::string type() { return "string"; } static std::string type_name() { return "string"; } + virtual bool is_invisible() const; virtual size_t hash() { diff --git a/src/eval.cpp b/src/eval.cpp index a751e4378e..a62bec4a7e 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1125,11 +1125,12 @@ namespace Sass { if (List* l = dynamic_cast(ex)) { List* ll = SASS_MEMORY_NEW(ctx.mem, List, l->pstate(), 0, l->separator()); // this fixes an issue with bourbon sample, not really sure why - if (l->size() && dynamic_cast((*l)[0])) { res += " "; } + // if (l->size() && dynamic_cast((*l)[0])) { res += ""; } for(auto item : *l) { item->is_interpolant(l->is_interpolant()); std::string rl(""); interpolation(ctx, rl, item, into_quotes, l->is_interpolant()); - if (rl != "") *ll << SASS_MEMORY_NEW(ctx.mem, String_Quoted, item->pstate(), rl); + bool is_null = dynamic_cast(item) != 0; // rl != "" + if (!is_null) *ll << SASS_MEMORY_NEW(ctx.mem, String_Quoted, item->pstate(), rl); } res += (ll->to_string(ctx.c_options)); ll->is_interpolant(l->is_interpolant()); @@ -1170,15 +1171,22 @@ namespace Sass { } } } + bool was_quoted = false; + bool was_interpolant = false; std::string res(""); for (size_t i = 0; i < L; ++i) { + bool is_quoted = dynamic_cast((*s)[i]) != NULL; (*s)[i]->perform(this); + if (was_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; } + else if (i > 0 && is_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; } Expression* ex = (*s)[i]->is_delayed() ? (*s)[i] : (*s)[i]->perform(this); interpolation(ctx, res, ex, into_quotes, ex->is_interpolant()); + was_quoted = dynamic_cast((*s)[i]) != NULL; + was_interpolant = (*s)[i]->is_interpolant(); } if (!s->is_interpolant()) { - if (res == "") return SASS_MEMORY_NEW(ctx.mem, Null, s->pstate()); + if (s->length() > 1 && res == "") return SASS_MEMORY_NEW(ctx.mem, Null, s->pstate()); return SASS_MEMORY_NEW(ctx.mem, String_Constant, s->pstate(), res); } String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), res); diff --git a/src/inspect.cpp b/src/inspect.cpp index e1a78c2586..b11be4ba58 100644 --- a/src/inspect.cpp +++ b/src/inspect.cpp @@ -406,7 +406,10 @@ namespace Sass { Expression* list_item = (*list)[i]; if (output_style() != TO_SASS) { if (list_item->is_invisible()) { - continue; + // this fixes an issue with "" in a list + if (!dynamic_cast(list_item)) { + continue; + } } } if (items_output) { diff --git a/src/parser.cpp b/src/parser.cpp index 5aac5dad34..38502a2e3d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1591,6 +1591,8 @@ namespace Sass { } const char* e = 0; + const char* ee = end; + end = stop; size_t num_items = 0; bool need_space = false; while (position < stop) { @@ -1600,7 +1602,7 @@ namespace Sass { } if (need_space) { need_space = false; - (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " "); + // (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " "); } if ((e = peek< re_functional >()) && e < stop) { (*schema) << parse_function_call(); @@ -1627,19 +1629,22 @@ namespace Sass { else if (lex< alternatives < exactly<'%'>, exactly < '-' >, exactly < '+' > > >()) { (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); } - else if (lex< sequence < identifier > >()) { - (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); + // lex a quoted string + else if (lex< quoted_string >()) { + // need_space = true; + // if (schema->length()) (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " "); + // else need_space = true; + (*schema) << parse_string(); if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) { - need_space = true; + // need_space = true; } + if (peek < exactly < '-' > >()) break; } - // lex a quoted string - else if (lex< quoted_string >()) { - (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, lexed, '"'); + else if (lex< sequence < identifier > >()) { + (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) { - need_space = true; + // need_space = true; } - if (peek < exactly < '-' > >()) return schema; } // lex (normalized) variable else if (lex< variable >()) { @@ -1670,10 +1675,15 @@ namespace Sass { (*schema) << parse_factor(); } else { - return schema; + break; } ++num_items; } + if (position != stop) { + (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(position, stop)); + position = stop; + } + end = ee; return schema; } @@ -2387,19 +2397,27 @@ namespace Sass { non_greedy < alternatives < // consume whitespace - block_comment, spaces, + block_comment, // spaces, // main tokens - interpolant, + sequence < + interpolant, + optional < + quoted_string + > + >, identifier, variable, // issue #442 sequence < parenthese_scope, - interpolant + interpolant, + optional < + quoted_string + > > >, sequence < - optional_spaces, + // optional_spaces, alternatives < exactly<'{'>, exactly<'}'>, diff --git a/src/parser.hpp b/src/parser.hpp index bbb62c8903..6cf9e2cf53 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -116,7 +116,10 @@ namespace Sass { const char* it_before_token = sneak < mx >(start); // match the given prelexer - return mx(it_before_token); + const char* match = mx(it_before_token); + + // check if match is in valid range + return match <= end ? match : 0; } @@ -142,6 +145,9 @@ namespace Sass { // now call matcher to get position after token const char* it_after_token = mx(it_before_token); + // check if match is in valid range + if (it_after_token > end) return 0; + // maybe we want to update the parser state anyway? if (force == false) { // assertion that we got a valid match