Use Ruby Sass string semantics.

This commit is contained in:
Natalie Weizenbaum 2016-10-18 15:17:46 -07:00
parent 286b24afca
commit e7024437d8
4 changed files with 45 additions and 11 deletions

View File

@ -13,8 +13,7 @@ import '../interpolation.dart';
/// A string literal.
class StringExpression implements Expression {
/// Interpolation that, when evaluated, produces the semantic content of this
/// string.
/// Interpolation that, when evaluated, produces the contents of this string.
///
/// Unlike [asInterpolation], escapes are resolved and quotes are not
/// included.
@ -41,7 +40,14 @@ class StringExpression implements Expression {
///
/// Unlike [text], his doesn't resolve escapes and does include quotes for
/// quoted strings.
///
/// If [static] is true, this escapes any `#{` sequences in the string. If
/// [quote] is passed and this is a quoted string, it uses that character as
/// the quote mark; otherwise, it determines the best quote to add by looking
/// at the string.
Interpolation asInterpolation({bool static: false, int quote}) {
if (!hasQuotes) return text;
quote ??= hasQuotes ? null : _bestQuote();
var buffer = new InterpolationBuffer();
if (quote != null) buffer.writeCharCode(quote);

View File

@ -1882,7 +1882,7 @@ abstract class StylesheetParser extends Parser {
} else if (isNameStart(first)) {
buffer.writeCharCode(scanner.readChar());
} else if (first == $backslash) {
buffer.writeCharCode(escape());
_scanEscapeText(buffer);
} else if (first == $hash && scanner.peekChar(1) == $lbrace) {
buffer.add(singleInterpolation());
}
@ -1897,7 +1897,7 @@ abstract class StylesheetParser extends Parser {
next >= 0x0080) {
buffer.writeCharCode(scanner.readChar());
} else if (next == $backslash) {
buffer.writeCharCode(escape());
_scanEscapeText(buffer);
} else if (next == $hash && scanner.peekChar(1) == $lbrace) {
buffer.add(singleInterpolation());
} else {
@ -1908,6 +1908,31 @@ abstract class StylesheetParser extends Parser {
return buffer.interpolation(scanner.spanFrom(start));
}
/// Consumes an escape sequence and writes the characters that compose it to
/// [buffer].
void _scanEscapeText(StringSink buffer) {
scanner.expectChar($backslash);
buffer.writeCharCode($backslash);
var first = scanner.peekChar();
if (first == null) {
return;
} else if (isNewline(first)) {
scanner.error("Expected escape sequence.");
} else if (isHex(first)) {
for (var i = 0; i < 6; i++) {
var next = scanner.peekChar();
if (next == null || !isHex(next)) break;
buffer.writeCharCode(scanner.readChar());
}
if (isWhitespace(scanner.peekChar())) {
buffer.writeCharCode(scanner.readChar());
}
} else {
buffer.writeCharCode(scanner.readChar());
}
}
/// Consumes interpolation.
Expression singleInterpolation() {
scanner.expect('#{');

View File

@ -14,8 +14,16 @@ import '../value.dart';
class SassString extends Value {
/// The contents of the string.
///
/// This is the semantic contentany escape sequences are resolved to their
/// Unicode values.
/// For quoted strings, this is the semantic contentany escape sequences that
/// were been written in the source text are resolved to their Unicode values.
/// For unquoted strings, though, escape sequences are preserved as literal
/// backslashes.
///
/// This difference allows us to distinguish between identifiers with escapes,
/// such as `url\u28 http://example.com\u29`, and unquoted strings that
/// contain characters that aren't valid in identifiers, such as
/// `url(http://example.com)`. Unfortunately, it also means that we don't
/// consider `foo` and `f\6F\6F` the same string.
final String text;
/// Whether this string has quotes.

View File

@ -594,11 +594,6 @@ class _SerializeCssVisitor
for (var i = 0; i < string.length; i++) {
var char = string.codeUnitAt(i);
switch (char) {
case $backslash:
_buffer.writeCharCode($backslash);
_buffer.writeCharCode($backslash);
break;
case $lf:
_buffer.writeCharCode($space);
break;