This commit is contained in:
ConnorSkees 2020-05-25 16:23:20 -04:00
commit 217ef033c4
9 changed files with 55 additions and 47 deletions

View File

@ -54,6 +54,7 @@ rand = { version = "0.7.3", optional = true }
codemap = "0.1.3" codemap = "0.1.3"
peekmore = "0.4.0" peekmore = "0.4.0"
wasm-bindgen = { version = "0.2.60", optional = true } wasm-bindgen = { version = "0.2.60", optional = true }
beef = "0.4.4"
# criterion is not a dev-dependency because it makes tests take too # criterion is not a dev-dependency because it makes tests take too
# long to compile, and you cannot make dev-dependencies optional # long to compile, and you cannot make dev-dependencies optional
criterion = { version = "0.3.2", optional = true } criterion = { version = "0.3.2", optional = true }

View File

@ -5,6 +5,7 @@ use codemap::{Span, Spanned};
use peekmore::PeekMoreIterator; use peekmore::PeekMoreIterator;
use crate::Cow;
use crate::common::Identifier; use crate::common::Identifier;
use crate::error::SassResult; use crate::error::SassResult;
use crate::scope::Scope; use crate::scope::Scope;
@ -90,9 +91,9 @@ impl CallArgs {
.iter() .iter()
.map(|a| { .map(|a| {
span = span.merge(a.span); span = span.merge(a.span);
Ok(a.node.to_css_string(a.span)?.into()) Ok(a.node.to_css_string(a.span)?)
}) })
.collect::<SassResult<Vec<String>>>()? .collect::<SassResult<Vec<Cow<'static, str>>>>()?
.join(", "), .join(", "),
); );
string.push(')'); string.push(')');

View File

