Skip to content

Commit 965f226

Browse files
committed
Merge pull request #1534 from mgreter/hotfix/additional-escapes-in-interpolate
Fix regression for interpolation adding additional escapes
2 parents 3ade3d0 + 4fe91c6 commit 965f226

File tree

9 files changed

+48
-19
lines changed

9 files changed

+48
-19
lines changed

src/ast.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,10 +1424,10 @@ namespace Sass {
14241424
////////////////////////////////////////////////////////
14251425
class String_Quoted : public String_Constant {
14261426
public:
1427-
String_Quoted(ParserState pstate, std::string val, char q = 0)
1427+
String_Quoted(ParserState pstate, std::string val, char q = 0, bool keep_utf8_escapes = false)
14281428
: String_Constant(pstate, val)
14291429
{
1430-
value_ = unquote(value_, &quote_mark_);
1430+
value_ = unquote(value_, &quote_mark_, keep_utf8_escapes);
14311431
if (q && quote_mark_) quote_mark_ = q;
14321432
}
14331433
virtual bool operator==(const Expression& rhs) const;

src/eval.cpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,7 @@ namespace Sass {
861861
}
862862
}
863863

864-
std::string Eval::interpolation(Expression* s) {
864+
std::string Eval::interpolation(Expression* s, bool into_quotes) {
865865
Env* env = environment();
866866
if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>(s)) {
867867
if (str_quoted->quote_mark()) {
@@ -874,6 +874,7 @@ namespace Sass {
874874
return evacuate_escapes(str_quoted->value());
875875
}
876876
} else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
877+
if (into_quotes && !str_constant->is_interpolant()) return str_constant->value();
877878
return evacuate_escapes(str_constant->value());
878879
} else if (dynamic_cast<Parent_Selector*>(s)) {
879880
To_String to_string(&ctx);
@@ -936,7 +937,17 @@ namespace Sass {
936937
Expression* Eval::operator()(String_Schema* s)
937938
{
938939
std::string acc;
939-
for (size_t i = 0, L = s->length(); i < L; ++i) {
940+
bool into_quotes = false;
941+
size_t L = s->length();
942+
if (L > 1) {
943+
if (String_Constant* l = dynamic_cast<String_Constant*>((*s)[0])) {
944+
if (String_Constant* r = dynamic_cast<String_Constant*>((*s)[L - 1])) {
945+
if (l->value()[0] == '"' && r->value()[r->value().size() - 1] == '"') into_quotes = true;
946+
if (l->value()[0] == '\'' && r->value()[r->value().size() - 1] == '\'') into_quotes = true;
947+
}
948+
}
949+
}
950+
for (size_t i = 0; i < L; ++i) {
940951
// really a very special fix, but this is the logic I got from
941952
// analyzing the ruby sass behavior and it actually seems to work
942953
// https://github.com/sass/libsass/issues/1333
@@ -946,13 +957,13 @@ namespace Sass {
946957
if (sq->is_delayed() && ! s->has_interpolants()) {
947958
acc += string_escape(quote(sq->value(), sq->quote_mark()));
948959
} else {
949-
acc += interpolation((*s)[i]);
960+
acc += interpolation((*s)[i], into_quotes);
950961
}
951962
} else if (ex) {
952-
acc += interpolation((*s)[i]);
963+
acc += interpolation((*s)[i], into_quotes);
953964
}
954965
} else if ((*s)[i]) {
955-
acc += interpolation((*s)[i]);
966+
acc += interpolation((*s)[i], into_quotes);
956967
}
957968
}
958969
String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), acc);
@@ -1316,12 +1327,17 @@ namespace Sass {
13161327
if (ltype == Expression::NULL_VAL) error("invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs.pstate());
13171328
if (rtype == Expression::NULL_VAL) error("invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", rhs.pstate());
13181329

1319-
String_Constant* str = (ltype == Expression::STRING || sep == "") &&
1320-
(sep != "/" || !rqstr || !rqstr->quote_mark())
1321-
? SASS_MEMORY_NEW(mem, String_Quoted, lhs.pstate(), (lstr) + sep + (rstr))
1322-
: SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), (lstr) + sep + quote(rstr));
1323-
str->quote_mark(0);
1324-
return str;
1330+
if ( (ltype == Expression::STRING || sep == "") &&
1331+
(sep != "/" || !rqstr || !rqstr->quote_mark())
1332+
) {
1333+
char quote_mark = 0;
1334+
std::string unq(unquote(lstr + sep + rstr, &quote_mark, true));
1335+
if (quote_mark && quote_mark != '*') {
1336+
return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), quote_mark + unq + quote_mark);
1337+
}
1338+
return SASS_MEMORY_NEW(mem, String_Quoted, lhs.pstate(), lstr + sep + rstr);
1339+
}
1340+
return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), (lstr) + sep + quote(rstr));
13251341
}
13261342

