Use remove() rather than .get() to avoid a clone

This commit is contained in:
ConnorSkees 2020-02-16 22:04:54 -05:00
parent a44e52c7e3
commit 23b90aa97e
12 changed files with 87 additions and 83 deletions

View File

@ -37,6 +37,10 @@ impl CallArgs {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn remove(&mut self, s: &str) -> Option<Value> {
self.0.remove(s)
}
}
pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(

View File

@ -8,15 +8,15 @@ use crate::value::{Number, Value};
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "hsl", |args, _| {
let hue = match arg!(args, 0, "hue").eval() {
let hue = match arg!(args, 0, "hue") {
Value::Dimension(n, _) => n,
v => return Err(format!("$hue: {} is not a number.", v).into()),
};
let saturation = match arg!(args, 1, "saturation").eval() {
let saturation = match arg!(args, 1, "saturation") {
Value::Dimension(n, _) => n / Number::from(100),
v => return Err(format!("$saturation: {} is not a number.", v).into()),
};
let luminance = match arg!(args, 2, "luminance").eval() {
let luminance = match arg!(args, 2, "luminance") {
Value::Dimension(n, _) => n / Number::from(100),
v => return Err(format!("$luminance: {} is not a number.", v).into()),
};
@ -29,19 +29,19 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
Ok(Value::Color(Color::from_hsla(hue, saturation, luminance, alpha)))
});
decl!(f "hsla", |args, _| {
let hue = match arg!(args, 0, "hue").eval() {
let hue = match arg!(args, 0, "hue") {
Value::Dimension(n, _) => n,
v => return Err(format!("$hue: {} is not a number.", v).into()),
};
let saturation = match arg!(args, 1, "saturation").eval() {
let saturation = match arg!(args, 1, "saturation") {
Value::Dimension(n, _) => n / Number::from(100),
v => return Err(format!("$saturation: {} is not a number.", v).into()),
};
let luminance = match arg!(args, 2, "luminance").eval() {
let luminance = match arg!(args, 2, "luminance") {
Value::Dimension(n, _) => n / Number::from(100),
v => return Err(format!("$luminance: {} is not a number.", v).into()),
};
let alpha = match arg!(args, 3, "alpha").eval() {
let alpha = match arg!(args, 3, "alpha") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
@ -72,11 +72,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "adjust-hue", |args, _| {
max_args!(args, 2);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let degrees = match arg!(args, 1, "degrees").eval() {
let degrees = match arg!(args, 1, "degrees") {
Value::Dimension(n, _) => n,
v => return Err(format!("$degrees: {} is not a number.", v).into()),
};
@ -84,11 +84,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "lighten", |args, _| {
max_args!(args, 2);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let amount = match arg!(args, 1, "amount").eval() {
let amount = match arg!(args, 1, "amount") {
Value::Dimension(n, u) => bound!("amount", n, u, 0, 100) / Number::from(100),
v => return Err(format!("$amount: {} is not a number.", v).into())
};
@ -96,11 +96,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "darken", |args, _| {
max_args!(args, 2);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let amount = match arg!(args, 1, "amount").eval() {
let amount = match arg!(args, 1, "amount") {
Value::Dimension(n, u) => bound!("amount", n, u, 0, 100) / Number::from(100),
v => return Err(format!("$amount: {} is not a number.", v).into())
};
@ -108,11 +108,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "saturate", |args, _| {
max_args!(args, 2);
let amount = match arg!(args, 1, "amount").eval() {
let amount = match arg!(args, 1, "amount") {
Value::Dimension(n, u) => bound!("amount", n, u, 0, 100) / Number::from(100),
v => return Err(format!("$amount: {} is not a number.", v).into())
};
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
Value::Dimension(n, u) => return Ok(Value::Ident(format!("saturate({}{})", n, u), QuoteKind::None)),
v => return Err(format!("$color: {} is not a color.", v).into()),
@ -121,11 +121,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "desaturate", |args, _| {
max_args!(args, 2);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let amount = match arg!(args, 1, "amount").eval() {
let amount = match arg!(args, 1, "amount") {
Value::Dimension(n, u) => bound!("amount", n, u, 0, 100) / Number::from(100),
v => return Err(format!("$amount: {} is not a number.", v).into())
};
@ -133,7 +133,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "grayscale", |args, _| {
max_args!(args, 1);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
Value::Dimension(n, u) => return Ok(Value::Ident(format!("grayscale({}{})", n, u), QuoteKind::None)),
v => return Err(format!("$color: {} is not a color.", v).into()),
@ -142,7 +142,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "complement", |args, _| {
max_args!(args, 1);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};

View File

@ -24,11 +24,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "opacify", |args, _| {
max_args!(args, 2);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let amount = match arg!(args, 1, "amount").eval() {
let amount = match arg!(args, 1, "amount") {
Value::Dimension(n, u) => bound!("amount", n, u, 0, 1),
v => return Err(format!("$amount: {} is not a number.", v).into()),
};
@ -36,11 +36,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "fade-in", |args, _| {
max_args!(args, 2);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let amount = match arg!(args, 1, "amount").eval() {
let amount = match arg!(args, 1, "amount") {
Value::Dimension(n, u) => bound!("amount", n, u, 0, 1),
v => return Err(format!("$amount: {} is not a number.", v).into()),
};
@ -48,11 +48,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "transparentize", |args, _| {
max_args!(args, 2);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let amount = match arg!(args, 1, "amount").eval() {
let amount = match arg!(args, 1, "amount") {
Value::Dimension(n, u) => bound!("amount", n, u, 0, 1),
v => return Err(format!("$amount: {} is not a number.", v).into()),
};
@ -60,11 +60,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "fade-out", |args, _| {
max_args!(args, 2);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let amount = match arg!(args, 1, "amount").eval() {
let amount = match arg!(args, 1, "amount") {
Value::Dimension(n, u) => bound!("amount", n, u, 0, 1),
v => return Err(format!("$amount: {} is not a number.", v).into()),
};

View File

@ -8,7 +8,7 @@ use crate::value::{Number, Value};
macro_rules! opt_arg {
($args:ident, $name:ident, $arg:literal) => {
let $name = match arg!($args, -1, $arg = Value::Null).eval() {
let $name = match arg!($args, -1, $arg = Value::Null) {
Value::Dimension(n, Unit::None) => Some(n),
Value::Dimension(n, Unit::Percent) => Some(n / Number::from(100)),
Value::Null => None,
@ -16,7 +16,7 @@ macro_rules! opt_arg {
};
};
(hsl: $args:ident, $name:ident, $arg:literal) => {
let $name = match arg!($args, -1, $arg = Value::Null).eval() {
let $name = match arg!($args, -1, $arg = Value::Null) {
Value::Dimension(n, Unit::None) | Value::Dimension(n, Unit::Percent) => {
Some(n / Number::from(100))
}
@ -28,7 +28,11 @@ macro_rules! opt_arg {
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "change-color", |args, _| {
let color = match arg!(args, 0, "color").eval() {
if args.get("1").is_some() {
return Err("Only one positional argument is allowed. All other arguments must be passed by name.".into());
}
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
@ -42,7 +46,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
return Ok(Value::Color(Color::from_rgba(red.unwrap_or(color.red()), green.unwrap_or(color.green()), blue.unwrap_or(color.blue()), alpha.unwrap_or(color.alpha()))))
}
let hue = match arg!(args, -1, "hue"=Value::Null).eval() {
let hue = match arg!(args, -1, "hue"=Value::Null) {
Value::Dimension(n, Unit::None)
| Value::Dimension(n, Unit::Percent)
| Value::Dimension(n, Unit::Deg) => Some(n),
@ -66,7 +70,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
}))
});
decl!(f "adjust-color", |args, _| {
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
@ -88,7 +92,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
))
}
let hue = match arg!(args, -1, "hue"=Value::Null).eval() {
let hue = match arg!(args, -1, "hue"=Value::Null) {
Value::Dimension(n, Unit::None)
| Value::Dimension(n, Unit::Percent)
| Value::Dimension(n, Unit::Deg) => Some(n),
@ -120,7 +124,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
}))
});
decl!(f "scale-color", |args, _| {
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
@ -142,7 +146,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
))
}
let hue = match arg!(args, -1, "hue"=Value::Null).eval() {
let hue = match arg!(args, -1, "hue"=Value::Null) {
Value::Dimension(n, Unit::None)
| Value::Dimension(n, Unit::Percent)
| Value::Dimension(n, Unit::Deg) => Some(n),
@ -175,7 +179,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "ie-hex-str", |args, _| {
max_args!(args, 1);
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};

View File

@ -8,7 +8,7 @@ use crate::value::{Number, Value};
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "rgb", |args, _| {
if args.len() == 1 {
let mut channels = match arg!(args, 0, "channels").eval() {
let mut channels = match arg!(args, 0, "channels") {
Value::List(v, _) => v,
_ => return Err("Missing element $green.".into())
};
@ -41,11 +41,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
Ok(Value::Color(color))
} else if args.len() == 2 {
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let alpha = match arg!(args, 1, "alpha").eval() {
let alpha = match arg!(args, 1, "alpha") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
@ -53,25 +53,25 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
};
Ok(Value::Color(color.with_alpha(alpha)))
} else {
let red = match arg!(args, 0, "red").eval() {
let red = match arg!(args, 0, "red") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => return Err(format!("$red: Expected {} to have no units or \"%\".", v).into()),
v => return Err(format!("$red: {} is not a number.", v).into()),
};
let green = match arg!(args, 1, "green").eval() {
let green = match arg!(args, 1, "green") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => return Err(format!("$green: Expected {} to have no units or \"%\".", v).into()),
v => return Err(format!("$green: {} is not a number.", v).into()),
};
let blue = match arg!(args, 2, "blue").eval() {
let blue = match arg!(args, 2, "blue") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => return Err(format!("$blue: Expected {} to have no units or \"%\".", v).into()),
v => return Err(format!("$blue: {} is not a number.", v).into()),
};
let alpha = match arg!(args, 3, "alpha"=Value::Dimension(Number::from(1), Unit::None)).eval() {
let alpha = match arg!(args, 3, "alpha"=Value::Dimension(Number::from(1), Unit::None)) {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
@ -82,7 +82,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "rgba", |args, _| {
if args.len() == 1 {
let mut channels = match arg!(args, 0, "channels").eval() {
let mut channels = match arg!(args, 0, "channels") {
Value::List(v, _) => v,
_ => return Err("Missing element $green.".into())
};
@ -115,11 +115,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
Ok(Value::Color(color))
} else if args.len() == 2 {
let color = match arg!(args, 0, "color").eval() {
let color = match arg!(args, 0, "color") {
Value::Color(c) => c,
v => return Err(format!("$color: {} is not a color.", v).into()),
};
let alpha = match arg!(args, 1, "alpha").eval() {
let alpha = match arg!(args, 1, "alpha") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
@ -127,25 +127,25 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
};
Ok(Value::Color(color.with_alpha(alpha)))
} else {
let red = match arg!(args, 0, "red").eval() {
let red = match arg!(args, 0, "red") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => return Err(format!("$red: Expected {} to have no units or \"%\".", v).into()),
v => return Err(format!("$red: {} is not a number.", v).into()),
};
let green = match arg!(args, 1, "green").eval() {
let green = match arg!(args, 1, "green") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => return Err(format!("$green: Expected {} to have no units or \"%\".", v).into()),
v => return Err(format!("$green: {} is not a number.", v).into()),
};
let blue = match arg!(args, 2, "blue").eval() {
let blue = match arg!(args, 2, "blue") {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => return Err(format!("$blue: Expected {} to have no units or \"%\".", v).into()),
v => return Err(format!("$blue: {} is not a number.", v).into()),
};
let alpha = match arg!(args, 3, "alpha"=Value::Dimension(Number::from(1), Unit::None)).eval() {
let alpha = match arg!(args, 3, "alpha"=Value::Dimension(Number::from(1), Unit::None)) {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
@ -177,12 +177,12 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "mix", |args, _| {
max_args!(args, 3);
let color1 = match arg!(args, 0, "color1").eval() {
let color1 = match arg!(args, 0, "color1") {
Value::Color(c) => c,
v => return Err(format!("$color1: {} is not a color.", v).into()),
};
let color2 = match arg!(args, 1, "color2").eval() {
let color2 = match arg!(args, 1, "color2") {
Value::Color(c) => c,
v => return Err(format!("$color2: {} is not a color.", v).into()),
};

View File

@ -6,7 +6,7 @@ use crate::value::{Number, Value};
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "length", |args, _| {
let len = match arg!(args, 0, "list").eval() {
let len = match arg!(args, 0, "list") {
Value::List(v, _) => Number::from(v.len()),
_ => Number::from(1)
};

View File

@ -1,9 +1,9 @@
macro_rules! arg {
($args:ident, $idx:literal, $name:literal) => {
match $args.get(stringify!($idx)) {
Some(v) => v,
None => match $args.get($name) {
Some(v) => v,
match $args.remove(stringify!($idx)) {
Some(v) => v.eval(),
None => match $args.remove($name) {
Some(v) => v.eval(),
None => return Err(concat!("Missing argument $", $name, ".").into()),
},
};

View File

@ -7,7 +7,7 @@ use crate::value::{Number, Value};
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "percentage", |args, _| {
max_args!(args, 1);
let num = match arg!(args, 0, "number").eval() {
let num = match arg!(args, 0, "number") {
Value::Dimension(n, Unit::None) => n * Number::from(100),
v @ Value::Dimension(..) => return Err(format!("$number: Expected {} to have no units.", v).into()),
v => return Err(format!("$number: {} is not a number.", v).into()),
@ -16,39 +16,39 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "round", |args, _| {
max_args!(args, 1);
match arg!(args, 0, "number").eval() {
match arg!(args, 0, "number") {
Value::Dimension(n, u) => Ok(Value::Dimension(n.round(), u)),
v => return Err(format!("$number: {} is not a number.", v).into()),
}
});
decl!(f "ceil", |args, _| {
max_args!(args, 1);
match arg!(args, 0, "number").eval() {
match arg!(args, 0, "number") {
Value::Dimension(n, u) => Ok(Value::Dimension(n.ceil(), u)),
v => return Err(format!("$number: {} is not a number.", v).into()),
}
});
decl!(f "floor", |args, _| {
max_args!(args, 1);
match arg!(args, 0, "number").eval() {
match arg!(args, 0, "number") {
Value::Dimension(n, u) => Ok(Value::Dimension(n.floor(), u)),
v => return Err(format!("$number: {} is not a number.", v).into()),
}
});
decl!(f "abs", |args, _| {
max_args!(args, 1);
match arg!(args, 0, "number").eval() {
match arg!(args, 0, "number") {
Value::Dimension(n, u) => Ok(Value::Dimension(n.abs(), u)),
v => return Err(format!("$number: {} is not a number.", v).into()),
}
});
decl!(f "comparable", |args, _| {
max_args!(args, 2);
let unit1 = match arg!(args, 0, "number1").eval() {
let unit1 = match arg!(args, 0, "number1") {
Value::Dimension(_, u) => u,
v => return Err(format!("$number1: {} is not a number.", v).into()),
};
let unit2 = match arg!(args, 1, "number2").eval() {
let unit2 = match arg!(args, 1, "number2") {
Value::Dimension(_, u) => u,
v => return Err(format!("$number2: {} is not a number.", v).into()),
};

View File

@ -9,14 +9,14 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "if", |args, _| {
max_args!(args, 3);
if arg!(args, 0, "condition").is_true() {
Ok(arg!(args, 1, "if-true").eval())
Ok(arg!(args, 1, "if-true"))
} else {
Ok(arg!(args, 2, "if-false").eval())
Ok(arg!(args, 2, "if-false"))
}
});
decl!(f "feature-exists", |args, _| {
max_args!(args, 1);
match arg!(args, 0, "feature").eval().unquote().to_string().as_str() {
match arg!(args, 0, "feature").unquote().to_string().as_str() {
// A local variable will shadow a global variable unless
// `!global` is used.
"global-variable-shadowing" => Ok(Value::False),
@ -45,7 +45,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "type-of", |args, _| {
max_args!(args, 1);
let value = arg!(args, 0, "value").eval();
let value = arg!(args, 0, "value");
Ok(Value::Ident(value.kind().to_owned(), QuoteKind::None))
});
decl!(f "unitless", |args, _| {
@ -74,7 +74,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "function-exists", |args, scope| {
max_args!(args, 1);
let value = arg!(args, 0, "name");
let s = value.eval().unquote().to_string();
let s = value.unquote().to_string();
Ok(Value::bool(scope.fn_exists(&s) || GLOBAL_FUNCTIONS.contains_key(&s)))
});
decl!(f "call", |_args, _scope| {

View File

@ -17,7 +17,7 @@ mod meta;
mod selector;
mod string;
pub(crate) type Builtin = Box<dyn Fn(&CallArgs, &Scope) -> SassResult<Value> + Send + Sync>;
pub(crate) type Builtin = Box<dyn Fn(&mut CallArgs, &Scope) -> SassResult<Value> + Send + Sync>;
lazy_static! {
pub(crate) static ref GLOBAL_FUNCTIONS: BTreeMap<String, Builtin> = {

View File

@ -12,39 +12,35 @@ use crate::value::{Number, Value};
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
decl!(f "to-upper-case", |args, _| {
max_args!(args, 1);
let s: &Value = arg!(args, 0, "string");
match s.eval() {
match arg!(args, 0, "string") {
Value::Ident(i, q) => Ok(Value::Ident(i.to_ascii_uppercase(), q)),
v => Err(format!("$string: {} is not a string.", v).into()),
}
});
decl!(f "to-lower-case", |args, _| {
max_args!(args, 1);
let s: &Value = arg!(args, 0, "string");
match s.eval() {
match arg!(args, 0, "string") {
Value::Ident(i, q) => Ok(Value::Ident(i.to_ascii_lowercase(), q)),
v => Err(format!("$string: {} is not a string.", v).into()),
}
});
decl!(f "str-length", |args, _| {
max_args!(args, 1);
let s: &Value = arg!(args, 0, "string");
match s.eval() {
match arg!(args, 0, "string") {
Value::Ident(i, _) => Ok(Value::Dimension(Number::from(i.len()), Unit::None)),
v => Err(format!("$string: {} is not a string.", v).into()),
}
});
decl!(f "quote", |args, _| {
max_args!(args, 1);
let s = arg!(args, 0, "string").eval();
match s {
match arg!(args, 0, "string") {
Value::Ident(i, _) => Ok(Value::Ident(i, QuoteKind::Double)),
v => Err(format!("$string: {} is not a string.", v).into()),
}
});
decl!(f "unquote", |args, _| {
max_args!(args, 1);
match arg!(args, 0, "string").eval() {
match arg!(args, 0, "string") {
Value::Ident(i, _) if i.is_empty() => Ok(Value::Null),
i @ Value::Ident(..) => Ok(i.unquote()),
v => Err(format!("$string: {} is not a string.", v).into()),
@ -52,12 +48,12 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
});
decl!(f "str-slice", |args, _| {
max_args!(args, 3);
let (string, quotes) = match arg!(args, 0, "string").eval() {
let (string, quotes) = match arg!(args, 0, "string") {
Value::Ident(s, q) => (s, q),
v => return Err(format!("$string: {} is not a string.", v).into()),
};
let str_len = string.len();
let start = match arg!(args, 1, "start-at").eval() {
let start = match arg!(args, 1, "start-at") {
Value::Dimension(n, Unit::None) if n.is_decimal() => return Err(format!("{} is not an int.", n).into()),
Value::Dimension(n, Unit::None) if n.to_integer().is_positive() => n.to_integer().to_usize().unwrap(),
Value::Dimension(n, Unit::None) if n == Number::from(0) => 1_usize,
@ -66,7 +62,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
v @ Value::Dimension(..) => return Err(format!("$start: Expected {} to have no units.", v).into()),
v => return Err(format!("$start-at: {} is not a number.", v).into()),
};
let mut end = match arg!(args, 2, "end-at"=Value::Null).eval() {
let mut end = match arg!(args, 2, "end-at"=Value::Null) {
Value::Dimension(n, Unit::None) if n.is_decimal() => return Err(format!("{} is not an int.", n).into()),
Value::Dimension(n, Unit::None) if n.to_integer().is_positive() => n.to_integer().to_usize().unwrap(),
Value::Dimension(n, Unit::None) if n == Number::from(0) => 0_usize,

View File

@ -223,7 +223,7 @@ impl Value {
let func = match scope.get_fn(&s) {
Ok(f) => f,
Err(_) => match GLOBAL_FUNCTIONS.get(&s) {
Some(f) => return f(&eat_call_args(toks, scope)?, scope),
Some(f) => return f(&mut eat_call_args(toks, scope)?, scope),
None => {
s.push('(');
let mut unclosed_parens = 0;