@ -10,7 +10,7 @@ use crate::utils::{
read_until_semicolon_or_closing_curly_brace, read_until_semicolon_or_closing_curly_brace,
}; };
use crate::value::Value; use crate::value::Value;
use crate::{RuleSet, Stmt, Token}; use crate::{Cow, RuleSet, Stmt, Token};
use each_rule::{parse_each, Each}; use each_rule::{parse_each, Each};
use for_rule::For; use for_rule::For;
@ -36,8 +36,8 @@ mod while_rule;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum AtRule { pub(crate) enum AtRule {
Warn(Spanned<String>), Warn(Spanned<Cow<'static, str>>),
Debug(Spanned<String>), Debug(Spanned<Cow<'static, str>>),
Mixin(String, Box<Mixin>), Mixin(String, Box<Mixin>),
Function(String, Box<Function>), Function(String, Box<Function>),
Return(Vec<Token>), Return(Vec<Token>),
@ -94,7 +94,7 @@ impl AtRule {
devour_whitespace(toks); devour_whitespace(toks);
Spanned { Spanned {
node: AtRule::Warn(Spanned { node: AtRule::Warn(Spanned {
node: message.to_css_string(span)?.into(), node: message.to_css_string(span)?,
span, span,
}), }),
span, span,
@ -117,7 +117,7 @@ impl AtRule {
devour_whitespace(toks); devour_whitespace(toks);
Spanned { Spanned {
node: AtRule::Debug(Spanned { node: AtRule::Debug(Spanned {
node: message.inspect(span)?.into(), node: message.inspect(span)?,
span, span,
}), }),
span, span,

View File

@ -98,7 +98,7 @@ fn inspect(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sass
Ok(Value::String( Ok(Value::String(
arg!(args, scope, super_selector, 0, "value") arg!(args, scope, super_selector, 0, "value")
.inspect(args.span())? .inspect(args.span())?
.into(), .into_owned(),
QuoteKind::None, QuoteKind::None,
)) ))
} }

View File

@ -84,6 +84,11 @@ grass input.scss
use std::convert::TryFrom; use std::convert::TryFrom;
use std::iter::Iterator; use std::iter::Iterator;
#[cfg(target_pointer_width = "64")]
pub(crate) use beef::lean::Cow;
#[cfg(not(target_pointer_width = "64"))]
pub(crate) use beef::Cow;
use codemap::{Span, Spanned}; use codemap::{Span, Spanned};
use peekmore::{PeekMore, PeekMoreIterator}; use peekmore::{PeekMore, PeekMoreIterator};

View File

@ -1,4 +1,5 @@
use std::iter::Iterator; use std::iter::Iterator;
use std::borrow::Borrow;
use codemap::{Span, Spanned}; use codemap::{Span, Spanned};
@ -216,12 +217,10 @@ pub(crate) fn eat_ident<I: Iterator<Item = Token>>(
}; };
if kind == '{' { if kind == '{' {
toks.next(); toks.next();
text.push_str( match parse_interpolation(toks, scope, super_selector, pos)?.node {
&match parse_interpolation(toks, scope, super_selector, pos)?.node { Value::String(ref s, ..) => text.push_str(s),
Value::String(s, ..) => s, v => text.push_str(v.to_css_string(span)?.borrow()),
v => v.to_css_string(span)?.into(), }
},
);
} else { } else {
return Err(("Expected identifier.", pos).into()); return Err(("Expected identifier.", pos).into());
} }
@ -300,10 +299,10 @@ pub(crate) fn parse_quoted_string<I: Iterator<Item = Token>>(
if let Some(Token { kind: '{', pos }) = toks.peek().cloned() { if let Some(Token { kind: '{', pos }) = toks.peek().cloned() {
toks.next(); toks.next();
let interpolation = parse_interpolation(toks, scope, super_selector, pos)?; let interpolation = parse_interpolation(toks, scope, super_selector, pos)?;
s.push_str(&match interpolation.node { match interpolation.node {
Value::String(s, ..) => s, Value::String(ref v, ..) => s.push_str(v),
v => v.to_css_string(interpolation.span)?.into(), v => s.push_str(v.to_css_string(interpolation.span)?.borrow()),
}); };
continue; continue;
} else { } else {
s.push('#'); s.push('#');

View File

@ -1,3 +1,5 @@
use std::borrow::Borrow;
use codemap::{Span, Spanned}; use codemap::{Span, Spanned};
use peekmore::PeekMoreIterator; use peekmore::PeekMoreIterator;
@ -115,10 +117,10 @@ pub(crate) fn try_eat_url<I: Iterator<Item = Token>>(
peek_counter += 1; peek_counter += 1;
let (interpolation, count) = peek_interpolation(toks, scope, super_selector, pos)?; let (interpolation, count) = peek_interpolation(toks, scope, super_selector, pos)?;
peek_counter += count; peek_counter += count;
buf.push_str(&match interpolation.node { match interpolation.node {
Value::String(s, ..) => s, Value::String(ref s, ..) => buf.push_str(s),
v => v.to_css_string(interpolation.span)?.into(), v => buf.push_str(v.to_css_string(interpolation.span)?.borrow()),
}); };
} else { } else {
buf.push('#'); buf.push('#');
} }

View File

@ -1,4 +1,3 @@
use std::borrow::Cow;
use std::iter::Iterator; use std::iter::Iterator;
use codemap::{Span, Spanned}; use codemap::{Span, Spanned};
@ -8,6 +7,7 @@ use crate::common::{Brackets, ListSeparator, Op, QuoteKind};
use crate::error::SassResult; use crate::error::SassResult;
use crate::unit::Unit; use crate::unit::Unit;
use crate::utils::hex_char_for; use crate::utils::hex_char_for;
use crate::Cow;
use css_function::is_special_function; use css_function::is_special_function;
pub(crate) use map::SassMap; pub(crate) use map::SassMap;
@ -128,12 +128,12 @@ impl Value {
pub fn to_css_string(&self, span: Span) -> SassResult<Cow<'static, str>> { pub fn to_css_string(&self, span: Span) -> SassResult<Cow<'static, str>> {
Ok(match self { Ok(match self {
Self::Important => Cow::Borrowed("!important"), Self::Important => Cow::const_str("!important"),
Self::Dimension(num, unit) => match unit { Self::Dimension(num, unit) => match unit {
Unit::Mul(..) => { Unit::Mul(..) => {
return Err((format!("{}{} isn't a valid CSS value.", num, unit), span).into()); return Err((format!("{}{} isn't a valid CSS value.", num, unit), span).into());
} }
_ => Cow::Owned(format!("{}{}", num, unit)), _ => Cow::owned(format!("{}{}", num, unit)),
}, },
Self::Map(..) | Self::Function(..) => { Self::Map(..) | Self::Function(..) => {
return Err(( return Err((
@ -143,14 +143,14 @@ impl Value {
.into()) .into())
} }
Self::List(vals, sep, brackets) => match brackets { Self::List(vals, sep, brackets) => match brackets {
Brackets::None => Cow::Owned( Brackets::None => Cow::owned(
vals.iter() vals.iter()
.filter(|x| !x.is_null(span).unwrap()) .filter(|x| !x.is_null(span).unwrap())
.map(|x| x.to_css_string(span)) .map(|x| x.to_css_string(span))
.collect::<SassResult<Vec<Cow<'static, str>>>>()? .collect::<SassResult<Vec<Cow<'static, str>>>>()?
.join(sep.as_str()), .join(sep.as_str()),
), ),
Brackets::Bracketed => Cow::Owned(format!( Brackets::Bracketed => Cow::owned(format!(
"[{}]", "[{}]",
vals.iter() vals.iter()
.filter(|x| !x.is_null(span).unwrap()) .filter(|x| !x.is_null(span).unwrap())
@ -159,7 +159,7 @@ impl Value {
.join(sep.as_str()), .join(sep.as_str()),
)), )),
}, },
Self::Color(c) => Cow::Owned(c.to_string()), Self::Color(c) => Cow::owned(c.to_string()),
Self::UnaryOp(..) | Self::BinaryOp(..) => { Self::UnaryOp(..) | Self::BinaryOp(..) => {
self.clone().eval(span)?.to_css_string(span)? self.clone().eval(span)?.to_css_string(span)?
} }
@ -184,21 +184,21 @@ impl Value {
} }
} }
} }
Cow::Owned(buf) Cow::owned(buf)
} }
Self::String(string, QuoteKind::Quoted) => { Self::String(string, QuoteKind::Quoted) => {
let mut buf = String::with_capacity(string.len()); let mut buf = String::with_capacity(string.len());
visit_quoted_string(&mut buf, false, string)?; visit_quoted_string(&mut buf, false, string)?;
Cow::Owned(buf) Cow::owned(buf)
} }
Self::True => Cow::Borrowed("true"), Self::True => Cow::const_str("true"),
Self::False => Cow::Borrowed("false"), Self::False => Cow::const_str("false"),
Self::Null => Cow::Borrowed(""), Self::Null => Cow::const_str(""),
Self::ArgList(args) => Cow::Owned( Self::ArgList(args) => Cow::owned(
args.iter() args.iter()
.filter(|x| !x.is_null(span).unwrap()) .filter(|x| !x.is_null(span).unwrap())
.map(|a| Ok(a.node.to_css_string(span)?.into())) .map(|a| Ok(a.node.to_css_string(span)?))
.collect::<SassResult<Vec<String>>>()? .collect::<SassResult<Vec<Cow<'static, str>>>>()?
.join(", "), .join(", "),
), ),
}) })
@ -265,20 +265,20 @@ impl Value {
pub fn inspect(&self, span: Span) -> SassResult<Cow<'static, str>> { pub fn inspect(&self, span: Span) -> SassResult<Cow<'static, str>> {
Ok(match self { Ok(match self {
Value::List(v, _, brackets) if v.is_empty() => match brackets { Value::List(v, _, brackets) if v.is_empty() => match brackets {
Brackets::None => Cow::Borrowed("()"), Brackets::None => Cow::const_str("()"),
Brackets::Bracketed => Cow::Borrowed("[]"), Brackets::Bracketed => Cow::const_str("[]"),
}, },
Value::List(v, sep, brackets) if v.len() == 1 => match brackets { Value::List(v, sep, brackets) if v.len() == 1 => match brackets {
Brackets::None => match sep { Brackets::None => match sep {
ListSeparator::Space => v[0].inspect(span)?, ListSeparator::Space => v[0].inspect(span)?,
ListSeparator::Comma => Cow::Owned(format!("({},)", v[0].inspect(span)?)), ListSeparator::Comma => Cow::owned(format!("({},)", v[0].inspect(span)?)),
}, },
Brackets::Bracketed => match sep { Brackets::Bracketed => match sep {
ListSeparator::Space => Cow::Owned(format!("[{}]", v[0].inspect(span)?)), ListSeparator::Space => Cow::owned(format!("[{}]", v[0].inspect(span)?)),
ListSeparator::Comma => Cow::Owned(format!("[{},]", v[0].inspect(span)?)), ListSeparator::Comma => Cow::owned(format!("[{},]", v[0].inspect(span)?)),
}, },
}, },
Self::List(vals, sep, brackets) => Cow::Owned(match brackets { Self::List(vals, sep, brackets) => Cow::owned(match brackets {
Brackets::None => vals Brackets::None => vals
.iter() .iter()
.map(|x| x.inspect(span)) .map(|x| x.inspect(span))
@ -292,9 +292,9 @@ impl Value {
.join(sep.as_str()), .join(sep.as_str()),
), ),
}), }),
Value::Function(f) => Cow::Owned(format!("get-function(\"{}\")", f.name())), Value::Function(f) => Cow::owned(format!("get-function(\"{}\")", f.name())),
Value::Null => Cow::Borrowed("null"), Value::Null => Cow::const_str("null"),
Value::Map(map) => Cow::Owned(format!( Value::Map(map) => Cow::owned(format!(
"({})", "({})",
map.iter() map.iter()
.map(|(k, v)| Ok(format!( .map(|(k, v)| Ok(format!(

View File

@ -268,7 +268,7 @@ impl Value {
format!("{}{}", self.to_css_string(span)?, s), format!("{}{}", self.to_css_string(span)?, s),
QuoteKind::Quoted, QuoteKind::Quoted,
), ),
Self::Null => Value::String(self.to_css_string(span)?.into(), QuoteKind::None), Self::Null => Value::String(self.to_css_string(span)?.into_owned(), QuoteKind::None),
_ => Value::String( _ => Value::String(
format!( format!(
"{}{}", "{}{}",
@ -280,7 +280,7 @@ impl Value {
}, },
Self::Null => match other { Self::Null => match other {
Self::Null => Self::Null, Self::Null => Self::Null,
_ => Value::String(other.to_css_string(span)?.into(), QuoteKind::None), _ => Value::String(other.to_css_string(span)?.into_owned(), QuoteKind::None),
}, },
Self::Dimension(num, unit) => match other { Self::Dimension(num, unit) => match other {
Self::Dimension(num2, unit2) => { Self::Dimension(num2, unit2) => {