13271343
Expression* cval_to_astnode(Memory_Manager<AST_Node>& mem, union Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)

src/eval.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ namespace Sass {
9696
static Value* op_strings(Memory_Manager<AST_Node>&, enum Sass_OP, Value&, Value&, bool compressed = false, int precision = 5);
9797

9898
private:
99-
std::string interpolation(Expression* s);
99+
std::string interpolation(Expression* s, bool into_quotes = false);
100100

101101
};
102102

src/functions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ namespace Sass {
879879
return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
880880
}
881881
else if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
882-
String_Quoted* result = SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, string_quoted->value());
882+
String_Constant* result = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, string_quoted->value());
883883
// remember if the string was quoted (color tokens)
884884
result->sass_fix_1291(string_quoted->quote_mark() != 0);
885885
return result;

src/parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@ namespace Sass {
14601460
if (lex< sequence< dimension, optional< sequence< exactly<'-'>, negate< digit > > > > >())
14611461
{ return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::DIMENSION, lexed); }
14621462

1463-
if (lex< sequence< static_component, one_plus< identifier > > >())
1463+
if (lex< sequence< static_component, one_plus< strict_identifier > > >())
14641464
{ return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); }
14651465

14661466
if (lex< number >())

src/prelexer.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ namespace Sass {
108108
>(src);
109109
}
110110

111+
// Match CSS identifiers.
112+
const char* strict_identifier(const char* src)
113+
{
114+
return sequence<
115+
one_plus < strict_identifier_alpha >,
116+
zero_plus < strict_identifier_alnum >
117+
// word_boundary not needed
118+
>(src);
119+
}
120+
111121
// Match CSS identifiers.
112122
const char* identifier(const char* src)
113123
{

src/prelexer.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ namespace Sass {
195195
const char* identifier(const char* src);
196196
const char* identifier_alpha(const char* src);
197197
const char* identifier_alnum(const char* src);
198+
const char* strict_identifier(const char* src);
198199
const char* strict_identifier_alpha(const char* src);
199200
const char* strict_identifier_alnum(const char* src);
200201
// Match a CSS unit identifier.

src/util.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ namespace Sass {
355355
return quote_mark;
356356
}
357357

358-
std::string unquote(const std::string& s, char* qd)
358+
std::string unquote(const std::string& s, char* qd, bool keep_utf8_sequences)
359359
{
360360

361361
// not enough room for quotes
@@ -395,7 +395,9 @@ namespace Sass {
395395
while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
396396

397397
// hex string?
398-
if (len > 1) {
398+
if (keep_utf8_sequences) {
399+
unq.push_back(s[i]);
400+
} else if (len > 1) {
399401

400402
// convert the extracted hex string to code point value
401403
// ToDo: Maybe we could do this without creating a substring

src/util.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace Sass {
2626
std::string normalize_wspace(const std::string& str);
2727

2828
std::string quote(const std::string&, char q = 0, bool keep_linefeed_whitespace = false);
29-
std::string unquote(const std::string&, char* q = 0);
29+
std::string unquote(const std::string&, char* q = 0, bool keep_utf8_sequences = false);
3030
char detect_best_quotemark(const char* s, char qm = '"');
3131

3232
bool is_hex_doublet(double n);

0 commit comments

Comments
 (0)