Revert string interning

There existed issues related to multithreaded tests that are difficult
to resolve. In the future interning may be reimplemented but in a more
limited capacity.

The motivation behind interning *values* was that it appeared checking
for named colors was responsible for much of the time lost when parsing
unquoted strings. If interning were to be reimplemented, it may make
sense to limit it solely to identifiers and style properties.
This commit is contained in:
ConnorSkees 2020-05-22 14:20:31 -04:00
parent 3e5abf0587
commit 969726eb30
24 changed files with 431 additions and 1158 deletions

View File

@ -49,7 +49,6 @@ 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 }
lasso = "0.2.2"
[features] [features]
default = ["commandline", "random"] default = ["commandline", "random"]

View File

@ -42,7 +42,7 @@ impl Each {
if self.vars.len() == 1 { if self.vars.len() == 1 {
if this_iterator.len() == 1 { if this_iterator.len() == 1 {
scope.insert_var( scope.insert_var(
&self.vars[0].node, &self.vars[0],
Spanned { Spanned {
node: this_iterator[0].clone(), node: this_iterator[0].clone(),
span: self.vars[0].span, span: self.vars[0].span,
@ -50,7 +50,7 @@ impl Each {
)?; )?;
} else { } else {
scope.insert_var( scope.insert_var(
&self.vars[0].node, &self.vars[0],
Spanned { Spanned {
node: Value::List(this_iterator, ListSeparator::Space, Brackets::None), node: Value::List(this_iterator, ListSeparator::Space, Brackets::None),
span: self.vars[0].span, span: self.vars[0].span,

View File

@ -6,7 +6,6 @@ use crate::args::CallArgs;
use crate::color::Color; use crate::color::Color;
use crate::common::QuoteKind; use crate::common::QuoteKind;
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
use crate::unit::Unit; use crate::unit::Unit;
@ -108,10 +107,7 @@ fn inner_hsl(
); );
} }
string.push(')'); string.push(')');
return Ok(Value::Ident( return Ok(Value::Ident(string, QuoteKind::None));
InternedString::get_or_intern(string),
QuoteKind::None,
));
} }
v => { v => {
return Err(( return Err((
@ -140,10 +136,7 @@ fn inner_hsl(
); );
} }
string.push(')'); string.push(')');
return Ok(Value::Ident( return Ok(Value::Ident(string, QuoteKind::None));
InternedString::get_or_intern(string),
QuoteKind::None,
));
} }
v => { v => {
return Err(( return Err((
@ -174,10 +167,7 @@ fn inner_hsl(
); );
} }
string.push(')'); string.push(')');
return Ok(Value::Ident( return Ok(Value::Ident(string, QuoteKind::None));
InternedString::get_or_intern(string),
QuoteKind::None,
));
} }
v => { v => {
return Err(( return Err((
@ -211,14 +201,14 @@ fn inner_hsl(
} }
v if v.is_special_function() => { v if v.is_special_function() => {
return Ok(Value::Ident( return Ok(Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}({}, {}, {}, {})", "{}({}, {}, {}, {})",
name, name,
hue, hue,
saturation, saturation,
lightness, lightness,
v.to_css_string(args.span())? v.to_css_string(args.span())?
)), ),
QuoteKind::None, QuoteKind::None,
)); ));
} }
@ -368,10 +358,10 @@ fn saturate(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sas
args.max_args(2)?; args.max_args(2)?;
if args.len() == 1 { if args.len() == 1 {
return Ok(Value::Ident( return Ok(Value::Ident(
InternedString::get_or_intern(format!( format!(
"saturate({})", "saturate({})",
arg!(args, scope, super_selector, 0, "amount").to_css_string(args.span())? arg!(args, scope, super_selector, 0, "amount").to_css_string(args.span())?
)), ),
QuoteKind::None, QuoteKind::None,
)); ));
} }
@ -393,7 +383,7 @@ fn saturate(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sas
Value::Color(c) => c, Value::Color(c) => c,
Value::Dimension(n, u) => { Value::Dimension(n, u) => {
return Ok(Value::Ident( return Ok(Value::Ident(
InternedString::get_or_intern(format!("saturate({}{})", n, u)), format!("saturate({}{})", n, u),
QuoteKind::None, QuoteKind::None,
)) ))
} }
@ -442,7 +432,7 @@ fn grayscale(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sa
Value::Color(c) => c, Value::Color(c) => c,
Value::Dimension(n, u) => { Value::Dimension(n, u) => {
return Ok(Value::Ident( return Ok(Value::Ident(
InternedString::get_or_intern(format!("grayscale({}{})", n, u)), format!("grayscale({}{})", n, u),
QuoteKind::None, QuoteKind::None,
)) ))
} }
@ -495,10 +485,9 @@ fn invert(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassR
}; };
match arg!(args, scope, super_selector, 0, "color") { match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => Ok(Value::Color(Box::new(c.invert(weight)))), Value::Color(c) => Ok(Value::Color(Box::new(c.invert(weight)))),
Value::Dimension(n, Unit::Percent) => Ok(Value::Ident( Value::Dimension(n, Unit::Percent) => {
InternedString::get_or_intern(format!("invert({}%)", n)), Ok(Value::Ident(format!("invert({}%)", n), QuoteKind::None))
QuoteKind::None, }
)),
Value::Dimension(..) => Err(( Value::Dimension(..) => Err((
"Only one argument may be passed to the plain-CSS invert() function.", "Only one argument may be passed to the plain-CSS invert() function.",
args.span(), args.span(),

View File

@ -3,7 +3,6 @@ use super::{Builtin, GlobalFunctionMap};
use crate::args::CallArgs; use crate::args::CallArgs;
use crate::common::QuoteKind; use crate::common::QuoteKind;
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
use crate::unit::Unit; use crate::unit::Unit;
@ -27,7 +26,7 @@ fn opacity(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sass
match arg!(args, scope, super_selector, 0, "color") { match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None)), Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None)),
Value::Dimension(num, unit) => Ok(Value::Ident( Value::Dimension(num, unit) => Ok(Value::Ident(
InternedString::get_or_intern(format!("opacity({}{})", num, unit)), format!("opacity({}{})", num, unit),
QuoteKind::None, QuoteKind::None,
)), )),
v => Err(( v => Err((

View File

@ -6,7 +6,6 @@ use crate::args::CallArgs;
use crate::color::Color; use crate::color::Color;
use crate::common::QuoteKind; use crate::common::QuoteKind;
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
use crate::unit::Unit; use crate::unit::Unit;
@ -47,13 +46,13 @@ fn inner_rgb(
let green = channels.pop().unwrap(); let green = channels.pop().unwrap();
let red = channels.pop().unwrap(); let red = channels.pop().unwrap();
return Ok(Value::Ident( return Ok(Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}({}, {}, {})", "{}({}, {}, {})",
name, name,
red.to_css_string(args.span())?, red.to_css_string(args.span())?,
green.to_css_string(args.span())?, green.to_css_string(args.span())?,
v.to_css_string(args.span())? v.to_css_string(args.span())?
)), ),
QuoteKind::None, QuoteKind::None,
)); ));
} }
@ -81,10 +80,7 @@ fn inner_rgb(
), ),
None => format!("{}({} {})", name, v.to_css_string(args.span())?, blue), None => format!("{}({} {})", name, v.to_css_string(args.span())?, blue),
}; };
return Ok(Value::Ident( return Ok(Value::Ident(string, QuoteKind::None));
InternedString::get_or_intern(string),
QuoteKind::None,
));
} }
Some(v) => { Some(v) => {
return Err(( return Err((
@ -101,13 +97,13 @@ fn inner_rgb(
Some(Value::Dimension(n, Unit::Percent)) => (n / Number::from(100)) * Number::from(255), Some(Value::Dimension(n, Unit::Percent)) => (n / Number::from(100)) * Number::from(255),
Some(v) if v.is_special_function() => { Some(v) if v.is_special_function() => {
return Ok(Value::Ident( return Ok(Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}({}, {}, {})", "{}({}, {}, {})",
name, name,
v.to_css_string(args.span())?, v.to_css_string(args.span())?,
green, green,
blue blue
)), ),
QuoteKind::None, QuoteKind::None,
)); ));
} }
@ -130,12 +126,12 @@ fn inner_rgb(
v if v.is_special_function() => { v if v.is_special_function() => {
let alpha = arg!(args, scope, super_selector, 1, "alpha"); let alpha = arg!(args, scope, super_selector, 1, "alpha");
return Ok(Value::Ident( return Ok(Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}({}, {})", "{}({}, {})",
name, name,
v.to_css_string(args.span())?, v.to_css_string(args.span())?,
alpha.to_css_string(args.span())? alpha.to_css_string(args.span())?
)), ),
QuoteKind::None, QuoteKind::None,
)); ));
} }
@ -162,14 +158,14 @@ fn inner_rgb(
} }
v if v.is_special_function() => { v if v.is_special_function() => {
return Ok(Value::Ident( return Ok(Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}({}, {}, {}, {})", "{}({}, {}, {}, {})",
name, name,
color.red(), color.red(),
color.green(), color.green(),
color.blue(), color.blue(),
v.to_css_string(args.span())? v.to_css_string(args.span())?
)), ),
QuoteKind::None, QuoteKind::None,
)); ));
} }
@ -214,10 +210,7 @@ fn inner_rgb(
); );
} }
string.push(')'); string.push(')');
return Ok(Value::Ident( return Ok(Value::Ident(string, QuoteKind::None));
InternedString::get_or_intern(string),
QuoteKind::None,
));
} }
v => { v => {
return Err(( return Err((
@ -257,10 +250,7 @@ fn inner_rgb(
); );
} }
string.push(')'); string.push(')');
return Ok(Value::Ident( return Ok(Value::Ident(string, QuoteKind::None));
InternedString::get_or_intern(string),
QuoteKind::None,
));
} }
v => { v => {
return Err(( return Err((
@ -299,10 +289,7 @@ fn inner_rgb(
); );
} }
string.push(')'); string.push(')');
return Ok(Value::Ident( return Ok(Value::Ident(string, QuoteKind::None));
InternedString::get_or_intern(string),
QuoteKind::None,
));
} }
v => { v => {
return Err(( return Err((
@ -340,10 +327,7 @@ fn inner_rgb(
blue, blue,
v.to_css_string(args.span())? v.to_css_string(args.span())?
); );
return Ok(Value::Ident( return Ok(Value::Ident(string, QuoteKind::None));
InternedString::get_or_intern(string),
QuoteKind::None,
));
} }
v => { v => {
return Err(( return Err((

View File

@ -5,7 +5,6 @@ use num_traits::{One, Signed, ToPrimitive, Zero};
use crate::args::CallArgs; use crate::args::CallArgs;
use crate::common::{Brackets, ListSeparator, QuoteKind}; use crate::common::{Brackets, ListSeparator, QuoteKind};
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
use crate::unit::Unit; use crate::unit::Unit;
@ -73,10 +72,11 @@ fn list_separator(
) -> SassResult<Value> { ) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
Ok(Value::Ident( Ok(Value::Ident(
InternedString::get_or_intern(match arg!(args, scope, super_selector, 0, "list") { match arg!(args, scope, super_selector, 0, "list") {
Value::List(_, sep, ..) => sep.name(), Value::List(_, sep, ..) => sep.name(),
_ => ListSeparator::Space.name(), _ => ListSeparator::Space.name(),
}), }
.to_owned(),
QuoteKind::None, QuoteKind::None,
)) ))
} }
@ -140,9 +140,9 @@ fn append(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassR
scope, scope,
super_selector, super_selector,
2, 2,
"separator" = Value::Ident(InternedString::get_or_intern("auto"), QuoteKind::None) "separator" = Value::Ident("auto".to_owned(), QuoteKind::None)
) { ) {
Value::Ident(s, ..) => match s.resolve_ref() { Value::Ident(s, ..) => match s.as_str() {
"auto" => sep, "auto" => sep,
"comma" => ListSeparator::Comma, "comma" => ListSeparator::Comma,
"space" => ListSeparator::Space, "space" => ListSeparator::Space,
@ -188,9 +188,9 @@ fn join(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassRes
scope, scope,
super_selector, super_selector,
2, 2,
"separator" = Value::Ident(InternedString::get_or_intern("auto"), QuoteKind::None) "separator" = Value::Ident("auto".to_owned(), QuoteKind::None)
) { ) {
Value::Ident(s, ..) => match s.resolve_ref() { Value::Ident(s, ..) => match s.as_str() {
"auto" => { "auto" => {
if list1.is_empty() || (list1.len() == 1 && sep1 == ListSeparator::Space) { if list1.is_empty() || (list1.len() == 1 && sep1 == ListSeparator::Space) {
sep2 sep2
@ -225,9 +225,9 @@ fn join(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassRes
scope, scope,
super_selector, super_selector,
3, 3,
"bracketed" = Value::Ident(InternedString::get_or_intern("auto"), QuoteKind::None) "bracketed" = Value::Ident("auto".to_owned(), QuoteKind::None)
) { ) {
Value::Ident(s, ..) => match s.resolve_ref() { Value::Ident(s, ..) => match s.as_str() {
"auto" => brackets, "auto" => brackets,
_ => Brackets::Bracketed, _ => Brackets::Bracketed,
}, },

View File

@ -5,7 +5,6 @@ use codemap::Spanned;
use crate::args::CallArgs; use crate::args::CallArgs;
use crate::common::QuoteKind; use crate::common::QuoteKind;
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::global_var_exists; use crate::scope::global_var_exists;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
@ -28,7 +27,7 @@ fn feature_exists(
) -> SassResult<Value> { ) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match arg!(args, scope, super_selector, 0, "feature") { match arg!(args, scope, super_selector, 0, "feature") {
Value::Ident(s, _) => Ok(match s.resolve_ref() { Value::Ident(s, _) => Ok(match s.as_str() {
// A local variable will shadow a global variable unless // A local variable will shadow a global variable unless
// `!global` is used. // `!global` is used.
"global-variable-shadowing" => Value::True, "global-variable-shadowing" => Value::True,
@ -72,17 +71,14 @@ fn unit(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassRes
.into()) .into())
} }
}; };
Ok(Value::Ident( Ok(Value::Ident(unit, QuoteKind::Quoted))
InternedString::get_or_intern(unit),
QuoteKind::Quoted,
))
} }
fn type_of(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> { fn type_of(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let value = arg!(args, scope, super_selector, 0, "value"); let value = arg!(args, scope, super_selector, 0, "value");
Ok(Value::Ident( Ok(Value::Ident(
InternedString::get_or_intern(value.kind(args.span())?), value.kind(args.span())?.to_owned(),
QuoteKind::None, QuoteKind::None,
)) ))
} }
@ -99,9 +95,9 @@ fn unitless(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sas
fn inspect(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> { fn inspect(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
Ok(Value::Ident( Ok(Value::Ident(
InternedString::get_or_intern( arg!(args, scope, super_selector, 0, "value")
arg!(args, scope, super_selector, 0, "value").inspect(args.span())?, .inspect(args.span())?
), .into(),
QuoteKind::None, QuoteKind::None,
)) ))
} }
@ -113,7 +109,7 @@ fn variable_exists(
) -> SassResult<Value> { ) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match arg!(args, scope, super_selector, 0, "name") { match arg!(args, scope, super_selector, 0, "name") {
Value::Ident(s, _) => Ok(Value::bool(scope.var_exists(s))), Value::Ident(s, _) => Ok(Value::bool(scope.var_exists(&s))),
v => Err(( v => Err((
format!("$name: {} is not a string.", v.to_css_string(args.span())?), format!("$name: {} is not a string.", v.to_css_string(args.span())?),
args.span(), args.span(),
@ -129,7 +125,7 @@ fn global_variable_exists(
) -> SassResult<Value> { ) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match arg!(args, scope, super_selector, 0, "name") { match arg!(args, scope, super_selector, 0, "name") {
Value::Ident(s, _) => Ok(Value::bool(global_var_exists(s))), Value::Ident(s, _) => Ok(Value::bool(global_var_exists(&s))),
v => Err(( v => Err((
format!("$name: {} is not a string.", v.to_css_string(args.span())?), format!("$name: {} is not a string.", v.to_css_string(args.span())?),
args.span(), args.span(),
@ -141,7 +137,7 @@ fn global_variable_exists(
fn mixin_exists(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> { fn mixin_exists(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
match arg!(args, scope, super_selector, 0, "name") { match arg!(args, scope, super_selector, 0, "name") {
Value::Ident(s, _) => Ok(Value::bool(scope.mixin_exists(s))), Value::Ident(s, _) => Ok(Value::bool(scope.mixin_exists(&s))),
v => Err(( v => Err((
format!("$name: {} is not a string.", v.to_css_string(args.span())?), format!("$name: {} is not a string.", v.to_css_string(args.span())?),
args.span(), args.span(),
@ -157,7 +153,9 @@ fn function_exists(
) -> SassResult<Value> { ) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
match arg!(args, scope, super_selector, 0, "name") { match arg!(args, scope, super_selector, 0, "name") {
Value::Ident(s, _) => Ok(Value::bool(scope.fn_exists(s))), Value::Ident(s, _) => Ok(Value::bool(
scope.fn_exists(&s) || GLOBAL_FUNCTIONS.contains_key(s.as_str()),
)),
v => Err(( v => Err((
format!("$name: {} is not a string.", v.to_css_string(args.span())?), format!("$name: {} is not a string.", v.to_css_string(args.span())?),
args.span(), args.span(),
@ -203,12 +201,12 @@ fn get_function(mut args: CallArgs, scope: &Scope, super_selector: &Selector) ->
} }
let func = match scope.get_fn(Spanned { let func = match scope.get_fn(Spanned {
node: name, node: name.clone(),
span: args.span(), span: args.span(),
}) { }) {
Ok(f) => SassFunction::UserDefined(Box::new(f), name.into()), Ok(f) => SassFunction::UserDefined(Box::new(f), name),
Err(..) => match GLOBAL_FUNCTIONS.get(&name.resolve_ref()) { Err(..) => match GLOBAL_FUNCTIONS.get(name.as_str()) {
Some(f) => SassFunction::Builtin(f.clone(), name.into()), Some(f) => SassFunction::Builtin(f.clone(), name),
None => return Err((format!("Function not found: {}", name), args.span()).into()), None => return Err((format!("Function not found: {}", name), args.span()).into()),
}, },
}; };

View File

@ -9,7 +9,6 @@ use rand::{distributions::Alphanumeric, thread_rng, Rng};
use crate::args::CallArgs; use crate::args::CallArgs;
use crate::common::QuoteKind; use crate::common::QuoteKind;
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
use crate::unit::Unit; use crate::unit::Unit;
@ -22,10 +21,9 @@ fn to_upper_case(
) -> SassResult<Value> { ) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match arg!(args, scope, super_selector, 0, "string") { match arg!(args, scope, super_selector, 0, "string") {
Value::Ident(i, q) => { Value::Ident(mut i, q) => {
let mut i = i.resolve();
i.make_ascii_uppercase(); i.make_ascii_uppercase();
Ok(Value::Ident(InternedString::get_or_intern(i), q)) Ok(Value::Ident(i, q))
} }
v => Err(( v => Err((
format!( format!(
@ -45,10 +43,9 @@ fn to_lower_case(
) -> SassResult<Value> { ) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match arg!(args, scope, super_selector, 0, "string") { match arg!(args, scope, super_selector, 0, "string") {
Value::Ident(i, q) => { Value::Ident(mut i, q) => {
let mut i = i.resolve();
i.make_ascii_lowercase(); i.make_ascii_lowercase();
Ok(Value::Ident(InternedString::get_or_intern(i), q)) Ok(Value::Ident(i, q))
} }
v => Err(( v => Err((
format!( format!(
@ -65,7 +62,7 @@ fn str_length(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> S
args.max_args(1)?; args.max_args(1)?;
match arg!(args, scope, super_selector, 0, "string") { match arg!(args, scope, super_selector, 0, "string") {
Value::Ident(i, _) => Ok(Value::Dimension( Value::Ident(i, _) => Ok(Value::Dimension(
Number::from(i.resolve().chars().count()), Number::from(i.chars().count()),
Unit::None, Unit::None,
)), )),
v => Err(( v => Err((
@ -124,7 +121,7 @@ fn str_slice(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sa
.into()) .into())
} }
}; };
let str_len = string.resolve().chars().count(); let str_len = string.chars().count();
let start = match arg!(args, scope, super_selector, 1, "start-at") { let start = match arg!(args, scope, super_selector, 1, "start-at") {
Value::Dimension(n, Unit::None) if n.is_decimal() => { Value::Dimension(n, Unit::None) if n.is_decimal() => {
return Err((format!("{} is not an int.", n), args.span()).into()) return Err((format!("{} is not an int.", n), args.span()).into())
@ -198,17 +195,14 @@ fn str_slice(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sa
} }
if start > end || start > str_len { if start > end || start > str_len {
Ok(Value::Ident(InternedString::get_or_intern(""), quotes)) Ok(Value::Ident(String::new(), quotes))
} else { } else {
Ok(Value::Ident( Ok(Value::Ident(
InternedString::get_or_intern( string
string .chars()
.resolve() .skip(start - 1)
.chars() .take(end - start + 1)
.skip(start - 1) .collect(),
.take(end - start + 1)
.collect::<String>(),
),
quotes, quotes,
)) ))
} }
@ -217,7 +211,7 @@ fn str_slice(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sa
fn str_index(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> { fn str_index(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let s1 = match arg!(args, scope, super_selector, 0, "string") { let s1 = match arg!(args, scope, super_selector, 0, "string") {
Value::Ident(i, _) => i.resolve(), Value::Ident(i, _) => i,
v => { v => {
return Err(( return Err((
format!( format!(
@ -231,7 +225,7 @@ fn str_index(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sa
}; };
let substr = match arg!(args, scope, super_selector, 1, "substring") { let substr = match arg!(args, scope, super_selector, 1, "substring") {
Value::Ident(i, _) => i.resolve(), Value::Ident(i, _) => i,
v => { v => {
return Err(( return Err((
format!( format!(
@ -253,7 +247,7 @@ fn str_index(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> Sa
fn str_insert(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> { fn str_insert(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let (s1, quotes) = match arg!(args, scope, super_selector, 0, "string") { let (s1, quotes) = match arg!(args, scope, super_selector, 0, "string") {
Value::Ident(i, q) => (i.resolve().to_string(), q), Value::Ident(i, q) => (i, q),
v => { v => {
return Err(( return Err((
format!( format!(
@ -267,7 +261,7 @@ fn str_insert(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> S
}; };
let substr = match arg!(args, scope, super_selector, 1, "insert") { let substr = match arg!(args, scope, super_selector, 1, "insert") {
Value::Ident(i, _) => i.resolve().to_string(), Value::Ident(i, _) => i,
v => { v => {
return Err(( return Err((
format!( format!(
@ -305,7 +299,7 @@ fn str_insert(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> S
}; };
if s1.is_empty() { if s1.is_empty() {
return Ok(Value::Ident(InternedString::get_or_intern(substr), quotes)); return Ok(Value::Ident(substr, quotes));
} }
let len = s1.chars().count(); let len = s1.chars().count();
@ -348,21 +342,18 @@ fn str_insert(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> S
} }
}; };
Ok(Value::Ident(InternedString::get_or_intern(string), quotes)) Ok(Value::Ident(string, quotes))
} }
#[cfg(feature = "random")] #[cfg(feature = "random")]
fn unique_id(args: CallArgs, _: &Scope, _: &Selector) -> SassResult<Value> { fn unique_id(args: CallArgs, _: &Scope, _: &Selector) -> SassResult<Value> {
args.max_args(0)?; args.max_args(0)?;
let mut rng = thread_rng(); let mut rng = thread_rng();
let string: String = std::iter::repeat(()) let string = std::iter::repeat(())
.map(|()| rng.sample(Alphanumeric)) .map(|()| rng.sample(Alphanumeric))
.take(7) .take(7)
.collect(); .collect();
Ok(Value::Ident( Ok(Value::Ident(string, QuoteKind::None))
InternedString::get_or_intern(string),
QuoteKind::None,
))
} }
pub(crate) fn declare(f: &mut GlobalFunctionMap) { pub(crate) fn declare(f: &mut GlobalFunctionMap) {

View File

@ -17,7 +17,6 @@
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use crate::interner::InternedString;
use crate::value::Number; use crate::value::Number;
pub(crate) use name::NAMED_COLORS; pub(crate) use name::NAMED_COLORS;
@ -469,14 +468,14 @@ impl Color {
/// Other color functions /// Other color functions
impl Color { impl Color {
pub fn to_ie_hex_str(&self) -> InternedString { pub fn to_ie_hex_str(&self) -> String {
InternedString::get_or_intern(format!( format!(
"#{:X}{:X}{:X}{:X}", "#{:X}{:X}{:X}{:X}",
(self.alpha() * Number::from(255)).round().to_integer(), (self.alpha() * Number::from(255)).round().to_integer(),
self.red().to_integer(), self.red().to_integer(),
self.green().to_integer(), self.green().to_integer(),
self.blue().to_integer() self.blue().to_integer()
)) )
} }
} }

View File

@ -4,11 +4,9 @@
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::collections::HashMap; use std::collections::HashMap;
use crate::interner::InternedString;
pub(crate) struct NamedColorMap { pub(crate) struct NamedColorMap {
name_to_rgba: HashMap<InternedString, [u8; 4]>, name_to_rgba: HashMap<&'static str, [u8; 4]>,
rgba_to_name: HashMap<[u8; 4], InternedString>, rgba_to_name: HashMap<[u8; 4], &'static str>,
} }
impl NamedColorMap { impl NamedColorMap {
@ -19,581 +17,161 @@ impl NamedColorMap {
} }
} }
fn insert(&mut self, name: InternedString, rgba: [u8; 4]) { pub fn insert(&mut self, name: &'static str, rgba: [u8; 4]) {
self.name_to_rgba.insert(name, rgba); self.name_to_rgba.insert(name, rgba);
self.rgba_to_name.insert(rgba, name); self.rgba_to_name.insert(rgba, name);
} }
pub fn get_by_name(&self, name: InternedString) -> Option<&[u8; 4]> { pub fn get_by_name(&self, name: &str) -> Option<&[u8; 4]> {
self.name_to_rgba.get(&name) self.name_to_rgba.get(name)
} }
pub fn get_by_rgba(&self, rgba: [u8; 4]) -> Option<&InternedString> { pub fn get_by_rgba(&self, rgba: [u8; 4]) -> Option<&&str> {
self.rgba_to_name.get(&rgba) self.rgba_to_name.get(&rgba)
} }
} }
pub(crate) static NAMED_COLORS: Lazy<NamedColorMap> = Lazy::new(|| { pub(crate) static NAMED_COLORS: Lazy<NamedColorMap> = Lazy::new(|| {
let mut m = NamedColorMap::with_capacity(150); let mut m = NamedColorMap::with_capacity(150);
m.insert( m.insert("aliceblue", [0xF0, 0xF8, 0xFF, 0xFF]);
InternedString::get_or_intern("aliceblue"), m.insert("antiquewhite", [0xFA, 0xEB, 0xD7, 0xFF]);
[0xF0, 0xF8, 0xFF, 0xFF], m.insert("aqua", [0x00, 0xFF, 0xFF, 0xFF]);
); m.insert("aquamarine", [0x7F, 0xFF, 0xD4, 0xFF]);
m.insert( m.insert("azure", [0xF0, 0xFF, 0xFF, 0xFF]);
InternedString::get_or_intern("antiquewhite"), m.insert("beige", [0xF5, 0xF5, 0xDC, 0xFF]);
[0xFA, 0xEB, 0xD7, 0xFF], m.insert("bisque", [0xFF, 0xE4, 0xC4, 0xFF]);
); m.insert("black", [0x00, 0x00, 0x00, 0xFF]);
m.insert( m.insert("blanchedalmond", [0xFF, 0xEB, 0xCD, 0xFF]);
InternedString::get_or_intern("aqua"), m.insert("blue", [0x00, 0x00, 0xFF, 0xFF]);
[0x00, 0xFF, 0xFF, 0xFF], m.insert("blueviolet", [0x8A, 0x2B, 0xE2, 0xFF]);
); m.insert("brown", [0xA5, 0x2A, 0x2A, 0xFF]);
m.insert( m.insert("burlywood", [0xDE, 0xB8, 0x87, 0xFF]);
InternedString::get_or_intern("aquamarine"), m.insert("cadetblue", [0x5F, 0x9E, 0xA0, 0xFF]);
[0x7F, 0xFF, 0xD4, 0xFF], m.insert("chartreuse", [0x7F, 0xFF, 0x00, 0xFF]);
); m.insert("chocolate", [0xD2, 0x69, 0x1E, 0xFF]);
m.insert( m.insert("coral", [0xFF, 0x7F, 0x50, 0xFF]);
InternedString::get_or_intern("azure"), m.insert("cornflowerblue", [0x64, 0x95, 0xED, 0xFF]);
[0xF0, 0xFF, 0xFF, 0xFF], m.insert("cornsilk", [0xFF, 0xF8, 0xDC, 0xFF]);
); m.insert("crimson", [0xDC, 0x14, 0x3C, 0xFF]);
m.insert( m.insert("darkblue", [0x00, 0x00, 0x8B, 0xFF]);
InternedString::get_or_intern("beige"), m.insert("darkcyan", [0x00, 0x8B, 0x8B, 0xFF]);
[0xF5, 0xF5, 0xDC, 0xFF], m.insert("darkgoldenrod", [0xB8, 0x86, 0x0B, 0xFF]);
); m.insert("darkgray", [0xA9, 0xA9, 0xA9, 0xFF]);
m.insert( m.insert("darkgreen", [0x00, 0x64, 0x00, 0xFF]);
InternedString::get_or_intern("bisque"), m.insert("darkkhaki", [0xBD, 0xB7, 0x6B, 0xFF]);
[0xFF, 0xE4, 0xC4, 0xFF], m.insert("darkmagenta", [0x8B, 0x00, 0x8B, 0xFF]);
); m.insert("darkolivegreen", [0x55, 0x6B, 0x2F, 0xFF]);
m.insert( m.insert("darkorange", [0xFF, 0x8C, 0x00, 0xFF]);
InternedString::get_or_intern("black"), m.insert("darkorchid", [0x99, 0x32, 0xCC, 0xFF]);
[0x00, 0x00, 0x00, 0xFF], m.insert("darkred", [0x8B, 0x00, 0x00, 0xFF]);
); m.insert("darksalmon", [0xE9, 0x96, 0x7A, 0xFF]);
m.insert( m.insert("darkseagreen", [0x8F, 0xBC, 0x8F, 0xFF]);
InternedString::get_or_intern("blanchedalmond"), m.insert("darkslateblue", [0x48, 0x3D, 0x8B, 0xFF]);
[0xFF, 0xEB, 0xCD, 0xFF], m.insert("darkslategray", [0x2F, 0x4F, 0x4F, 0xFF]);
); m.insert("darkturquoise", [0x00, 0xCE, 0xD1, 0xFF]);
m.insert( m.insert("darkviolet", [0x94, 0x00, 0xD3, 0xFF]);
InternedString::get_or_intern("blue"), m.insert("deeppink", [0xFF, 0x14, 0x93, 0xFF]);
[0x00, 0x00, 0xFF, 0xFF], m.insert("deepskyblue", [0x00, 0xBF, 0xFF, 0xFF]);
); m.insert("dimgray", [0x69, 0x69, 0x69, 0xFF]);
m.insert( m.insert("dodgerblue", [0x1E, 0x90, 0xFF, 0xFF]);
InternedString::get_or_intern("blueviolet"), m.insert("firebrick", [0xB2, 0x22, 0x22, 0xFF]);
[0x8A, 0x2B, 0xE2, 0xFF], m.insert("floralwhite", [0xFF, 0xFA, 0xF0, 0xFF]);
); m.insert("forestgreen", [0x22, 0x8B, 0x22, 0xFF]);
m.insert( m.insert("fuchsia", [0xFF, 0x00, 0xFF, 0xFF]);
InternedString::get_or_intern("brown"), m.insert("gainsboro", [0xDC, 0xDC, 0xDC, 0xFF]);
[0xA5, 0x2A, 0x2A, 0xFF], m.insert("ghostwhite", [0xF8, 0xF8, 0xFF, 0xFF]);
); m.insert("gold", [0xFF, 0xD7, 0x00, 0xFF]);
m.insert( m.insert("goldenrod", [0xDA, 0xA5, 0x20, 0xFF]);
InternedString::get_or_intern("burlywood"), m.insert("gray", [0x80, 0x80, 0x80, 0xFF]);
[0xDE, 0xB8, 0x87, 0xFF], m.insert("green", [0x00, 0x80, 0x00, 0xFF]);
); m.insert("greenyellow", [0xAD, 0xFF, 0x2F, 0xFF]);
m.insert( m.insert("honeydew", [0xF0, 0xFF, 0xF0, 0xFF]);
InternedString::get_or_intern("cadetblue"), m.insert("hotpink", [0xFF, 0x69, 0xB4, 0xFF]);
[0x5F, 0x9E, 0xA0, 0xFF], m.insert("indianred", [0xCD, 0x5C, 0x5C, 0xFF]);
); m.insert("indigo", [0x4B, 0x00, 0x82, 0xFF]);
m.insert( m.insert("ivory", [0xFF, 0xFF, 0xF0, 0xFF]);
InternedString::get_or_intern("chartreuse"), m.insert("khaki", [0xF0, 0xE6, 0x8C, 0xFF]);
[0x7F, 0xFF, 0x00, 0xFF], m.insert("lavender", [0xE6, 0xE6, 0xFA, 0xFF]);
); m.insert("lavenderblush", [0xFF, 0xF0, 0xF5, 0xFF]);
m.insert( m.insert("lawngreen", [0x7C, 0xFC, 0x00, 0xFF]);
InternedString::get_or_intern("chocolate"), m.insert("lemonchiffon", [0xFF, 0xFA, 0xCD, 0xFF]);
[0xD2, 0x69, 0x1E, 0xFF], m.insert("lightblue", [0xAD, 0xD8, 0xE6, 0xFF]);
); m.insert("lightcoral", [0xF0, 0x80, 0x80, 0xFF]);
m.insert( m.insert("lightcyan", [0xE0, 0xFF, 0xFF, 0xFF]);
InternedString::get_or_intern("coral"), m.insert("lightgoldenrodyellow", [0xFA, 0xFA, 0xD2, 0xFF]);
[0xFF, 0x7F, 0x50, 0xFF], m.insert("lightgray", [0xD3, 0xD3, 0xD3, 0xFF]);
); m.insert("lightgreen", [0x90, 0xEE, 0x90, 0xFF]);
m.insert( m.insert("lightpink", [0xFF, 0xB6, 0xC1, 0xFF]);
InternedString::get_or_intern("cornflowerblue"), m.insert("lightsalmon", [0xFF, 0xA0, 0x7A, 0xFF]);
[0x64, 0x95, 0xED, 0xFF], m.insert("lightseagreen", [0x20, 0xB2, 0xAA, 0xFF]);
); m.insert("lightskyblue", [0x87, 0xCE, 0xFA, 0xFF]);
m.insert( m.insert("lightslategray", [0x77, 0x88, 0x99, 0xFF]);
InternedString::get_or_intern("cornsilk"), m.insert("lightsteelblue", [0xB0, 0xC4, 0xDE, 0xFF]);
[0xFF, 0xF8, 0xDC, 0xFF], m.insert("lightyellow", [0xFF, 0xFF, 0xE0, 0xFF]);
); m.insert("lime", [0x00, 0xFF, 0x00, 0xFF]);
m.insert( m.insert("limegreen", [0x32, 0xCD, 0x32, 0xFF]);
InternedString::get_or_intern("crimson"), m.insert("linen", [0xFA, 0xF0, 0xE6, 0xFF]);
[0xDC, 0x14, 0x3C, 0xFF], m.insert("maroon", [0x80, 0x00, 0x00, 0xFF]);
); m.insert("mediumaquamarine", [0x66, 0xCD, 0xAA, 0xFF]);
m.insert( m.insert("mediumblue", [0x00, 0x00, 0xCD, 0xFF]);
InternedString::get_or_intern("darkblue"), m.insert("mediumorchid", [0xBA, 0x55, 0xD3, 0xFF]);
[0x00, 0x00, 0x8B, 0xFF], m.insert("mediumpurple", [0x93, 0x70, 0xDB, 0xFF]);
); m.insert("mediumseagreen", [0x3C, 0xB3, 0x71, 0xFF]);
m.insert( m.insert("mediumslateblue", [0x7B, 0x68, 0xEE, 0xFF]);
InternedString::get_or_intern("darkcyan"), m.insert("mediumspringgreen", [0x00, 0xFA, 0x9A, 0xFF]);
[0x00, 0x8B, 0x8B, 0xFF], m.insert("mediumturquoise", [0x48, 0xD1, 0xCC, 0xFF]);
); m.insert("mediumvioletred", [0xC7, 0x15, 0x85, 0xFF]);
m.insert( m.insert("midnightblue", [0x19, 0x19, 0x70, 0xFF]);
InternedString::get_or_intern("darkgoldenrod"), m.insert("mintcream", [0xF5, 0xFF, 0xFA, 0xFF]);
[0xB8, 0x86, 0x0B, 0xFF], m.insert("mistyrose", [0xFF, 0xE4, 0xE1, 0xFF]);
); m.insert("moccasin", [0xFF, 0xE4, 0xB5, 0xFF]);
m.insert( m.insert("navajowhite", [0xFF, 0xDE, 0xAD, 0xFF]);
InternedString::get_or_intern("darkgray"), m.insert("navy", [0x00, 0x00, 0x80, 0xFF]);
[0xA9, 0xA9, 0xA9, 0xFF], m.insert("oldlace", [0xFD, 0xF5, 0xE6, 0xFF]);
); m.insert("olive", [0x80, 0x80, 0x00, 0xFF]);
m.insert( m.insert("olivedrab", [0x6B, 0x8E, 0x23, 0xFF]);
InternedString::get_or_intern("darkgreen"), m.insert("orange", [0xFF, 0xA5, 0x00, 0xFF]);
[0x00, 0x64, 0x00, 0xFF], m.insert("orangered", [0xFF, 0x45, 0x00, 0xFF]);
); m.insert("orchid", [0xDA, 0x70, 0xD6, 0xFF]);
m.insert( m.insert("palegoldenrod", [0xEE, 0xE8, 0xAA, 0xFF]);
InternedString::get_or_intern("darkkhaki"), m.insert("palegreen", [0x98, 0xFB, 0x98, 0xFF]);
[0xBD, 0xB7, 0x6B, 0xFF], m.insert("paleturquoise", [0xAF, 0xEE, 0xEE, 0xFF]);
); m.insert("palevioletred", [0xDB, 0x70, 0x93, 0xFF]);
m.insert( m.insert("papayawhip", [0xFF, 0xEF, 0xD5, 0xFF]);
InternedString::get_or_intern("darkmagenta"), m.insert("peachpuff", [0xFF, 0xDA, 0xB9, 0xFF]);
[0x8B, 0x00, 0x8B, 0xFF], m.insert("peru", [0xCD, 0x85, 0x3F, 0xFF]);
); m.insert("pink", [0xFF, 0xC0, 0xCB, 0xFF]);
m.insert( m.insert("plum", [0xDD, 0xA0, 0xDD, 0xFF]);
InternedString::get_or_intern("darkolivegreen"), m.insert("powderblue", [0xB0, 0xE0, 0xE6, 0xFF]);
[0x55, 0x6B, 0x2F, 0xFF], m.insert("purple", [0x80, 0x00, 0x80, 0xFF]);
); m.insert("rebeccapurple", [0x66, 0x33, 0x99, 0xFF]);
m.insert( m.insert("red", [0xFF, 0x00, 0x00, 0xFF]);
InternedString::get_or_intern("darkorange"), m.insert("rosybrown", [0xBC, 0x8F, 0x8F, 0xFF]);
[0xFF, 0x8C, 0x00, 0xFF], m.insert("royalblue", [0x41, 0x69, 0xE1, 0xFF]);
); m.insert("saddlebrown", [0x8B, 0x45, 0x13, 0xFF]);
m.insert( m.insert("salmon", [0xFA, 0x80, 0x72, 0xFF]);
InternedString::get_or_intern("darkorchid"), m.insert("sandybrown", [0xF4, 0xA4, 0x60, 0xFF]);
[0x99, 0x32, 0xCC, 0xFF], m.insert("seagreen", [0x2E, 0x8B, 0x57, 0xFF]);
); m.insert("seashell", [0xFF, 0xF5, 0xEE, 0xFF]);
m.insert( m.insert("sienna", [0xA0, 0x52, 0x2D, 0xFF]);
InternedString::get_or_intern("darkred"), m.insert("silver", [0xC0, 0xC0, 0xC0, 0xFF]);
[0x8B, 0x00, 0x00, 0xFF], m.insert("skyblue", [0x87, 0xCE, 0xEB, 0xFF]);
); m.insert("slateblue", [0x6A, 0x5A, 0xCD, 0xFF]);
m.insert( m.insert("slategray", [0x70, 0x80, 0x90, 0xFF]);
InternedString::get_or_intern("darksalmon"), m.insert("snow", [0xFF, 0xFA, 0xFA, 0xFF]);
[0xE9, 0x96, 0x7A, 0xFF], m.insert("springgreen", [0x00, 0xFF, 0x7F, 0xFF]);
); m.insert("steelblue", [0x46, 0x82, 0xB4, 0xFF]);
m.insert( m.insert("tan", [0xD2, 0xB4, 0x8C, 0xFF]);
InternedString::get_or_intern("darkseagreen"), m.insert("teal", [0x00, 0x80, 0x80, 0xFF]);
[0x8F, 0xBC, 0x8F, 0xFF], m.insert("thistle", [0xD8, 0xBF, 0xD8, 0xFF]);
); m.insert("tomato", [0xFF, 0x63, 0x47, 0xFF]);
m.insert( m.insert("turquoise", [0x40, 0xE0, 0xD0, 0xFF]);
InternedString::get_or_intern("darkslateblue"), m.insert("violet", [0xEE, 0x82, 0xEE, 0xFF]);
[0x48, 0x3D, 0x8B, 0xFF], m.insert("wheat", [0xF5, 0xDE, 0xB3, 0xFF]);
); m.insert("white", [0xFF, 0xFF, 0xFF, 0xFF]);
m.insert( m.insert("whitesmoke", [0xF5, 0xF5, 0xF5, 0xFF]);
InternedString::get_or_intern("darkslategray"), m.insert("yellow", [0xFF, 0xFF, 0x00, 0xFF]);
[0x2F, 0x4F, 0x4F, 0xFF], m.insert("yellowgreen", [0x9A, 0xCD, 0x32, 0xFF]);
); m.insert("transparent", [0x00, 0x00, 0x00, 0x00]);
m.insert(
InternedString::get_or_intern("darkturquoise"),
[0x00, 0xCE, 0xD1, 0xFF],
);
m.insert(
InternedString::get_or_intern("darkviolet"),
[0x94, 0x00, 0xD3, 0xFF],
);
m.insert(
InternedString::get_or_intern("deeppink"),
[0xFF, 0x14, 0x93, 0xFF],
);
m.insert(
InternedString::get_or_intern("deepskyblue"),
[0x00, 0xBF, 0xFF, 0xFF],
);
m.insert(
InternedString::get_or_intern("dimgray"),
[0x69, 0x69, 0x69, 0xFF],
);
m.insert(
InternedString::get_or_intern("dodgerblue"),
[0x1E, 0x90, 0xFF, 0xFF],
);
m.insert(
InternedString::get_or_intern("firebrick"),
[0xB2, 0x22, 0x22, 0xFF],
);
m.insert(
InternedString::get_or_intern("floralwhite"),
[0xFF, 0xFA, 0xF0, 0xFF],
);
m.insert(
InternedString::get_or_intern("forestgreen"),
[0x22, 0x8B, 0x22, 0xFF],
);
m.insert(
InternedString::get_or_intern("fuchsia"),
[0xFF, 0x00, 0xFF, 0xFF],
);
m.insert(
InternedString::get_or_intern("gainsboro"),
[0xDC, 0xDC, 0xDC, 0xFF],
);
m.insert(
InternedString::get_or_intern("ghostwhite"),
[0xF8, 0xF8, 0xFF, 0xFF],
);
m.insert(
InternedString::get_or_intern("gold"),
[0xFF, 0xD7, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("goldenrod"),
[0xDA, 0xA5, 0x20, 0xFF],
);
m.insert(
InternedString::get_or_intern("gray"),
[0x80, 0x80, 0x80, 0xFF],
);
m.insert(
InternedString::get_or_intern("green"),
[0x00, 0x80, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("greenyellow"),
[0xAD, 0xFF, 0x2F, 0xFF],
);
m.insert(
InternedString::get_or_intern("honeydew"),
[0xF0, 0xFF, 0xF0, 0xFF],
);
m.insert(
InternedString::get_or_intern("hotpink"),
[0xFF, 0x69, 0xB4, 0xFF],
);
m.insert(
InternedString::get_or_intern("indianred"),
[0xCD, 0x5C, 0x5C, 0xFF],
);
m.insert(
InternedString::get_or_intern("indigo"),
[0x4B, 0x00, 0x82, 0xFF],
);
m.insert(
InternedString::get_or_intern("ivory"),
[0xFF, 0xFF, 0xF0, 0xFF],
);
m.insert(
InternedString::get_or_intern("khaki"),
[0xF0, 0xE6, 0x8C, 0xFF],
);
m.insert(
InternedString::get_or_intern("lavender"),
[0xE6, 0xE6, 0xFA, 0xFF],
);
m.insert(
InternedString::get_or_intern("lavenderblush"),
[0xFF, 0xF0, 0xF5, 0xFF],
);
m.insert(
InternedString::get_or_intern("lawngreen"),
[0x7C, 0xFC, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("lemonchiffon"),
[0xFF, 0xFA, 0xCD, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightblue"),
[0xAD, 0xD8, 0xE6, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightcoral"),
[0xF0, 0x80, 0x80, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightcyan"),
[0xE0, 0xFF, 0xFF, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightgoldenrodyellow"),
[0xFA, 0xFA, 0xD2, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightgray"),
[0xD3, 0xD3, 0xD3, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightgreen"),
[0x90, 0xEE, 0x90, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightpink"),
[0xFF, 0xB6, 0xC1, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightsalmon"),
[0xFF, 0xA0, 0x7A, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightseagreen"),
[0x20, 0xB2, 0xAA, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightskyblue"),
[0x87, 0xCE, 0xFA, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightslategray"),
[0x77, 0x88, 0x99, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightsteelblue"),
[0xB0, 0xC4, 0xDE, 0xFF],
);
m.insert(
InternedString::get_or_intern("lightyellow"),
[0xFF, 0xFF, 0xE0, 0xFF],
);
m.insert(
InternedString::get_or_intern("lime"),
[0x00, 0xFF, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("limegreen"),
[0x32, 0xCD, 0x32, 0xFF],
);
m.insert(
InternedString::get_or_intern("linen"),
[0xFA, 0xF0, 0xE6, 0xFF],
);
m.insert(
InternedString::get_or_intern("maroon"),
[0x80, 0x00, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumaquamarine"),
[0x66, 0xCD, 0xAA, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumblue"),
[0x00, 0x00, 0xCD, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumorchid"),
[0xBA, 0x55, 0xD3, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumpurple"),
[0x93, 0x70, 0xDB, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumseagreen"),
[0x3C, 0xB3, 0x71, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumslateblue"),
[0x7B, 0x68, 0xEE, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumspringgreen"),
[0x00, 0xFA, 0x9A, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumturquoise"),
[0x48, 0xD1, 0xCC, 0xFF],
);
m.insert(
InternedString::get_or_intern("mediumvioletred"),
[0xC7, 0x15, 0x85, 0xFF],
);
m.insert(
InternedString::get_or_intern("midnightblue"),
[0x19, 0x19, 0x70, 0xFF],
);
m.insert(
InternedString::get_or_intern("mintcream"),
[0xF5, 0xFF, 0xFA, 0xFF],
);
m.insert(
InternedString::get_or_intern("mistyrose"),
[0xFF, 0xE4, 0xE1, 0xFF],
);
m.insert(
InternedString::get_or_intern("moccasin"),
[0xFF, 0xE4, 0xB5, 0xFF],
);
m.insert(
InternedString::get_or_intern("navajowhite"),
[0xFF, 0xDE, 0xAD, 0xFF],
);
m.insert(
InternedString::get_or_intern("navy"),
[0x00, 0x00, 0x80, 0xFF],
);
m.insert(
InternedString::get_or_intern("oldlace"),
[0xFD, 0xF5, 0xE6, 0xFF],
);
m.insert(
InternedString::get_or_intern("olive"),
[0x80, 0x80, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("olivedrab"),
[0x6B, 0x8E, 0x23, 0xFF],
);
m.insert(
InternedString::get_or_intern("orange"),
[0xFF, 0xA5, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("orangered"),
[0xFF, 0x45, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("orchid"),
[0xDA, 0x70, 0xD6, 0xFF],
);
m.insert(
InternedString::get_or_intern("palegoldenrod"),
[0xEE, 0xE8, 0xAA, 0xFF],
);
m.insert(
InternedString::get_or_intern("palegreen"),
[0x98, 0xFB, 0x98, 0xFF],
);
m.insert(
InternedString::get_or_intern("paleturquoise"),
[0xAF, 0xEE, 0xEE, 0xFF],
);
m.insert(
InternedString::get_or_intern("palevioletred"),
[0xDB, 0x70, 0x93, 0xFF],
);
m.insert(
InternedString::get_or_intern("papayawhip"),
[0xFF, 0xEF, 0xD5, 0xFF],
);
m.insert(
InternedString::get_or_intern("peachpuff"),
[0xFF, 0xDA, 0xB9, 0xFF],
);
m.insert(
InternedString::get_or_intern("peru"),
[0xCD, 0x85, 0x3F, 0xFF],
);
m.insert(
InternedString::get_or_intern("pink"),
[0xFF, 0xC0, 0xCB, 0xFF],
);
m.insert(
InternedString::get_or_intern("plum"),
[0xDD, 0xA0, 0xDD, 0xFF],
);
m.insert(
InternedString::get_or_intern("powderblue"),
[0xB0, 0xE0, 0xE6, 0xFF],
);
m.insert(
InternedString::get_or_intern("purple"),
[0x80, 0x00, 0x80, 0xFF],
);
m.insert(
InternedString::get_or_intern("rebeccapurple"),
[0x66, 0x33, 0x99, 0xFF],
);
m.insert(
InternedString::get_or_intern("red"),
[0xFF, 0x00, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("rosybrown"),
[0xBC, 0x8F, 0x8F, 0xFF],
);
m.insert(
InternedString::get_or_intern("royalblue"),
[0x41, 0x69, 0xE1, 0xFF],
);
m.insert(
InternedString::get_or_intern("saddlebrown"),
[0x8B, 0x45, 0x13, 0xFF],
);
m.insert(
InternedString::get_or_intern("salmon"),
[0xFA, 0x80, 0x72, 0xFF],
);
m.insert(
InternedString::get_or_intern("sandybrown"),
[0xF4, 0xA4, 0x60, 0xFF],
);
m.insert(
InternedString::get_or_intern("seagreen"),
[0x2E, 0x8B, 0x57, 0xFF],
);
m.insert(
InternedString::get_or_intern("seashell"),
[0xFF, 0xF5, 0xEE, 0xFF],
);
m.insert(
InternedString::get_or_intern("sienna"),
[0xA0, 0x52, 0x2D, 0xFF],
);
m.insert(
InternedString::get_or_intern("silver"),
[0xC0, 0xC0, 0xC0, 0xFF],
);
m.insert(
InternedString::get_or_intern("skyblue"),
[0x87, 0xCE, 0xEB, 0xFF],
);
m.insert(
InternedString::get_or_intern("slateblue"),
[0x6A, 0x5A, 0xCD, 0xFF],
);
m.insert(
InternedString::get_or_intern("slategray"),
[0x70, 0x80, 0x90, 0xFF],
);
m.insert(
InternedString::get_or_intern("snow"),
[0xFF, 0xFA, 0xFA, 0xFF],
);
m.insert(
InternedString::get_or_intern("springgreen"),
[0x00, 0xFF, 0x7F, 0xFF],
);
m.insert(
InternedString::get_or_intern("steelblue"),
[0x46, 0x82, 0xB4, 0xFF],
);
m.insert(
InternedString::get_or_intern("tan"),
[0xD2, 0xB4, 0x8C, 0xFF],
);
m.insert(
InternedString::get_or_intern("teal"),
[0x00, 0x80, 0x80, 0xFF],
);
m.insert(
InternedString::get_or_intern("thistle"),
[0xD8, 0xBF, 0xD8, 0xFF],
);
m.insert(
InternedString::get_or_intern("tomato"),
[0xFF, 0x63, 0x47, 0xFF],
);
m.insert(
InternedString::get_or_intern("turquoise"),
[0x40, 0xE0, 0xD0, 0xFF],
);
m.insert(
InternedString::get_or_intern("violet"),
[0xEE, 0x82, 0xEE, 0xFF],
);
m.insert(
InternedString::get_or_intern("wheat"),
[0xF5, 0xDE, 0xB3, 0xFF],
);
m.insert(
InternedString::get_or_intern("white"),
[0xFF, 0xFF, 0xFF, 0xFF],
);
m.insert(
InternedString::get_or_intern("whitesmoke"),
[0xF5, 0xF5, 0xF5, 0xFF],
);
m.insert(
InternedString::get_or_intern("yellow"),
[0xFF, 0xFF, 0x00, 0xFF],
);
m.insert(
InternedString::get_or_intern("yellowgreen"),
[0x9A, 0xCD, 0x32, 0xFF],
);
m.insert(
InternedString::get_or_intern("transparent"),
[0x00, 0x00, 0x00, 0x00],
);
m m
}); });

View File

@ -1,4 +1,3 @@
use crate::interner::InternedString;
use std::fmt::{self, Display, Write}; use std::fmt::{self, Display, Write};
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -120,38 +119,3 @@ impl Display for QualifiedName {
f.write_str(&self.ident) f.write_str(&self.ident)
} }
} }
#[derive(Debug, Clone, Hash, Eq, PartialEq, Copy)]
pub(crate) struct Identifier(InternedString);
impl Into<Identifier> for InternedString {
fn into(self) -> Identifier {
Identifier(InternedString::get_or_intern(
self.resolve_ref().replace('_', "-"),
))
}
}
impl From<String> for Identifier {
fn from(s: String) -> Identifier {
Identifier(InternedString::get_or_intern(s.replace('_', "-")))
}
}
impl Into<Identifier> for &String {
fn into(self) -> Identifier {
Identifier(InternedString::get_or_intern(self.replace('_', "-")))
}
}
impl Into<Identifier> for &str {
fn into(self) -> Identifier {
Identifier(InternedString::get_or_intern(self.replace('_', "-")))
}
}
impl Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

View File

@ -1,35 +0,0 @@
use lasso::{Rodeo, Spur};
use std::cell::RefCell;
use std::fmt::{self, Display};
thread_local!(static STRINGS: RefCell<Rodeo<Spur>> = RefCell::new(Rodeo::default()));
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct InternedString(Spur);
impl InternedString {
pub fn get_or_intern<T: AsRef<str>>(s: T) -> Self {
Self(STRINGS.with(|interner| interner.borrow_mut().get_or_intern(s)))
}
pub fn resolve(self) -> String {
STRINGS.with(|interner| interner.borrow().resolve(&self.0).to_string())
}
pub fn is_empty(self) -> bool {
self.resolve_ref() == ""
}
pub fn resolve_ref<'a>(self) -> &'a str {
unsafe {
STRINGS.with(|interner| &(*(interner.as_ptr()).as_ref().unwrap().resolve(&self.0)))
}
}
}
impl Display for InternedString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
STRINGS.with(|interner| write!(f, "{}", interner.borrow().resolve(&self.0)))
}
}

View File

@ -90,7 +90,6 @@ use peekmore::{PeekMore, PeekMoreIterator};
use crate::atrule::{AtRule, AtRuleKind, Function, Mixin}; use crate::atrule::{AtRule, AtRuleKind, Function, Mixin};
pub use crate::error::{SassError, SassResult}; pub use crate::error::{SassError, SassResult};
use crate::interner::InternedString;
use crate::scope::{insert_global_var, Scope}; use crate::scope::{insert_global_var, Scope};
use crate::selector::Selector; use crate::selector::Selector;
use crate::style::Style; use crate::style::Style;
@ -110,7 +109,6 @@ mod color;
mod common; mod common;
mod error; mod error;
mod imports; mod imports;
mod interner;
mod lexer; mod lexer;
mod output; mod output;
mod scope; mod scope;
@ -200,7 +198,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
&mut values.into_iter().peekmore(), &mut values.into_iter().peekmore(),
scope, scope,
super_selector, super_selector,
InternedString::get_or_intern(""), String::new(),
tok.pos, tok.pos,
)?; )?;
return Ok(Some(Spanned { return Ok(Some(Spanned {
@ -220,7 +218,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
devour_whitespace(toks); devour_whitespace(toks);
return Ok(Some(Spanned { return Ok(Some(Spanned {
node: Expr::Style(Box::new(Style { node: Expr::Style(Box::new(Style {
property: InternedString::get_or_intern(""), property: String::new(),
value: Value::Null.span(span), value: Value::Null.span(span),
})), })),
span, span,
@ -230,7 +228,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
&mut v, &mut v,
scope, scope,
super_selector, super_selector,
InternedString::get_or_intern(""), String::new(),
span_before, span_before,
)?; )?;
let value = Style::parse_value(&mut v, scope, super_selector)?; let value = Style::parse_value(&mut v, scope, super_selector)?;
@ -257,7 +255,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
&mut v, &mut v,
scope, scope,
super_selector, super_selector,
InternedString::get_or_intern(""), String::new(),
tok.pos, tok.pos,
)?; )?;
let value = Style::parse_value(&mut v, scope, super_selector)?; let value = Style::parse_value(&mut v, scope, super_selector)?;

View File

@ -4,70 +4,66 @@ use std::collections::HashMap;
use codemap::Spanned; use codemap::Spanned;
use crate::atrule::{Function, Mixin}; use crate::atrule::{Function, Mixin};
use crate::common::Identifier;
use crate::error::SassResult; use crate::error::SassResult;
use crate::value::Value; use crate::value::Value;
thread_local!(pub(crate) static GLOBAL_SCOPE: RefCell<Scope> = RefCell::new(Scope::new())); thread_local!(pub(crate) static GLOBAL_SCOPE: RefCell<Scope> = RefCell::new(Scope::new()));
pub(crate) fn get_global_var<T: Into<Identifier>>(s: Spanned<T>) -> SassResult<Spanned<Value>> { pub(crate) fn get_global_var(s: Spanned<String>) -> SassResult<Spanned<Value>> {
GLOBAL_SCOPE.with(|scope| match scope.borrow().vars().get(&s.node.into()) { GLOBAL_SCOPE.with(|scope| match scope.borrow().vars().get(&s.node) {
Some(v) => Ok(v.clone()), Some(v) => Ok(v.clone()),
None => Err(("Undefined variable.", s.span).into()), None => Err(("Undefined variable.", s.span).into()),
}) })
} }
/// Returns true if a variable exists in the *global* scope pub(crate) fn global_var_exists(v: &str) -> bool {
pub(crate) fn global_var_exists<T: Into<Identifier>>(v: T) -> bool { GLOBAL_SCOPE.with(|scope| scope.borrow().vars().contains_key(&v.replace('_', "-")))
GLOBAL_SCOPE.with(|scope| scope.borrow().vars().contains_key(&v.into()))
} }
pub(crate) fn insert_global_var<T: Into<Identifier>>( pub(crate) fn insert_global_var(s: &str, v: Spanned<Value>) -> SassResult<Option<Spanned<Value>>> {
s: T, GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s, v))
v: Spanned<Value>,
) -> SassResult<Option<Spanned<Value>>> {
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s.into(), v))
} }
pub(crate) fn get_global_fn<T: Into<Identifier>>(s: Spanned<T>) -> SassResult<Function> { pub(crate) fn get_global_fn(s: Spanned<String>) -> SassResult<Function> {
GLOBAL_SCOPE.with( GLOBAL_SCOPE.with(|scope| match scope.borrow().functions().get(&s.node) {
|scope| match scope.borrow().functions().get(&s.node.into()) { Some(v) => Ok(v.clone()),
Some(v) => Ok(v.clone()), None => Err(("Undefined function.", s.span).into()),
None => Err(("Undefined function.", s.span).into()), })
},
)
} }
/// Returns true if a function exists in the *global* scope pub(crate) fn global_fn_exists(v: &str) -> bool {
pub(crate) fn global_fn_exists<T: Into<Identifier>>(v: T) -> bool { GLOBAL_SCOPE.with(|scope| {
GLOBAL_SCOPE.with(|scope| scope.borrow().functions().contains_key(&v.into())) scope
.borrow()
.functions()
.contains_key(&v.replace('_', "-"))
})
} }
pub(crate) fn insert_global_fn<T: Into<Identifier>>(s: T, v: Function) -> Option<Function> { pub(crate) fn insert_global_fn(s: &str, v: Function) -> Option<Function> {
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_fn(s.into(), v)) GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_fn(s, v))
} }
pub(crate) fn get_global_mixin<T: Into<Identifier>>(s: Spanned<T>) -> SassResult<Mixin> { pub(crate) fn get_global_mixin(s: Spanned<String>) -> SassResult<Mixin> {
GLOBAL_SCOPE.with(|scope| match scope.borrow().mixins().get(&s.node.into()) { GLOBAL_SCOPE.with(|scope| match scope.borrow().mixins().get(&s.node) {
Some(v) => Ok(v.clone()), Some(v) => Ok(v.clone()),
None => Err(("Undefined mixin.", s.span).into()), None => Err(("Undefined mixin.", s.span).into()),
}) })
} }
/// Returns true if a mixin exists in the *global* scope pub(crate) fn global_mixin_exists(v: &str) -> bool {
pub(crate) fn global_mixin_exists<T: Into<Identifier>>(v: T) -> bool { GLOBAL_SCOPE.with(|scope| scope.borrow().mixins().contains_key(&v.replace('_', "-")))
GLOBAL_SCOPE.with(|scope| scope.borrow().mixins().contains_key(&v.into()))
} }
pub(crate) fn insert_global_mixin<T: Into<Identifier>>(s: T, v: Mixin) -> Option<Mixin> { pub(crate) fn insert_global_mixin(s: &str, v: Mixin) -> Option<Mixin> {
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_mixin(s.into(), v)) GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_mixin(s, v))
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Scope { pub(crate) struct Scope {
vars: HashMap<Identifier, Spanned<Value>>, vars: HashMap<String, Spanned<Value>>,
mixins: HashMap<Identifier, Mixin>, mixins: HashMap<String, Mixin>,
functions: HashMap<Identifier, Function>, functions: HashMap<String, Function>,
} }
impl Scope { impl Scope {
@ -80,72 +76,68 @@ impl Scope {
} }
} }
pub const fn vars(&self) -> &HashMap<Identifier, Spanned<Value>> { pub const fn vars(&self) -> &HashMap<String, Spanned<Value>> {
&self.vars &self.vars
} }
pub const fn functions(&self) -> &HashMap<Identifier, Function> { pub const fn functions(&self) -> &HashMap<String, Function> {
&self.functions &self.functions
} }
pub const fn mixins(&self) -> &HashMap<Identifier, Mixin> { pub const fn mixins(&self) -> &HashMap<String, Mixin> {
&self.mixins &self.mixins
} }
pub fn get_var<T: Into<Identifier>>(&self, name: Spanned<T>) -> SassResult<Spanned<Value>> { pub fn get_var(&self, mut name: Spanned<String>) -> SassResult<Spanned<Value>> {
let name = name.map_node(|n| n.into()); name.node = name.node.replace('_', "-");
match self.vars.get(&name.node) { match self.vars.get(&name.node) {
Some(v) => Ok(v.clone()), Some(v) => Ok(v.clone()),
None => get_global_var(name), None => get_global_var(name),
} }
} }
pub fn insert_var<T: Into<Identifier>>( pub fn insert_var(&mut self, s: &str, v: Spanned<Value>) -> SassResult<Option<Spanned<Value>>> {
&mut self,
s: T,
v: Spanned<Value>,
) -> SassResult<Option<Spanned<Value>>> {
let Spanned { node, span } = v; let Spanned { node, span } = v;
Ok(self.vars.insert(s.into(), node.eval(span)?)) Ok(self.vars.insert(s.replace('_', "-"), node.eval(span)?))
} }
pub fn var_exists<T: Into<Identifier>>(&self, v: T) -> bool { pub fn var_exists(&self, v: &str) -> bool {
let name = v.into(); let name = &v.replace('_', "-");
self.vars.contains_key(&name) || global_var_exists(name) self.vars.contains_key(name) || global_var_exists(name)
} }
pub fn get_mixin<T: Into<Identifier>>(&self, name: Spanned<T>) -> SassResult<Mixin> { pub fn get_mixin(&self, mut name: Spanned<String>) -> SassResult<Mixin> {
let name = name.map_node(|n| n.into()); name.node = name.node.replace('_', "-");
match self.mixins.get(&name.node) { match self.mixins.get(&name.node) {
Some(v) => Ok(v.clone()), Some(v) => Ok(v.clone()),
None => get_global_mixin(name), None => get_global_mixin(name),
} }
} }
pub fn insert_mixin<T: Into<Identifier>>(&mut self, s: T, v: Mixin) -> Option<Mixin> { pub fn insert_mixin(&mut self, s: &str, v: Mixin) -> Option<Mixin> {
self.mixins.insert(s.into(), v) self.mixins.insert(s.replace('_', "-"), v)
} }
pub fn mixin_exists<T: Into<Identifier>>(&self, v: T) -> bool { pub fn mixin_exists(&self, v: &str) -> bool {
let name = v.into(); let name = &v.replace('_', "-");
self.mixins.contains_key(&name) || global_mixin_exists(name) self.mixins.contains_key(name) || global_mixin_exists(name)
} }
pub fn get_fn<T: Into<Identifier>>(&self, name: Spanned<T>) -> SassResult<Function> { pub fn get_fn(&self, mut name: Spanned<String>) -> SassResult<Function> {
let name = name.map_node(|n| n.into()); name.node = name.node.replace('_', "-");
match self.functions.get(&name.node) { match self.functions.get(&name.node) {
Some(v) => Ok(v.clone()), Some(v) => Ok(v.clone()),
None => get_global_fn(name), None => get_global_fn(name),
} }
} }
pub fn insert_fn<T: Into<Identifier>>(&mut self, s: T, v: Function) -> Option<Function> { pub fn insert_fn(&mut self, s: &str, v: Function) -> Option<Function> {
self.functions.insert(s.into(), v) self.functions.insert(s.replace('_', "-"), v)
} }
pub fn fn_exists<T: Into<Identifier>>(&self, v: T) -> bool { pub fn fn_exists(&self, v: &str) -> bool {
let name = v.into(); let name = &v.replace('_', "-");
self.functions.contains_key(&name) || global_fn_exists(name) self.functions.contains_key(name) || global_fn_exists(name)
} }
pub fn extend(&mut self, other: Scope) { pub fn extend(&mut self, other: Scope) {

View File

@ -7,7 +7,6 @@ use codemap::Span;
use super::{Selector, SelectorKind}; use super::{Selector, SelectorKind};
use crate::common::{QualifiedName, QuoteKind}; use crate::common::{QualifiedName, QuoteKind};
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::utils::{devour_whitespace, eat_ident, is_ident, parse_quoted_string}; use crate::utils::{devour_whitespace, eat_ident, is_ident, parse_quoted_string};
use crate::value::Value; use crate::value::Value;
@ -125,7 +124,7 @@ impl Attribute {
q @ '\'' | q @ '"' => { q @ '\'' | q @ '"' => {
toks.next(); toks.next();
match parse_quoted_string(toks, scope, q, super_selector)?.node { match parse_quoted_string(toks, scope, q, super_selector)?.node {
Value::Ident(s, ..) => s.resolve().to_string(), Value::Ident(s, ..) => s,
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -181,12 +180,9 @@ impl Display for Attribute {
// or having special emitter for quoted strings? // or having special emitter for quoted strings?
// (also avoids the clone because we can consume/modify self) // (also avoids the clone because we can consume/modify self)
f.write_str( f.write_str(
&Value::Ident( &Value::Ident(self.value.clone(), QuoteKind::Quoted)
InternedString::get_or_intern(self.value.clone()), .to_css_string(self.span)
QuoteKind::Quoted, .unwrap(),
)
.to_css_string(self.span)
.unwrap(),
)?; )?;
// todo: this space is not emitted when `compressed` output // todo: this space is not emitted when `compressed` output
if self.modifier.is_some() { if self.modifier.is_some() {

View File

@ -4,7 +4,6 @@ use peekmore::{PeekMore, PeekMoreIterator};
use crate::common::{Brackets, ListSeparator, QuoteKind}; use crate::common::{Brackets, ListSeparator, QuoteKind};
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::utils::{ use crate::utils::{
devour_whitespace, eat_comment, eat_ident_no_interpolation, parse_interpolation, devour_whitespace, eat_comment, eat_ident_no_interpolation, parse_interpolation,
@ -58,12 +57,7 @@ impl SelectorPart {
Value::List( Value::List(
kinds kinds
.iter() .iter()
.map(|s| { .map(|s| Value::Ident(s.to_string(), QuoteKind::None))
Value::Ident(
InternedString::get_or_intern(s.to_string()),
QuoteKind::None,
)
})
.collect(), .collect(),
ListSeparator::Space, ListSeparator::Space,
Brackets::None, Brackets::None,

View File

@ -3,7 +3,6 @@ use peekmore::PeekMoreIterator;
use codemap::{Span, Spanned}; use codemap::{Span, Spanned};
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
use crate::utils::{devour_whitespace, devour_whitespace_or_comment, eat_ident}; use crate::utils::{devour_whitespace, devour_whitespace_or_comment, eat_ident};
@ -13,7 +12,7 @@ use crate::{Expr, Token};
/// A style: `color: red` /// A style: `color: red`
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct Style { pub(crate) struct Style {
pub property: InternedString, pub property: String,
pub value: Spanned<Value>, pub value: Spanned<Value>,
} }
@ -22,9 +21,9 @@ impl Style {
toks: &mut PeekMoreIterator<I>, toks: &mut PeekMoreIterator<I>,
scope: &Scope, scope: &Scope,
super_selector: &Selector, super_selector: &Selector,
super_property: InternedString, super_property: String,
span_before: Span, span_before: Span,
) -> SassResult<InternedString> { ) -> SassResult<String> {
StyleParser::new(scope, super_selector).parse_property(toks, super_property, span_before) StyleParser::new(scope, super_selector).parse_property(toks, super_property, span_before)
} }
@ -58,7 +57,7 @@ impl Style {
toks: &mut PeekMoreIterator<I>, toks: &mut PeekMoreIterator<I>,
scope: &Scope, scope: &Scope,
super_selector: &Selector, super_selector: &Selector,
super_property: InternedString, super_property: String,
) -> SassResult<Expr> { ) -> SassResult<Expr> {
StyleParser::new(scope, super_selector).eat_style_group(toks, super_property, scope) StyleParser::new(scope, super_selector).eat_style_group(toks, super_property, scope)
} }
@ -89,7 +88,7 @@ impl<'a> StyleParser<'a> {
pub(crate) fn eat_style_group<I: Iterator<Item = Token>>( pub(crate) fn eat_style_group<I: Iterator<Item = Token>>(
&self, &self,
toks: &mut PeekMoreIterator<I>, toks: &mut PeekMoreIterator<I>,
super_property: InternedString, super_property: String,
scope: &Scope, scope: &Scope,
) -> SassResult<Expr> { ) -> SassResult<Expr> {
let mut styles = Vec::new(); let mut styles = Vec::new();
@ -100,7 +99,8 @@ impl<'a> StyleParser<'a> {
let span_before = toks.next().unwrap().pos; let span_before = toks.next().unwrap().pos;
devour_whitespace(toks); devour_whitespace(toks);
loop { loop {
let property = self.parse_property(toks, super_property, span_before)?; let property =
self.parse_property(toks, super_property.clone(), span_before)?;
if let Some(tok) = toks.peek() { if let Some(tok) = toks.peek() {
if tok.kind == '{' { if tok.kind == '{' {
match self.eat_style_group(toks, property, scope)? { match self.eat_style_group(toks, property, scope)? {
@ -133,7 +133,7 @@ impl<'a> StyleParser<'a> {
} }
'{' => { '{' => {
styles.push(Style { styles.push(Style {
property: property, property: property.clone(),
value, value,
}); });
match self.eat_style_group(toks, property, scope)? { match self.eat_style_group(toks, property, scope)? {
@ -170,7 +170,7 @@ impl<'a> StyleParser<'a> {
} }
'{' => { '{' => {
let mut v = vec![Style { let mut v = vec![Style {
property: super_property, property: super_property.clone(),
value, value,
}]; }];
match self.eat_style_group(toks, super_property, scope)? { match self.eat_style_group(toks, super_property, scope)? {
@ -195,9 +195,9 @@ impl<'a> StyleParser<'a> {
pub(crate) fn parse_property<I: Iterator<Item = Token>>( pub(crate) fn parse_property<I: Iterator<Item = Token>>(
&self, &self,
toks: &mut PeekMoreIterator<I>, toks: &mut PeekMoreIterator<I>,
super_property: InternedString, mut super_property: String,
span_before: Span, span_before: Span,
) -> SassResult<InternedString> { ) -> SassResult<String> {
devour_whitespace(toks); devour_whitespace(toks);
let property = eat_ident(toks, self.scope, self.super_selector, span_before)?; let property = eat_ident(toks, self.scope, self.super_selector, span_before)?;
devour_whitespace_or_comment(toks)?; devour_whitespace_or_comment(toks)?;
@ -209,13 +209,12 @@ impl<'a> StyleParser<'a> {
} }
if super_property.is_empty() { if super_property.is_empty() {
Ok(InternedString::get_or_intern(property.node)) Ok(property.node)
} else { } else {
let mut super_property = super_property.resolve().to_string();
super_property.reserve(1 + property.node.len()); super_property.reserve(1 + property.node.len());
super_property.push('-'); super_property.push('-');
super_property.push_str(&property.node); super_property.push_str(&property.node);
Ok(InternedString::get_or_intern(super_property)) Ok(super_property)
} }
} }
} }

View File

@ -10,7 +10,6 @@ use peekmore::{PeekMore, PeekMoreIterator};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use crate::atrule::{eat_include, AtRule, AtRuleKind}; use crate::atrule::{eat_include, AtRule, AtRuleKind};
use crate::common::Identifier;
use crate::error::{SassError, SassResult}; use crate::error::{SassError, SassResult};
use crate::imports::import; use crate::imports::import;
use crate::lexer::Lexer; use crate::lexer::Lexer;
@ -165,9 +164,8 @@ impl<'a> StyleSheetParser<'a> {
let mut rules: Vec<Spanned<Stmt>> = Vec::new(); let mut rules: Vec<Spanned<Stmt>> = Vec::new();
while let Some(Token { kind, .. }) = self.lexer.peek() { while let Some(Token { kind, .. }) = self.lexer.peek() {
match kind { match kind {
_ if is_selector_char(*kind) => { _ if is_selector_char(*kind) => rules
rules.extend(self.eat_rules(&Selector::new(), &mut Scope::new())?) .extend(self.eat_rules(&Selector::new(), &mut Scope::new())?),
}
'\t' | '\n' | ' ' => { '\t' | '\n' | ' ' => {
self.lexer.next(); self.lexer.next();
continue; continue;
@ -179,18 +177,15 @@ impl<'a> StyleSheetParser<'a> {
match self.lexer.peek() { match self.lexer.peek() {
Some(Token { kind: ':', .. }) => { Some(Token { kind: ':', .. }) => {
self.lexer self.lexer.take(name.node.chars().count() + whitespace + 1)
.take(name.node.chars().count() + whitespace + 1)
.for_each(drop); .for_each(drop);
devour_whitespace(self.lexer); devour_whitespace(self.lexer);
let name = name.map_node(|n| Identifier::from(n));
let VariableDecl { val, default, .. } = let VariableDecl { val, default, .. } =
eat_variable_value(self.lexer, &Scope::new(), &Selector::new())?; eat_variable_value(self.lexer, &Scope::new(), &Selector::new())?;
if !(default && global_var_exists(name.node)) { if !(default && global_var_exists(&name)) {
insert_global_var(name.node, val)?; insert_global_var(&name.node, val)?;
} }
} }
Some(..) | None => return Err(("expected \":\".", name.span).into()), Some(..) | None => return Err(("expected \":\".", name.span).into()),
@ -207,15 +202,17 @@ impl<'a> StyleSheetParser<'a> {
let comment = eat_comment(self.lexer, &Scope::new(), &Selector::new())?; let comment = eat_comment(self.lexer, &Scope::new(), &Selector::new())?;
rules.push(comment.map_node(Stmt::MultilineComment)); rules.push(comment.map_node(Stmt::MultilineComment));
} }
_ => return Err(("expected selector.", pos).into()), _ => return Err(("expected selector.", pos).into())
} }
} }
'@' => { '@' => {
let span_before = self.lexer.next().unwrap().pos(); let span_before = self.lexer.next().unwrap().pos();
let Spanned { let Spanned { node: at_rule_kind, span } = eat_ident(
node: at_rule_kind, self.lexer,
span, &Scope::new(),
} = eat_ident(self.lexer, &Scope::new(), &Selector::new(), span_before)?; &Selector::new(),
span_before
)?;
if at_rule_kind.is_empty() { if at_rule_kind.is_empty() {
return Err(("Expected identifier.", span).into()); return Err(("Expected identifier.", span).into());
} }
@ -225,14 +222,14 @@ impl<'a> StyleSheetParser<'a> {
&Scope::new(), &Scope::new(),
&Selector::new(), &Selector::new(),
None, None,
span, span
)?), )?),
AtRuleKind::Import => { AtRuleKind::Import => {
devour_whitespace(self.lexer); devour_whitespace(self.lexer);
let mut file_name = String::new(); let mut file_name = String::new();
let next = match self.lexer.next() { let next = match self.lexer.next() {
Some(v) => v, Some(v) => v,
None => todo!("expected input after @import"), None => todo!("expected input after @import")
}; };
match next.kind { match next.kind {
q @ '"' | q @ '\'' => { q @ '"' | q @ '\'' => {
@ -241,12 +238,8 @@ impl<'a> StyleSheetParser<'a> {
self.lexer, self.lexer,
&Scope::new(), &Scope::new(),
q, q,
&Selector::new(), &Selector::new())?
)? .node.unquote().to_css_string(span)?);
.node
.unquote()
.to_css_string(span)?,
);
} }
_ => return Err(("Expected string.", next.pos()).into()), _ => return Err(("Expected string.", next.pos()).into()),
} }
@ -258,22 +251,14 @@ impl<'a> StyleSheetParser<'a> {
devour_whitespace(self.lexer); devour_whitespace(self.lexer);
let (new_rules, new_scope) = let (new_rules, new_scope) = import(self.path, file_name.as_ref(), &mut self.map)?;
import(self.path, file_name.as_ref(), &mut self.map)?;
rules.extend(new_rules); rules.extend(new_rules);
GLOBAL_SCOPE.with(|s| { GLOBAL_SCOPE.with(|s| {
s.borrow_mut().extend(new_scope); s.borrow_mut().extend(new_scope);
}); });
} }
v => { v => {
let rule = AtRule::from_tokens( let rule = AtRule::from_tokens(v, span, self.lexer, &mut Scope::new(), &Selector::new(), None)?;
v,
span,
self.lexer,
&mut Scope::new(),
&Selector::new(),
None,
)?;
match rule.node { match rule.node {
AtRule::Mixin(name, mixin) => { AtRule::Mixin(name, mixin) => {
insert_global_mixin(&name, *mixin); insert_global_mixin(&name, *mixin);
@ -289,36 +274,17 @@ impl<'a> StyleSheetParser<'a> {
("This at-rule is not allowed here.", rule.span).into() ("This at-rule is not allowed here.", rule.span).into()
) )
} }
AtRule::For(f) => rules.extend(f.ruleset_eval( AtRule::For(f) => rules.extend(f.ruleset_eval(&mut Scope::new(), &Selector::new(), None)?),
&mut Scope::new(), AtRule::While(w) => rules.extend(w.ruleset_eval(&mut Scope::new(), &Selector::new(), true, None)?),
&Selector::new(), AtRule::Each(e) => {
None, rules.extend(e.ruleset_eval(&mut Scope::new(), &Selector::new(), None)?)
)?),
AtRule::While(w) => rules.extend(w.ruleset_eval(
&mut Scope::new(),
&Selector::new(),
true,
None,
)?),
AtRule::Each(e) => rules.extend(e.ruleset_eval(
&mut Scope::new(),
&Selector::new(),
None,
)?),
AtRule::Include(s) => rules.extend(s),
AtRule::Content => {
return Err((
"@content is only allowed within mixin declarations.",
rule.span,
)
.into())
} }
AtRule::Include(s) => rules.extend(s),
AtRule::Content => return Err(
("@content is only allowed within mixin declarations.", rule.span
).into()),
AtRule::If(i) => { AtRule::If(i) => {
rules.extend(i.eval( rules.extend(i.eval(&mut Scope::new(), &Selector::new(), None)?);
&mut Scope::new(),
&Selector::new(),
None,
)?);
} }
AtRule::AtRoot(root_rules) => rules.extend(root_rules), AtRule::AtRoot(root_rules) => rules.extend(root_rules),
AtRule::Unknown(..) => rules.push(rule.map_node(Stmt::AtRule)), AtRule::Unknown(..) => rules.push(rule.map_node(Stmt::AtRule)),
@ -326,13 +292,11 @@ impl<'a> StyleSheetParser<'a> {
} }
} }
} }
} },
'&' => { '&' => {
return Err(( return Err(
"Top-level selectors may not contain the parent selector \"&\".", ("Top-level selectors may not contain the parent selector \"&\".", self.lexer.next().unwrap().pos()).into(),
self.lexer.next().unwrap().pos(),
) )
.into())
} }
c if c.is_control() => { c if c.is_control() => {
return Err(("expected selector.", self.lexer.next().unwrap().pos()).into()); return Err(("expected selector.", self.lexer.next().unwrap().pos()).into());

View File

@ -6,7 +6,6 @@ use peekmore::PeekMoreIterator;
use crate::common::QuoteKind; use crate::common::QuoteKind;
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::selector::Selector; use crate::selector::Selector;
use crate::value::Value; use crate::value::Value;
use crate::{Scope, Token}; use crate::{Scope, Token};
@ -214,7 +213,7 @@ pub(crate) fn eat_ident<I: Iterator<Item = Token>>(
toks.next(); toks.next();
text.push_str( text.push_str(
&match parse_interpolation(toks, scope, super_selector)?.node { &match parse_interpolation(toks, scope, super_selector)?.node {
Value::Ident(s, ..) => s.resolve().to_string(), Value::Ident(s, ..) => s,
v => v.to_css_string(span)?.into(), v => v.to_css_string(span)?.into(),
}, },
); );
@ -292,7 +291,7 @@ pub(crate) fn parse_quoted_string<I: Iterator<Item = Token>>(
toks.next(); toks.next();
let interpolation = parse_interpolation(toks, scope, super_selector)?; let interpolation = parse_interpolation(toks, scope, super_selector)?;
s.push_str(&match interpolation.node { s.push_str(&match interpolation.node {
Value::Ident(s, ..) => s.resolve().to_string(), Value::Ident(s, ..) => s,
v => v.to_css_string(interpolation.span)?.into(), v => v.to_css_string(interpolation.span)?.into(),
}); });
continue; continue;
@ -346,7 +345,7 @@ pub(crate) fn parse_quoted_string<I: Iterator<Item = Token>>(
} }
} }
Ok(Spanned { Ok(Spanned {
node: Value::Ident(InternedString::get_or_intern(s), QuoteKind::Quoted), node: Value::Ident(s, QuoteKind::Quoted),
span, span,
}) })
} }

View File

@ -113,7 +113,7 @@ pub(crate) fn try_eat_url<I: Iterator<Item = Token>>(
let (interpolation, count) = peek_interpolation(toks, scope, super_selector)?; let (interpolation, count) = peek_interpolation(toks, scope, super_selector)?;
peek_counter += count; peek_counter += count;
buf.push_str(&match interpolation.node { buf.push_str(&match interpolation.node {
Value::Ident(s, ..) => s.resolve().to_string(), Value::Ident(s, ..) => s,
v => v.to_css_string(interpolation.span)?.into(), v => v.to_css_string(interpolation.span)?.into(),
}); });
} else { } else {

View File

@ -6,7 +6,6 @@ use codemap::{Span, Spanned};
use crate::color::Color; use crate::color::Color;
use crate::common::{Brackets, ListSeparator, Op, QuoteKind}; use crate::common::{Brackets, ListSeparator, Op, QuoteKind};
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::unit::Unit; use crate::unit::Unit;
use crate::utils::hex_char_for; use crate::utils::hex_char_for;
@ -34,7 +33,7 @@ pub(crate) enum Value {
UnaryOp(Op, Box<Value>), UnaryOp(Op, Box<Value>),
BinaryOp(Box<Value>, Op, Box<Value>), BinaryOp(Box<Value>, Op, Box<Value>),
Paren(Box<Value>), Paren(Box<Value>),
Ident(InternedString, QuoteKind), Ident(String, QuoteKind),
Map(SassMap), Map(SassMap),
ArgList(Vec<Spanned<Value>>), ArgList(Vec<Spanned<Value>>),
/// Returned by `get-function()` /// Returned by `get-function()`
@ -168,7 +167,6 @@ impl Value {
} }
Self::Paren(val) => val.to_css_string(span)?, Self::Paren(val) => val.to_css_string(span)?,
Self::Ident(string, QuoteKind::None) => { Self::Ident(string, QuoteKind::None) => {
let string = string.resolve();
let mut after_newline = false; let mut after_newline = false;
let mut buf = String::with_capacity(string.len()); let mut buf = String::with_capacity(string.len());
for c in string.chars() { for c in string.chars() {
@ -191,9 +189,8 @@ impl Value {
Cow::Owned(buf) Cow::Owned(buf)
} }
Self::Ident(string, QuoteKind::Quoted) => { Self::Ident(string, QuoteKind::Quoted) => {
let string = string.resolve();
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::Borrowed("true"),
@ -252,7 +249,7 @@ impl Value {
pub fn is_special_function(&self) -> bool { pub fn is_special_function(&self) -> bool {
match self { match self {
Self::Ident(s, QuoteKind::None) => is_special_function(s.resolve_ref()), Self::Ident(s, QuoteKind::None) => is_special_function(s),
_ => false, _ => false,
} }
} }

View File

@ -4,7 +4,6 @@ use codemap::{Span, Spanned};
use crate::common::{Op, QuoteKind}; use crate::common::{Op, QuoteKind};
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::unit::{Unit, UNIT_CONVERSION_TABLE}; use crate::unit::{Unit, UNIT_CONVERSION_TABLE};
use crate::value::Value; use crate::value::Value;
@ -112,10 +111,7 @@ impl Value {
pub fn unary_op_plus(self, span: Span) -> SassResult<Self> { pub fn unary_op_plus(self, span: Span) -> SassResult<Self> {
Ok(match self.eval(span)?.node { Ok(match self.eval(span)?.node {
v @ Value::Dimension(..) => v, v @ Value::Dimension(..) => v,
v => Value::Ident( v => Value::Ident(format!("+{}", v.to_css_string(span)?), QuoteKind::None),
InternedString::get_or_intern(format!("+{}", v.to_css_string(span)?)),
QuoteKind::None,
),
}) })
} }
@ -263,28 +259,22 @@ impl Value {
Self::Function(..) | Self::ArgList(..) | Self::Map(..) => todo!(), Self::Function(..) | Self::ArgList(..) | Self::Map(..) => todo!(),
Self::Important | Self::True | Self::False => match other { Self::Important | Self::True | Self::False => match other {
Self::Ident(s, QuoteKind::Quoted) => Value::Ident( Self::Ident(s, QuoteKind::Quoted) => Value::Ident(
InternedString::get_or_intern(format!("{}{}", self.to_css_string(span)?, s)), format!("{}{}", self.to_css_string(span)?, s),
QuoteKind::Quoted, QuoteKind::Quoted,
), ),
Self::Null => Value::Ident( Self::Null => Value::Ident(self.to_css_string(span)?.into(), QuoteKind::None),
InternedString::get_or_intern(self.to_css_string(span)?.into_owned()),
QuoteKind::None,
),
_ => Value::Ident( _ => Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}{}", "{}{}",
self.to_css_string(span)?, self.to_css_string(span)?,
other.to_css_string(span)? other.to_css_string(span)?
)), ),
QuoteKind::None, QuoteKind::None,
), ),
}, },
Self::Null => match other { Self::Null => match other {
Self::Null => Self::Null, Self::Null => Self::Null,
_ => Value::Ident( _ => Value::Ident(other.to_css_string(span)?.into(), QuoteKind::None),
InternedString::get_or_intern(dbg!(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) => {
@ -309,30 +299,14 @@ impl Value {
) )
} }
} }
Self::Ident(s, q) => Value::Ident( Self::Ident(s, q) => Value::Ident(format!("{}{}{}", num, unit, s), q),
InternedString::get_or_intern(format!("{}{}{}", num, unit, s)), Self::Null => Value::Ident(format!("{}{}", num, unit), QuoteKind::None),
q,
),
Self::Null => Value::Ident(
InternedString::get_or_intern(format!("{}{}", num, unit)),
QuoteKind::None,
),
Self::List(..) => Value::Ident( Self::List(..) => Value::Ident(
InternedString::get_or_intern(format!( format!("{}{}{}", num, unit, other.to_css_string(span)?),
"{}{}{}",
num,
unit,
other.to_css_string(span)?
)),
QuoteKind::None, QuoteKind::None,
), ),
Self::True | Self::False => Self::Ident( Self::True | Self::False => Self::Ident(
InternedString::get_or_intern(format!( format!("{}{}{}", num, unit, other.to_css_string(span)?),
"{}{}{}",
num,
unit,
other.to_css_string(span)?
)),
QuoteKind::None, QuoteKind::None,
), ),
_ => { _ => {
@ -349,15 +323,10 @@ impl Value {
} }
}, },
Self::Color(c) => match other { Self::Color(c) => match other {
Self::Ident(s, q) => { Self::Ident(s, q) => Value::Ident(format!("{}{}", c, s), q),
Value::Ident(InternedString::get_or_intern(format!("{}{}", c, s)), q) Self::Null => Value::Ident(c.to_string(), QuoteKind::None),
}
Self::Null => Value::Ident(
InternedString::get_or_intern(c.to_string()),
QuoteKind::None,
),
Self::List(..) => Value::Ident( Self::List(..) => Value::Ident(
InternedString::get_or_intern(format!("{}{}", c, other.to_css_string(span)?)), format!("{}{}", c, other.to_css_string(span)?),
QuoteKind::None, QuoteKind::None,
), ),
_ => { _ => {
@ -394,27 +363,18 @@ impl Value {
} }
Self::UnaryOp(..) | Self::Paren(..) => self.eval(span)?.node.add(other, span)?, Self::UnaryOp(..) | Self::Paren(..) => self.eval(span)?.node.add(other, span)?,
Self::Ident(text, quotes) => match other { Self::Ident(text, quotes) => match other {
Self::Ident(text2, ..) => Self::Ident( Self::Ident(text2, ..) => Self::Ident(text + &text2, quotes),
InternedString::get_or_intern(text.resolve() + text2.resolve_ref()), _ => Value::Ident(text + &other.to_css_string(span)?, quotes),
quotes,
),
_ => Value::Ident(
InternedString::get_or_intern(text.resolve() + &other.to_css_string(span)?),
quotes,
),
}, },
Self::List(..) => match other { Self::List(..) => match other {
Self::Ident(s, q) => Value::Ident( Self::Ident(s, q) => Value::Ident(format!("{}{}", self.to_css_string(span)?, s), q),
InternedString::get_or_intern(format!("{}{}", self.to_css_string(span)?, s)),
q,
),
Self::Paren(..) => (self.add(other.eval(span)?.node, span))?, Self::Paren(..) => (self.add(other.eval(span)?.node, span))?,
_ => Value::Ident( _ => Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}{}", "{}{}",
self.to_css_string(span)?, self.to_css_string(span)?,
other.to_css_string(span)? other.to_css_string(span)?
)), ),
QuoteKind::None, QuoteKind::None,
), ),
}, },
@ -452,34 +412,20 @@ impl Value {
} }
} }
Self::List(..) => Value::Ident( Self::List(..) => Value::Ident(
InternedString::get_or_intern(format!( format!("{}{}-{}", num, unit, other.to_css_string(span)?),
"{}{}-{}",
num,
unit,
other.to_css_string(span)?
)),
QuoteKind::None, QuoteKind::None,
), ),
Self::Ident(..) => Value::Ident( Self::Ident(..) => Value::Ident(
InternedString::get_or_intern(format!( format!("{}{}-{}", num, unit, other.to_css_string(span)?),
"{}{}-{}",
num,
unit,
other.to_css_string(span)?
)),
QuoteKind::None, QuoteKind::None,
), ),
_ => todo!(), _ => todo!(),
}, },
Self::Color(c) => match other { Self::Color(c) => match other {
Self::Ident(s, q) => Value::Ident( Self::Ident(s, q) => {
InternedString::get_or_intern(format!("{}-{}{}{}", c, q, s, q)), Value::Ident(format!("{}-{}{}{}", c, q, s, q), QuoteKind::None)
QuoteKind::None, }
), Self::Null => Value::Ident(format!("{}-", c), QuoteKind::None),
Self::Null => Value::Ident(
InternedString::get_or_intern(format!("{}-", c)),
QuoteKind::None,
),
Self::Dimension(..) | Self::Color(..) => { Self::Dimension(..) | Self::Color(..) => {
return Err(( return Err((
format!( format!(
@ -492,7 +438,7 @@ impl Value {
.into()) .into())
} }
_ => Value::Ident( _ => Value::Ident(
InternedString::get_or_intern(format!("{}-{}", c, other.to_css_string(span)?)), format!("{}-{}", c, other.to_css_string(span)?),
QuoteKind::None, QuoteKind::None,
), ),
}, },
@ -518,54 +464,41 @@ impl Value {
} }
Self::Paren(..) => self.eval(span)?.node.sub(other, span)?, Self::Paren(..) => self.eval(span)?.node.sub(other, span)?,
Self::Ident(..) => Self::Ident( Self::Ident(..) => Self::Ident(
InternedString::get_or_intern(format!( format!(
"{}-{}", "{}-{}",
self.to_css_string(span)?, self.to_css_string(span)?,
other.to_css_string(span)? other.to_css_string(span)?
)), ),
QuoteKind::None, QuoteKind::None,
), ),
Self::List(..) => match other { Self::List(..) => match other {
Self::Ident(s, q) => Value::Ident( Self::Ident(s, q) => Value::Ident(
InternedString::get_or_intern(format!( format!("{}-{}{}{}", self.to_css_string(span)?, q, s, q),
"{}-{}{}{}",
self.to_css_string(span)?,
q,
s,
q
)),
QuoteKind::None, QuoteKind::None,
), ),
_ => Value::Ident( _ => Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}-{}", "{}-{}",
self.to_css_string(span)?, self.to_css_string(span)?,
other.to_css_string(span)? other.to_css_string(span)?
)), ),
QuoteKind::None, QuoteKind::None,
), ),
}, },
_ => match other { _ => match other {
Self::Ident(s, q) => Value::Ident( Self::Ident(s, q) => Value::Ident(
InternedString::get_or_intern(format!( format!("{}-{}{}{}", self.to_css_string(span)?, q, s, q),
"{}-{}{}{}",
self.to_css_string(span)?,
q,
s,
q
)),
QuoteKind::None,
),
Self::Null => Value::Ident(
InternedString::get_or_intern(format!("{}-", self.to_css_string(span)?)),
QuoteKind::None, QuoteKind::None,
), ),
Self::Null => {
Value::Ident(format!("{}-", self.to_css_string(span)?), QuoteKind::None)
}
_ => Value::Ident( _ => Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}-{}", "{}-{}",
self.to_css_string(span)?, self.to_css_string(span)?,
other.to_css_string(span)? other.to_css_string(span)?
)), ),
QuoteKind::None, QuoteKind::None,
), ),
}, },
@ -671,24 +604,19 @@ impl Value {
) )
} }
} }
Self::Ident(s, q) => Value::Ident( Self::Ident(s, q) => {
InternedString::get_or_intern(format!("{}{}/{}{}{}", num, unit, q, s, q)), Value::Ident(format!("{}{}/{}{}{}", num, unit, q, s, q), QuoteKind::None)
QuoteKind::None, }
),
Self::BinaryOp(..) | Self::Paren(..) => { Self::BinaryOp(..) | Self::Paren(..) => {
Self::Dimension(num, unit).div(other.eval(span)?.node, span)? Self::Dimension(num, unit).div(other.eval(span)?.node, span)?
} }
_ => todo!(), _ => todo!(),
}, },
Self::Color(c) => match other { Self::Color(c) => match other {
Self::Ident(s, q) => Value::Ident( Self::Ident(s, q) => {
InternedString::get_or_intern(format!("{}/{}{}{}", c, q, s, q)), Value::Ident(format!("{}/{}{}{}", c, q, s, q), QuoteKind::None)
QuoteKind::None, }
), Self::Null => Value::Ident(format!("{}/", c), QuoteKind::None),
Self::Null => Value::Ident(
InternedString::get_or_intern(format!("{}/", c)),
QuoteKind::None,
),
Self::Dimension(..) | Self::Color(..) => { Self::Dimension(..) | Self::Color(..) => {
return Err(( return Err((
format!( format!(
@ -701,7 +629,7 @@ impl Value {
.into()) .into())
} }
_ => Value::Ident( _ => Value::Ident(
InternedString::get_or_intern(format!("{}/{}", c, other.to_css_string(span)?)), format!("{}/{}", c, other.to_css_string(span)?),
QuoteKind::None, QuoteKind::None,
), ),
}, },
@ -728,7 +656,7 @@ impl Value {
Self::Paren(..) => self.eval(span)?.node.div(other, span)?, Self::Paren(..) => self.eval(span)?.node.div(other, span)?,
Self::Ident(s1, q1) => match other { Self::Ident(s1, q1) => match other {
Self::Ident(s2, q2) => Value::Ident( Self::Ident(s2, q2) => Value::Ident(
InternedString::get_or_intern(format!("{}{}{}/{}{}{}", q1, s1, q1, q2, s2, q2)), format!("{}{}{}/{}{}{}", q1, s1, q1, q2, s2, q2),
QuoteKind::None, QuoteKind::None,
), ),
Self::Important Self::Important
@ -736,42 +664,26 @@ impl Value {
| Self::False | Self::False
| Self::Dimension(..) | Self::Dimension(..)
| Self::Color(..) => Value::Ident( | Self::Color(..) => Value::Ident(
InternedString::get_or_intern(format!( format!("{}{}{}/{}", q1, s1, q1, other.to_css_string(span)?),
"{}{}{}/{}",
q1,
s1,
q1,
other.to_css_string(span)?
)),
QuoteKind::None,
),
Self::Null => Value::Ident(
InternedString::get_or_intern(format!("{}{}{}/", q1, s1, q1)),
QuoteKind::None, QuoteKind::None,
), ),
Self::Null => Value::Ident(format!("{}{}{}/", q1, s1, q1), QuoteKind::None),
_ => todo!(), _ => todo!(),
}, },
_ => match other { _ => match other {
Self::Ident(s, q) => Value::Ident( Self::Ident(s, q) => Value::Ident(
InternedString::get_or_intern(format!( format!("{}/{}{}{}", self.to_css_string(span)?, q, s, q),
"{}/{}{}{}",
self.to_css_string(span)?,
q,
s,
q
)),
QuoteKind::None,
),
Self::Null => Value::Ident(
InternedString::get_or_intern(format!("{}/", self.to_css_string(span)?)),
QuoteKind::None, QuoteKind::None,
), ),
Self::Null => {
Value::Ident(format!("{}/", self.to_css_string(span)?), QuoteKind::None)
}
_ => Value::Ident( _ => Value::Ident(
InternedString::get_or_intern(format!( format!(
"{}/{}", "{}/{}",
self.to_css_string(span)?, self.to_css_string(span)?,
other.to_css_string(span)? other.to_css_string(span)?
)), ),
QuoteKind::None, QuoteKind::None,
), ),
}, },
@ -824,10 +736,7 @@ impl Value {
pub fn neg(self, span: Span) -> SassResult<Self> { pub fn neg(self, span: Span) -> SassResult<Self> {
Ok(match self.eval(span)?.node { Ok(match self.eval(span)?.node {
Value::Dimension(n, u) => Value::Dimension(-n, u), Value::Dimension(n, u) => Value::Dimension(-n, u),
v => Value::Ident( v => Value::Ident(format!("-{}", v.to_css_string(span)?), QuoteKind::None),
InternedString::get_or_intern(format!("-{}", v.to_css_string(span)?)),
QuoteKind::None,
),
}) })
} }
} }

View File

@ -16,7 +16,6 @@ use crate::builtin::GLOBAL_FUNCTIONS;
use crate::color::{Color, NAMED_COLORS}; use crate::color::{Color, NAMED_COLORS};
use crate::common::{Brackets, ListSeparator, Op, QuoteKind}; use crate::common::{Brackets, ListSeparator, Op, QuoteKind};
use crate::error::SassResult; use crate::error::SassResult;
use crate::interner::InternedString;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
use crate::unit::Unit; use crate::unit::Unit;
@ -59,10 +58,7 @@ fn parse_hex<I: Iterator<Item = Token>>(
span = span.merge(i.span); span = span.merge(i.span);
} else { } else {
return Ok(Spanned { return Ok(Spanned {
node: Value::Ident( node: Value::Ident(format!("#{}", i.node), QuoteKind::None),
InternedString::get_or_intern(format!("#{}", i.node)),
QuoteKind::None,
),
span: i.span, span: i.span,
}); });
} }
@ -71,13 +67,7 @@ fn parse_hex<I: Iterator<Item = Token>>(
3 => { 3 => {
let v = match u16::from_str_radix(&s, 16) { let v = match u16::from_str_radix(&s, 16) {
Ok(a) => a, Ok(a) => a,
Err(_) => { Err(_) => return Ok(Value::Ident(format!("#{}", s), QuoteKind::None).span(span)),
return Ok(Value::Ident(
InternedString::get_or_intern(format!("#{}", s)),
QuoteKind::None,
)
.span(span))
}
}; };
let red = (((v & 0xf00) >> 8) * 0x11) as u8; let red = (((v & 0xf00) >> 8) * 0x11) as u8;
let green = (((v & 0x0f0) >> 4) * 0x11) as u8; let green = (((v & 0x0f0) >> 4) * 0x11) as u8;
@ -90,13 +80,7 @@ fn parse_hex<I: Iterator<Item = Token>>(
4 => { 4 => {
let v = match u16::from_str_radix(&s, 16) { let v = match u16::from_str_radix(&s, 16) {
Ok(a) => a, Ok(a) => a,
Err(_) => { Err(_) => return Ok(Value::Ident(format!("#{}", s), QuoteKind::None).span(span)),
return Ok(Value::Ident(
InternedString::get_or_intern(format!("#{}", s)),
QuoteKind::None,
)
.span(span))
}
}; };
let red = (((v & 0xf000) >> 12) * 0x11) as u8; let red = (((v & 0xf000) >> 12) * 0x11) as u8;
let green = (((v & 0x0f00) >> 8) * 0x11) as u8; let green = (((v & 0x0f00) >> 8) * 0x11) as u8;
@ -114,13 +98,7 @@ fn parse_hex<I: Iterator<Item = Token>>(
6 => { 6 => {
let v = match u32::from_str_radix(&s, 16) { let v = match u32::from_str_radix(&s, 16) {
Ok(a) => a, Ok(a) => a,
Err(_) => { Err(_) => return Ok(Value::Ident(format!("#{}", s), QuoteKind::None).span(span)),
return Ok(Value::Ident(
InternedString::get_or_intern(format!("#{}", s)),
QuoteKind::None,
)
.span(span))
}
}; };
let red = ((v & 0x00ff_0000) >> 16) as u8; let red = ((v & 0x00ff_0000) >> 16) as u8;
let green = ((v & 0x0000_ff00) >> 8) as u8; let green = ((v & 0x0000_ff00) >> 8) as u8;
@ -133,13 +111,7 @@ fn parse_hex<I: Iterator<Item = Token>>(
8 => { 8 => {
let v = match u32::from_str_radix(&s, 16) { let v = match u32::from_str_radix(&s, 16) {
Ok(a) => a, Ok(a) => a,
Err(_) => { Err(_) => return Ok(Value::Ident(format!("#{}", s), QuoteKind::None).span(span)),
return Ok(Value::Ident(
InternedString::get_or_intern(format!("#{}", s)),
QuoteKind::None,
)
.span(span))
}
}; };
let red = ((v & 0xff00_0000) >> 24) as u8; let red = ((v & 0xff00_0000) >> 24) as u8;
let green = ((v & 0x00ff_0000) >> 16) as u8; let green = ((v & 0x00ff_0000) >> 16) as u8;
@ -293,10 +265,7 @@ fn eat_op<I: Iterator<Item = Token>>(
devour_whitespace(iter); devour_whitespace(iter);
space_separated.push(Spanned { space_separated.push(Spanned {
node: Value::Ident( node: Value::Ident(
InternedString::get_or_intern(format!( format!("/{}", right.node.to_css_string(right.span)?),
"/{}",
right.node.to_css_string(right.span)?
)),
QuoteKind::None, QuoteKind::None,
), ),
span: op.span.merge(right.span), span: op.span.merge(right.span),
@ -340,13 +309,7 @@ fn eat_op<I: Iterator<Item = Token>>(
devour_whitespace(iter); devour_whitespace(iter);
// special case when the value is literally "and" or "or" // special case when the value is literally "and" or "or"
if iter.peek().is_none() { if iter.peek().is_none() {
space_separated.push( space_separated.push(Value::Ident(op.to_string(), QuoteKind::None).span(op.span));
Value::Ident(
InternedString::get_or_intern(op.to_string()),
QuoteKind::None,
)
.span(op.span),
);
} else if let Some(left) = space_separated.pop() { } else if let Some(left) = space_separated.pop() {
devour_whitespace(iter); devour_whitespace(iter);
let right = single_value(iter, scope, super_selector, left.span)?; let right = single_value(iter, scope, super_selector, left.span)?;
@ -409,23 +372,30 @@ fn single_value<I: Iterator<Item = Token>>(
let val = single_value(iter, scope, super_selector, span)?; let val = single_value(iter, scope, super_selector, span)?;
Spanned { Spanned {
node: Value::Ident( node: Value::Ident(
InternedString::get_or_intern(format!( format!("/{}", val.node.to_css_string(val.span)?),
"/{}",
val.node.to_css_string(val.span)?
)),
QuoteKind::None, QuoteKind::None,
), ),
span: next.span.merge(val.span), span: next.span.merge(val.span),
} }
} }
Op::And => Spanned { Op::And => {
node: Value::Ident(InternedString::get_or_intern("and"), QuoteKind::None), Spanned {
span: next.span, node: Value::Ident(
}, "and".into(),
Op::Or => Spanned { QuoteKind::None,
node: Value::Ident(InternedString::get_or_intern("or"), QuoteKind::None), ),
span: next.span, span: next.span,
}, }
}
Op::Or => {
Spanned {
node: Value::Ident(
"or".into(),
QuoteKind::None,
),
span: next.span,
}
}
_ => { _ => {
return Err(("Expected expression.", next.span).into()); return Err(("Expected expression.", next.span).into());
} }
@ -599,20 +569,15 @@ impl Value {
) -> SassResult<Spanned<IntermediateValue>> { ) -> SassResult<Spanned<IntermediateValue>> {
let Spanned { node: mut s, span } = eat_ident(toks, scope, super_selector, span_before)?; let Spanned { node: mut s, span } = eat_ident(toks, scope, super_selector, span_before)?;
let lower = dbg!(InternedString::get_or_intern(s.to_ascii_lowercase())); let lower = s.to_ascii_lowercase();
if lower.resolve_ref() == "progid" if lower == "progid" && toks.peek().is_some() && toks.peek().unwrap().kind == ':' {
&& toks.peek().is_some() s = lower;
&& toks.peek().unwrap().kind == ':'
{
s = "progid:".to_string();
toks.next(); toks.next();
s.push(':');
s.push_str(&eat_progid(toks, scope, super_selector)?); s.push_str(&eat_progid(toks, scope, super_selector)?);
return Ok(Spanned { return Ok(Spanned {
node: IntermediateValue::Value(Value::Ident( node: IntermediateValue::Value(Value::Ident(s, QuoteKind::None)),
InternedString::get_or_intern(s),
QuoteKind::None,
)),
span, span,
}); });
} }
@ -634,9 +599,9 @@ impl Value {
.span(span)) .span(span))
} }
None => { None => {
match lower.resolve_ref() { match lower.as_str() {
"calc" | "element" | "expression" => { "calc" | "element" | "expression" => {
s = lower.resolve().to_string(); s = lower;
eat_calc_args(toks, scope, super_selector, &mut s)?; eat_calc_args(toks, scope, super_selector, &mut s)?;
} }
// "min" => {} // "min" => {}
@ -651,11 +616,9 @@ impl Value {
&eat_call_args(toks)?.to_css_string(scope, super_selector)?, &eat_call_args(toks)?.to_css_string(scope, super_selector)?,
), ),
} }
return Ok(IntermediateValue::Value(Value::Ident( return Ok(
InternedString::get_or_intern(s), IntermediateValue::Value(Value::Ident(s, QuoteKind::None)).span(span)
QuoteKind::None, );
))
.span(span));
} }
}, },
}; };
@ -667,24 +630,21 @@ impl Value {
.span(span)); .span(span));
} }
if let Some(c) = NAMED_COLORS.get_by_name(lower) { if let Some(c) = NAMED_COLORS.get_by_name(&lower.as_str()) {
return Ok(IntermediateValue::Value(Value::Color(Box::new(Color::new( return Ok(IntermediateValue::Value(Value::Color(Box::new(Color::new(
c[0], c[1], c[2], c[3], s, c[0], c[1], c[2], c[3], s,
)))) ))))
.span(span)); .span(span));
} }
Ok(match dbg!(lower.resolve_ref()) { Ok(match lower.as_str() {
"true" => IntermediateValue::Value(Value::True), "true" => IntermediateValue::Value(Value::True),
"false" => IntermediateValue::Value(Value::False), "false" => IntermediateValue::Value(Value::False),
"null" => IntermediateValue::Value(Value::Null), "null" => IntermediateValue::Value(Value::Null),
"not" => IntermediateValue::Op(Op::Not), "not" => IntermediateValue::Op(Op::Not),
"and" => IntermediateValue::Op(Op::And), "and" => IntermediateValue::Op(Op::And),
"or" => IntermediateValue::Op(Op::Or), "or" => IntermediateValue::Op(Op::Or),
_ => IntermediateValue::Value(Value::Ident( _ => IntermediateValue::Value(Value::Ident(s, QuoteKind::None)),
InternedString::get_or_intern(s),
QuoteKind::None,
)),
} }
.span(span)) .span(span))
} }

View File

@ -14,7 +14,6 @@ use std::fmt;
use crate::args::CallArgs; use crate::args::CallArgs;
use crate::atrule::Function; use crate::atrule::Function;
use crate::builtin::Builtin; use crate::builtin::Builtin;
use crate::common::Identifier;
use crate::error::SassResult; use crate::error::SassResult;
use crate::scope::Scope; use crate::scope::Scope;
use crate::selector::Selector; use crate::selector::Selector;
@ -28,15 +27,15 @@ use crate::value::Value;
/// for use in the builtin function `inspect()` /// for use in the builtin function `inspect()`
#[derive(Clone)] #[derive(Clone)]
pub(crate) enum SassFunction { pub(crate) enum SassFunction {
Builtin(Builtin, Identifier), Builtin(Builtin, String),
UserDefined(Box<Function>, Identifier), UserDefined(Box<Function>, String),
} }
impl SassFunction { impl SassFunction {
/// Get the name of the function referenced /// Get the name of the function referenced
/// ///
/// Used mainly in debugging and `inspect()` /// Used mainly in debugging and `inspect()`
pub fn name(&self) -> &Identifier { pub fn name(&self) -> &str {
match self { match self {
Self::Builtin(_, name) => name, Self::Builtin(_, name) => name,
Self::UserDefined(_, name) => name, Self::UserDefined(_, name) => name,