From e00aec60a385b4eededeaa2e3ac53fe05cc81dd4 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Mon, 11 May 2015 02:06:43 +0200 Subject: [PATCH] Fix interpolation edge case in value parsing Fixes https://github.com/sass/libsass/issues/442 --- parser.cpp | 21 +++++++++++++++++---- prelexer.cpp | 11 +++++++++++ prelexer.hpp | 6 +++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/parser.cpp b/parser.cpp index de252bccb4..17ad342bc1 100644 --- a/parser.cpp +++ b/parser.cpp @@ -415,7 +415,13 @@ namespace Sass { string name(Util::normalize_underscores(lexed)); ParserState var_source_position = pstate; if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate); - Expression* val = parse_list(); + Expression* val; + Selector_Lookahead lookahead = lookahead_for_value(position); + if (lookahead.has_interpolants && lookahead.found) { + val = parse_value_schema(lookahead.found); + } else { + val = parse_list(); + } val->is_delayed(false); bool is_default = false; bool is_global = false; @@ -1553,12 +1559,18 @@ namespace Sass { else if (lex< hex >()) { (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed)); } + else if (lex < exactly < '-' > >()) { + (*schema) << new (ctx.mem) String_Constant(pstate, lexed); + } else if (lex< quoted_string >()) { (*schema) << new (ctx.mem) String_Quoted(pstate, lexed); } else if (lex< variable >()) { (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed)); } + else if (peek< parenthese_scope >()) { + (*schema) << parse_factor(); + } else { error("error parsing interpolated value", pstate); } @@ -2160,12 +2172,13 @@ namespace Sass { (q = peek< percentage >(p)) || (q = peek< dimension >(p)) || (q = peek< quoted_string >(p)) || - (q = peek< variable >(p)) || + (q = peek< variable >(p)) || (q = peek< exactly<'*'> >(p)) || (q = peek< exactly<'+'> >(p)) || (q = peek< exactly<'~'> >(p)) || (q = peek< exactly<'>'> >(p)) || (q = peek< exactly<','> >(p)) || + (q = peek< sequence>(p)) || (saw_stuff && (q = peek< exactly<'-'> >(p))) || (q = peek< binomial >(p)) || (q = peek< block_comment >(p)) || @@ -2173,10 +2186,10 @@ namespace Sass { zero_plus, exactly<'n'> > >(p)) || (q = peek< sequence< optional, - one_plus > >(p)) || + one_plus > >(p)) || (q = peek< number >(p)) || (q = peek< sequence< exactly<'&'>, - identifier_alnums > >(p)) || + identifier_alnums > >(p)) || (q = peek< exactly<'&'> >(p)) || (q = peek< exactly<'%'> >(p)) || (q = peek< sequence< exactly<'.'>, interpolant > >(p)) || diff --git a/prelexer.cpp b/prelexer.cpp index c9146981ae..702b577ada 100644 --- a/prelexer.cpp +++ b/prelexer.cpp @@ -759,5 +759,16 @@ namespace Sass { alternatives< exactly<';'>, exactly<'}'> > >(src); } + + const char* parenthese_scope(const char* src) { + return sequence < + exactly < '(' >, + skip_over_scopes < + exactly < '(' >, + exactly < ')' > + > + >(src); + } + } } diff --git a/prelexer.hpp b/prelexer.hpp index a04cfe61b9..7d519c6fc0 100644 --- a/prelexer.hpp +++ b/prelexer.hpp @@ -86,7 +86,7 @@ namespace Sass { // find another opener inside? else if (const char* pos = start(src)) { - ++ level; // increase stack counter + ++ level; // increase counter src = pos - 1; // advance position } @@ -108,6 +108,10 @@ namespace Sass { return 0; } + // skip to a skip delimited by parentheses + // uses smart `skip_over_scopes` internally + const char* parenthese_scope(const char* src); + // skip to delimiter (mx) inside given range // this will savely skip over all quoted strings // recursive skip stuff delimited by start/stop