Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix for interpolation adding additional escapes #1534

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1424,10 +1424,10 @@ namespace Sass {
////////////////////////////////////////////////////////
class String_Quoted : public String_Constant {
public:
String_Quoted(ParserState pstate, std::string val, char q = 0)
String_Quoted(ParserState pstate, std::string val, char q = 0, bool keep_utf8_escapes = false)
: String_Constant(pstate, val)
{
value_ = unquote(value_, &quote_mark_);
value_ = unquote(value_, &quote_mark_, keep_utf8_escapes);
if (q && quote_mark_) quote_mark_ = q;
}
virtual bool operator==(const Expression& rhs) const;
Expand Down
38 changes: 27 additions & 11 deletions src/eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,7 @@ namespace Sass {
}
}

std::string Eval::interpolation(Expression* s) {
std::string Eval::interpolation(Expression* s, bool into_quotes) {
Env* env = environment();
if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>(s)) {
if (str_quoted->quote_mark()) {
Expand All @@ -874,6 +874,7 @@ namespace Sass {
return evacuate_escapes(str_quoted->value());
}
} else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
if (into_quotes && !str_constant->is_interpolant()) return str_constant->value();
return evacuate_escapes(str_constant->value());
} else if (dynamic_cast<Parent_Selector*>(s)) {
To_String to_string(&ctx);
Expand Down Expand Up @@ -936,7 +937,17 @@ namespace Sass {
Expression* Eval::operator()(String_Schema* s)
{
std::string acc;
for (size_t i = 0, L = s->length(); i < L; ++i) {
bool into_quotes = false;
size_t L = s->length();
if (L > 1) {
if (String_Constant* l = dynamic_cast<String_Constant*>((*s)[0])) {
if (String_Constant* r = dynamic_cast<String_Constant*>((*s)[L - 1])) {
if (l->value()[0] == '"' && r->value()[r->value().size() - 1] == '"') into_quotes = true;
if (l->value()[0] == '\'' && r->value()[r->value().size() - 1] == '\'') into_quotes = true;
}
}
}
for (size_t i = 0; i < L; ++i) {
// really a very special fix, but this is the logic I got from
// analyzing the ruby sass behavior and it actually seems to work
// https://github.com/sass/libsass/issues/1333
Expand All @@ -946,13 +957,13 @@ namespace Sass {
if (sq->is_delayed() && ! s->has_interpolants()) {
acc += string_escape(quote(sq->value(), sq->quote_mark()));
} else {
acc += interpolation((*s)[i]);
acc += interpolation((*s)[i], into_quotes);
}
} else if (ex) {
acc += interpolation((*s)[i]);
acc += interpolation((*s)[i], into_quotes);
}
} else if ((*s)[i]) {
acc += interpolation((*s)[i]);
acc += interpolation((*s)[i], into_quotes);
}
}
String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), acc);
Expand Down Expand Up @@ -1316,12 +1327,17 @@ namespace Sass {
if (ltype == Expression::NULL_VAL) error("invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs.pstate());
if (rtype == Expression::NULL_VAL) error("invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", rhs.pstate());

String_Constant* str = (ltype == Expression::STRING || sep == "") &&
(sep != "/" || !rqstr || !rqstr->quote_mark())
? SASS_MEMORY_NEW(mem, String_Quoted, lhs.pstate(), (lstr) + sep + (rstr))
: SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), (lstr) + sep + quote(rstr));
str->quote_mark(0);
return str;
if ( (ltype == Expression::STRING || sep == "") &&
(sep != "/" || !rqstr || !rqstr->quote_mark())
) {
char quote_mark = 0;
std::string unq(unquote(lstr + sep + rstr, &quote_mark, true));
if (quote_mark && quote_mark != '*') {
return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), quote_mark + unq + quote_mark);
}
return SASS_MEMORY_NEW(mem, String_Quoted, lhs.pstate(), lstr + sep + rstr);
}
return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), (lstr) + sep + quote(rstr));
}

Expression* cval_to_astnode(Memory_Manager<AST_Node>& mem, union Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
Expand Down
2 changes: 1 addition & 1 deletion src/eval.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ namespace Sass {
static Value* op_strings(Memory_Manager<AST_Node>&, enum Sass_OP, Value&, Value&, bool compressed = false, int precision = 5);

private:
std::string interpolation(Expression* s);
std::string interpolation(Expression* s, bool into_quotes = false);

};

Expand Down
2 changes: 1 addition & 1 deletion src/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ namespace Sass {
return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
}
else if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
String_Quoted* result = SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, string_quoted->value());
String_Constant* result = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, string_quoted->value());
// remember if the string was quoted (color tokens)
result->sass_fix_1291(string_quoted->quote_mark() != 0);
return result;
Expand Down
2 changes: 1 addition & 1 deletion src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1460,7 +1460,7 @@ namespace Sass {
if (lex< sequence< dimension, optional< sequence< exactly<'-'>, negate< digit > > > > >())
{ return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::DIMENSION, lexed); }

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

if (lex< number >())
Expand Down
10 changes: 10 additions & 0 deletions src/prelexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ namespace Sass {
>(src);
}

// Match CSS identifiers.
const char* strict_identifier(const char* src)
{
return sequence<
one_plus < strict_identifier_alpha >,
zero_plus < strict_identifier_alnum >
// word_boundary not needed
>(src);
}

// Match CSS identifiers.
const char* identifier(const char* src)
{
Expand Down
1 change: 1 addition & 0 deletions src/prelexer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ namespace Sass {
const char* identifier(const char* src);
const char* identifier_alpha(const char* src);
const char* identifier_alnum(const char* src);
const char* strict_identifier(const char* src);
const char* strict_identifier_alpha(const char* src);
const char* strict_identifier_alnum(const char* src);
// Match a CSS unit identifier.
Expand Down
6 changes: 4 additions & 2 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ namespace Sass {
return quote_mark;
}

std::string unquote(const std::string& s, char* qd)
std::string unquote(const std::string& s, char* qd, bool keep_utf8_sequences)
{

// not enough room for quotes
Expand Down Expand Up @@ -357,7 +357,9 @@ namespace Sass {
while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;

// hex string?
if (len > 1) {
if (keep_utf8_sequences) {
unq.push_back(s[i]);
} else if (len > 1) {

// convert the extracted hex string to code point value
// ToDo: Maybe we could do this without creating a substring
Expand Down
2 changes: 1 addition & 1 deletion src/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace Sass {
std::string normalize_wspace(const std::string& str);

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

bool is_hex_doublet(double n);
Expand Down