Strings containing interpolation are double quoted

This commit is contained in:
ConnorSkees 2020-02-24 15:18:53 -05:00
parent 011577c9f6
commit 54e71130e7
3 changed files with 16 additions and 49 deletions

View File

@ -375,7 +375,7 @@ impl Attribute {
} }
q @ TokenKind::Symbol(Symbol::DoubleQuote) q @ TokenKind::Symbol(Symbol::DoubleQuote)
| q @ TokenKind::Symbol(Symbol::SingleQuote) => { | q @ TokenKind::Symbol(Symbol::SingleQuote) => {
parse_quoted_string(toks, scope, q)? parse_quoted_string(toks, scope, q)?.to_string()
} }
_ => return Err("Expected identifier.".into()), _ => return Err("Expected identifier.".into()),
} }
@ -437,7 +437,7 @@ impl Attribute {
} }
q @ TokenKind::Symbol(Symbol::DoubleQuote) q @ TokenKind::Symbol(Symbol::DoubleQuote)
| q @ TokenKind::Symbol(Symbol::SingleQuote) => { | q @ TokenKind::Symbol(Symbol::SingleQuote) => {
parse_quoted_string(toks, scope, q)? parse_quoted_string(toks, scope, q)?.to_string()
} }
_ => return Err("Expected identifier.".into()), _ => return Err("Expected identifier.".into()),
} }

View File

@ -152,9 +152,10 @@ pub(crate) fn parse_quoted_string<I: Iterator<Item = Token>>(
toks: &mut Peekable<I>, toks: &mut Peekable<I>,
scope: &Scope, scope: &Scope,
q: TokenKind, q: TokenKind,
) -> SassResult<String> { ) -> SassResult<Value> {
let mut s = String::new(); let mut s = String::new();
let mut is_escaped = false; let mut is_escaped = false;
let mut found_interpolation = false;
while let Some(tok) = toks.next() { while let Some(tok) = toks.next() {
match tok.kind { match tok.kind {
TokenKind::Symbol(Symbol::DoubleQuote) TokenKind::Symbol(Symbol::DoubleQuote)
@ -170,6 +171,7 @@ pub(crate) fn parse_quoted_string<I: Iterator<Item = Token>>(
TokenKind::Symbol(Symbol::BackSlash) if !is_escaped => is_escaped = true, TokenKind::Symbol(Symbol::BackSlash) if !is_escaped => is_escaped = true,
TokenKind::Symbol(Symbol::BackSlash) => s.push('\\'), TokenKind::Symbol(Symbol::BackSlash) => s.push('\\'),
TokenKind::Interpolation => { TokenKind::Interpolation => {
found_interpolation = true;
s.push_str( s.push_str(
&parse_interpolation(toks, scope)? &parse_interpolation(toks, scope)?
.iter() .iter()
@ -185,10 +187,14 @@ pub(crate) fn parse_quoted_string<I: Iterator<Item = Token>>(
} }
s.push_str(&tok.kind.to_string()); s.push_str(&tok.kind.to_string());
} }
let quotes = match q { let quotes = if found_interpolation {
QuoteKind::Double
} else {
match q {
TokenKind::Symbol(Symbol::DoubleQuote) => QuoteKind::Double, TokenKind::Symbol(Symbol::DoubleQuote) => QuoteKind::Double,
TokenKind::Symbol(Symbol::SingleQuote) => QuoteKind::Single, TokenKind::Symbol(Symbol::SingleQuote) => QuoteKind::Single,
_ => unreachable!(), _ => unreachable!(),
}; }
Ok(format!("{}{}{}", quotes, s, quotes)) };
Ok(Value::Ident(s, quotes))
} }

View File

@ -11,7 +11,7 @@ use crate::color::Color;
use crate::common::{Keyword, ListSeparator, Op, QuoteKind, Scope, Symbol}; use crate::common::{Keyword, ListSeparator, Op, QuoteKind, Scope, Symbol};
use crate::error::SassResult; use crate::error::SassResult;
use crate::units::Unit; use crate::units::Unit;
use crate::utils::{devour_whitespace_or_comment, parse_interpolation}; use crate::utils::{devour_whitespace_or_comment, parse_interpolation, parse_quoted_string};
use crate::value::Value; use crate::value::Value;
use crate::{Token, TokenKind}; use crate::{Token, TokenKind};
@ -287,46 +287,7 @@ impl Value {
} }
} }
q @ TokenKind::Symbol(Symbol::DoubleQuote) q @ TokenKind::Symbol(Symbol::DoubleQuote)
| q @ TokenKind::Symbol(Symbol::SingleQuote) => { | q @ TokenKind::Symbol(Symbol::SingleQuote) => parse_quoted_string(toks, scope, q),
let mut s = String::new();
let mut is_escaped = false;
while let Some(tok) = toks.next() {
match tok.kind {
TokenKind::Symbol(Symbol::DoubleQuote)
if !is_escaped && q == TokenKind::Symbol(Symbol::DoubleQuote) =>
{
break
}
TokenKind::Symbol(Symbol::SingleQuote)
if !is_escaped && q == TokenKind::Symbol(Symbol::SingleQuote) =>
{
break
}
TokenKind::Symbol(Symbol::BackSlash) if !is_escaped => is_escaped = true,
TokenKind::Symbol(Symbol::BackSlash) => s.push('\\'),
TokenKind::Interpolation => {
s.push_str(
&parse_interpolation(toks, scope)?
.iter()
.map(|x| x.kind.to_string())
.collect::<String>(),
);
continue;
}
_ => {}
}
if is_escaped && tok.kind != TokenKind::Symbol(Symbol::BackSlash) {
is_escaped = false;
}
s.push_str(&tok.kind.to_string());
}
let quotes = match q {
TokenKind::Symbol(Symbol::DoubleQuote) => QuoteKind::Double,
TokenKind::Symbol(Symbol::SingleQuote) => QuoteKind::Single,
_ => unreachable!(),
};
Ok(Value::Ident(s, quotes))
}
TokenKind::Variable(ref v) => Ok(scope.get_var(v)?.clone()), TokenKind::Variable(ref v) => Ok(scope.get_var(v)?.clone()),
TokenKind::Interpolation => { TokenKind::Interpolation => {
let mut s = parse_interpolation(toks, scope)? let mut s = parse_interpolation(toks, scope)?