Add StringExpression.asInterpolation.

This commit is contained in:
Natalie Weizenbaum 2016-08-14 19:52:38 -07:00
parent 8fa603feda
commit 4f4188fd12
3 changed files with 62 additions and 10 deletions

View File

@ -2,8 +2,11 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'package:charcode/charcode.dart';
import 'package:source_span/source_span.dart';
import '../../../interpolation_buffer.dart';
import '../../../util/character.dart';
import '../../../visitor/sass/expression.dart';
import '../expression.dart';
import 'interpolation.dart';
@ -18,13 +21,57 @@ class StringExpression implements Expression {
FileSpan get span => text.span;
/// Interpolation that, when evaluated, produces the syntax of the string.
///
/// Unlike [text], his doesn't resolve escapes and does include quotes.
InterpolationExpression get asInterpolation => throw new UnimplementedError();
StringExpression(this.text);
/*=T*/ accept/*<T>*/(ExpressionVisitor/*<T>*/ visitor) =>
visitor.visitStringExpression(this);
StringExpression(this.text);
}
/// Interpolation that, when evaluated, produces the syntax of the string.
///
/// Unlike [text], his doesn't resolve escapes and does include quotes.
InterpolationExpression asInterpolation({bool static: false, int quote}) {
quote ??= _bestQuote();
var buffer = new InterpolationBuffer()..writeCharCode(quote);
for (var value in text.contents) {
if (value is InterpolationExpression) {
buffer.addInterpolation(value);
} else if (value is String) {
for (var i = 0; i < value.length; i++) {
var codeUnit = value.codeUnitAt(i);
if (isNewline(codeUnit)) {
buffer.writeCharCode($backslash);
buffer.writeCharCode($a);
var next = i == value.length - 1 ? null : value.codeUnitAt(i + 1);
if (isWhitespace(next) || isHex(next)) buffer.writeCharCode($space);
} else {
if (codeUnit == quote ||
codeUnit == $backslash ||
(static &&
codeUnit == $hash &&
i < value.length - 1 &&
value.codeUnitAt(i + 1) == $lbrace)) {
buffer.writeCharCode($backslash);
}
buffer.writeCharCode(codeUnit);
}
}
}
}
buffer.writeCharCode(quote);
return buffer.interpolation(text.span);
}
int _bestQuote() {
var containsDoubleQuote = false;
for (var value in text.contents) {
for (var i = 0; i < value.length; i++) {
var codeUnit = value.codeUnitAt(i);
if (codeUnit == $single_quote) return $double_quote;
if (codeUnit == $double_quote) containsDoubleQuote = true;
}
}
return containsDoubleQuote ? $single_quote : $double_quote;
}
}

View File

@ -640,7 +640,7 @@ class Parser {
case $double_quote:
case $single_quote:
buffer.addInterpolation(_string().asInterpolation);
buffer.addInterpolation(_string().asInterpolation());
break;
case $slash:
@ -701,7 +701,9 @@ class Parser {
case $double_quote:
case $single_quote:
buffer.addInterpolation(_string(static: static).asInterpolation);
buffer.addInterpolation(
_string(static: static)
.asInterpolation(static: static, quote: next));
wroteNewline = false;
break;
@ -807,7 +809,7 @@ class Parser {
if (next == null) {
break;
} else if (next == $underscore || next == $dash ||
isAlphabetic(next) || isDigit(next) || next >= 0x0080) {
isAlphanumeric(next) || next >= 0x0080) {
buffer.writeCharCode(_scanner.readChar());
} else if (next == $backslash) {
buffer.writeCharCode(_escape());
@ -1279,7 +1281,7 @@ class Parser {
if (next == null) {
break;
} else if (next == $underscore || next == $dash ||
isAlphabetic(next) || isDigit(next) || next >= 0x0080) {
isAlphanumeric(next) || next >= 0x0080) {
text.writeCharCode(_scanner.readChar());
} else if (next == $backslash) {
text.writeCharCode(_escape());

View File

@ -10,6 +10,9 @@ bool isWhitespace(int character) =>
bool isNewline(int character) =>
character == $lf || character == $cr || character == $ff;
bool isAlphanumeric(int character) =>
isAlphabetic(character) || isDigit(character);
bool isAlphabetic(int character) =>
(character >= $a && character <= $z) ||
(character >= $A && character <= $Z);