Use remove() rather than .get() to avoid a clone
This commit is contained in:
parent
a44e52c7e3
commit
23b90aa97e
@ -37,6 +37,10 @@ impl CallArgs {
|
|||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.0.len()
|
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>>(
|
pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
|
||||||
|
@ -8,15 +8,15 @@ use crate::value::{Number, Value};
|
|||||||
|
|
||||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||||
decl!(f "hsl", |args, _| {
|
decl!(f "hsl", |args, _| {
|
||||||
let hue = match arg!(args, 0, "hue").eval() {
|
let hue = match arg!(args, 0, "hue") {
|
||||||
Value::Dimension(n, _) => n,
|
Value::Dimension(n, _) => n,
|
||||||
v => return Err(format!("$hue: {} is not a number.", v).into()),
|
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),
|
Value::Dimension(n, _) => n / Number::from(100),
|
||||||
v => return Err(format!("$saturation: {} is not a number.", v).into()),
|
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),
|
Value::Dimension(n, _) => n / Number::from(100),
|
||||||
v => return Err(format!("$luminance: {} is not a number.", v).into()),
|
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)))
|
Ok(Value::Color(Color::from_hsla(hue, saturation, luminance, alpha)))
|
||||||
});
|
});
|
||||||
decl!(f "hsla", |args, _| {
|
decl!(f "hsla", |args, _| {
|
||||||
let hue = match arg!(args, 0, "hue").eval() {
|
let hue = match arg!(args, 0, "hue") {
|
||||||
Value::Dimension(n, _) => n,
|
Value::Dimension(n, _) => n,
|
||||||
v => return Err(format!("$hue: {} is not a number.", v).into()),
|
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),
|
Value::Dimension(n, _) => n / Number::from(100),
|
||||||
v => return Err(format!("$saturation: {} is not a number.", v).into()),
|
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),
|
Value::Dimension(n, _) => n / Number::from(100),
|
||||||
v => return Err(format!("$luminance: {} is not a number.", v).into()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
|
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, _| {
|
decl!(f "adjust-hue", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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,
|
Value::Dimension(n, _) => n,
|
||||||
v => return Err(format!("$degrees: {} is not a number.", v).into()),
|
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, _| {
|
decl!(f "lighten", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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),
|
Value::Dimension(n, u) => bound!("amount", n, u, 0, 100) / Number::from(100),
|
||||||
v => return Err(format!("$amount: {} is not a number.", v).into())
|
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, _| {
|
decl!(f "darken", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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),
|
Value::Dimension(n, u) => bound!("amount", n, u, 0, 100) / Number::from(100),
|
||||||
v => return Err(format!("$amount: {} is not a number.", v).into())
|
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, _| {
|
decl!(f "saturate", |args, _| {
|
||||||
max_args!(args, 2);
|
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),
|
Value::Dimension(n, u) => bound!("amount", n, u, 0, 100) / Number::from(100),
|
||||||
v => return Err(format!("$amount: {} is not a number.", v).into())
|
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::Color(c) => c,
|
||||||
Value::Dimension(n, u) => return Ok(Value::Ident(format!("saturate({}{})", n, u), QuoteKind::None)),
|
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()),
|
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, _| {
|
decl!(f "desaturate", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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),
|
Value::Dimension(n, u) => bound!("amount", n, u, 0, 100) / Number::from(100),
|
||||||
v => return Err(format!("$amount: {} is not a number.", v).into())
|
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, _| {
|
decl!(f "grayscale", |args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
Value::Dimension(n, u) => return Ok(Value::Ident(format!("grayscale({}{})", n, u), QuoteKind::None)),
|
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()),
|
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, _| {
|
decl!(f "complement", |args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
v => return Err(format!("$color: {} is not a color.", v).into()),
|
||||||
};
|
};
|
||||||
|
@ -24,11 +24,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
});
|
});
|
||||||
decl!(f "opacify", |args, _| {
|
decl!(f "opacify", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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),
|
Value::Dimension(n, u) => bound!("amount", n, u, 0, 1),
|
||||||
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
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, _| {
|
decl!(f "fade-in", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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),
|
Value::Dimension(n, u) => bound!("amount", n, u, 0, 1),
|
||||||
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
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, _| {
|
decl!(f "transparentize", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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),
|
Value::Dimension(n, u) => bound!("amount", n, u, 0, 1),
|
||||||
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
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, _| {
|
decl!(f "fade-out", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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),
|
Value::Dimension(n, u) => bound!("amount", n, u, 0, 1),
|
||||||
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ use crate::value::{Number, Value};
|
|||||||
|
|
||||||
macro_rules! opt_arg {
|
macro_rules! opt_arg {
|
||||||
($args:ident, $name:ident, $arg:literal) => {
|
($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::None) => Some(n),
|
||||||
Value::Dimension(n, Unit::Percent) => Some(n / Number::from(100)),
|
Value::Dimension(n, Unit::Percent) => Some(n / Number::from(100)),
|
||||||
Value::Null => None,
|
Value::Null => None,
|
||||||
@ -16,7 +16,7 @@ macro_rules! opt_arg {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
(hsl: $args:ident, $name:ident, $arg:literal) => {
|
(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) => {
|
Value::Dimension(n, Unit::None) | Value::Dimension(n, Unit::Percent) => {
|
||||||
Some(n / Number::from(100))
|
Some(n / Number::from(100))
|
||||||
}
|
}
|
||||||
@ -28,7 +28,11 @@ macro_rules! opt_arg {
|
|||||||
|
|
||||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||||
decl!(f "change-color", |args, _| {
|
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,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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()))))
|
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::None)
|
||||||
| Value::Dimension(n, Unit::Percent)
|
| Value::Dimension(n, Unit::Percent)
|
||||||
| Value::Dimension(n, Unit::Deg) => Some(n),
|
| 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, _| {
|
decl!(f "adjust-color", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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::None)
|
||||||
| Value::Dimension(n, Unit::Percent)
|
| Value::Dimension(n, Unit::Percent)
|
||||||
| Value::Dimension(n, Unit::Deg) => Some(n),
|
| 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, _| {
|
decl!(f "scale-color", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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::None)
|
||||||
| Value::Dimension(n, Unit::Percent)
|
| Value::Dimension(n, Unit::Percent)
|
||||||
| Value::Dimension(n, Unit::Deg) => Some(n),
|
| 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, _| {
|
decl!(f "ie-hex-str", |args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
v => return Err(format!("$color: {} is not a color.", v).into()),
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ use crate::value::{Number, Value};
|
|||||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||||
decl!(f "rgb", |args, _| {
|
decl!(f "rgb", |args, _| {
|
||||||
if args.len() == 1 {
|
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,
|
Value::List(v, _) => v,
|
||||||
_ => return Err("Missing element $green.".into())
|
_ => return Err("Missing element $green.".into())
|
||||||
};
|
};
|
||||||
@ -41,11 +41,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Ok(Value::Color(color))
|
Ok(Value::Color(color))
|
||||||
|
|
||||||
} else if args.len() == 2 {
|
} else if args.len() == 2 {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
|
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)))
|
Ok(Value::Color(color.with_alpha(alpha)))
|
||||||
} else {
|
} 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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
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 @ 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()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
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 @ 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()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
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 @ 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()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
|
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, _| {
|
decl!(f "rgba", |args, _| {
|
||||||
if args.len() == 1 {
|
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,
|
Value::List(v, _) => v,
|
||||||
_ => return Err("Missing element $green.".into())
|
_ => return Err("Missing element $green.".into())
|
||||||
};
|
};
|
||||||
@ -115,11 +115,11 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Ok(Value::Color(color))
|
Ok(Value::Color(color))
|
||||||
|
|
||||||
} else if args.len() == 2 {
|
} else if args.len() == 2 {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color: {} is not a color.", v).into()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
|
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)))
|
Ok(Value::Color(color.with_alpha(alpha)))
|
||||||
} else {
|
} 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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
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 @ 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()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
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 @ 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()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
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 @ 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()),
|
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::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
v @ Value::Dimension(..) => return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()),
|
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, _| {
|
decl!(f "mix", |args, _| {
|
||||||
max_args!(args, 3);
|
max_args!(args, 3);
|
||||||
let color1 = match arg!(args, 0, "color1").eval() {
|
let color1 = match arg!(args, 0, "color1") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color1: {} is not a color.", v).into()),
|
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,
|
Value::Color(c) => c,
|
||||||
v => return Err(format!("$color2: {} is not a color.", v).into()),
|
v => return Err(format!("$color2: {} is not a color.", v).into()),
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@ use crate::value::{Number, Value};
|
|||||||
|
|
||||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||||
decl!(f "length", |args, _| {
|
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()),
|
Value::List(v, _) => Number::from(v.len()),
|
||||||
_ => Number::from(1)
|
_ => Number::from(1)
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
macro_rules! arg {
|
macro_rules! arg {
|
||||||
($args:ident, $idx:literal, $name:literal) => {
|
($args:ident, $idx:literal, $name:literal) => {
|
||||||
match $args.get(stringify!($idx)) {
|
match $args.remove(stringify!($idx)) {
|
||||||
Some(v) => v,
|
Some(v) => v.eval(),
|
||||||
None => match $args.get($name) {
|
None => match $args.remove($name) {
|
||||||
Some(v) => v,
|
Some(v) => v.eval(),
|
||||||
None => return Err(concat!("Missing argument $", $name, ".").into()),
|
None => return Err(concat!("Missing argument $", $name, ".").into()),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@ use crate::value::{Number, Value};
|
|||||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||||
decl!(f "percentage", |args, _| {
|
decl!(f "percentage", |args, _| {
|
||||||
max_args!(args, 1);
|
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),
|
Value::Dimension(n, Unit::None) => n * Number::from(100),
|
||||||
v @ Value::Dimension(..) => return Err(format!("$number: Expected {} to have no units.", v).into()),
|
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()),
|
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, _| {
|
decl!(f "round", |args, _| {
|
||||||
max_args!(args, 1);
|
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)),
|
Value::Dimension(n, u) => Ok(Value::Dimension(n.round(), u)),
|
||||||
v => return Err(format!("$number: {} is not a number.", v).into()),
|
v => return Err(format!("$number: {} is not a number.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "ceil", |args, _| {
|
decl!(f "ceil", |args, _| {
|
||||||
max_args!(args, 1);
|
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)),
|
Value::Dimension(n, u) => Ok(Value::Dimension(n.ceil(), u)),
|
||||||
v => return Err(format!("$number: {} is not a number.", v).into()),
|
v => return Err(format!("$number: {} is not a number.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "floor", |args, _| {
|
decl!(f "floor", |args, _| {
|
||||||
max_args!(args, 1);
|
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)),
|
Value::Dimension(n, u) => Ok(Value::Dimension(n.floor(), u)),
|
||||||
v => return Err(format!("$number: {} is not a number.", v).into()),
|
v => return Err(format!("$number: {} is not a number.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "abs", |args, _| {
|
decl!(f "abs", |args, _| {
|
||||||
max_args!(args, 1);
|
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)),
|
Value::Dimension(n, u) => Ok(Value::Dimension(n.abs(), u)),
|
||||||
v => return Err(format!("$number: {} is not a number.", v).into()),
|
v => return Err(format!("$number: {} is not a number.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "comparable", |args, _| {
|
decl!(f "comparable", |args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let unit1 = match arg!(args, 0, "number1").eval() {
|
let unit1 = match arg!(args, 0, "number1") {
|
||||||
Value::Dimension(_, u) => u,
|
Value::Dimension(_, u) => u,
|
||||||
v => return Err(format!("$number1: {} is not a number.", v).into()),
|
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,
|
Value::Dimension(_, u) => u,
|
||||||
v => return Err(format!("$number2: {} is not a number.", v).into()),
|
v => return Err(format!("$number2: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
|
@ -9,14 +9,14 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
decl!(f "if", |args, _| {
|
decl!(f "if", |args, _| {
|
||||||
max_args!(args, 3);
|
max_args!(args, 3);
|
||||||
if arg!(args, 0, "condition").is_true() {
|
if arg!(args, 0, "condition").is_true() {
|
||||||
Ok(arg!(args, 1, "if-true").eval())
|
Ok(arg!(args, 1, "if-true"))
|
||||||
} else {
|
} else {
|
||||||
Ok(arg!(args, 2, "if-false").eval())
|
Ok(arg!(args, 2, "if-false"))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "feature-exists", |args, _| {
|
decl!(f "feature-exists", |args, _| {
|
||||||
max_args!(args, 1);
|
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
|
// A local variable will shadow a global variable unless
|
||||||
// `!global` is used.
|
// `!global` is used.
|
||||||
"global-variable-shadowing" => Ok(Value::False),
|
"global-variable-shadowing" => Ok(Value::False),
|
||||||
@ -45,7 +45,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
});
|
});
|
||||||
decl!(f "type-of", |args, _| {
|
decl!(f "type-of", |args, _| {
|
||||||
max_args!(args, 1);
|
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))
|
Ok(Value::Ident(value.kind().to_owned(), QuoteKind::None))
|
||||||
});
|
});
|
||||||
decl!(f "unitless", |args, _| {
|
decl!(f "unitless", |args, _| {
|
||||||
@ -74,7 +74,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
decl!(f "function-exists", |args, scope| {
|
decl!(f "function-exists", |args, scope| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let value = arg!(args, 0, "name");
|
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)))
|
Ok(Value::bool(scope.fn_exists(&s) || GLOBAL_FUNCTIONS.contains_key(&s)))
|
||||||
});
|
});
|
||||||
decl!(f "call", |_args, _scope| {
|
decl!(f "call", |_args, _scope| {
|
||||||
|
@ -17,7 +17,7 @@ mod meta;
|
|||||||
mod selector;
|
mod selector;
|
||||||
mod string;
|
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! {
|
lazy_static! {
|
||||||
pub(crate) static ref GLOBAL_FUNCTIONS: BTreeMap<String, Builtin> = {
|
pub(crate) static ref GLOBAL_FUNCTIONS: BTreeMap<String, Builtin> = {
|
||||||
|
@ -12,39 +12,35 @@ use crate::value::{Number, Value};
|
|||||||
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
||||||
decl!(f "to-upper-case", |args, _| {
|
decl!(f "to-upper-case", |args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let s: &Value = arg!(args, 0, "string");
|
match arg!(args, 0, "string") {
|
||||||
match s.eval() {
|
|
||||||
Value::Ident(i, q) => Ok(Value::Ident(i.to_ascii_uppercase(), q)),
|
Value::Ident(i, q) => Ok(Value::Ident(i.to_ascii_uppercase(), q)),
|
||||||
v => Err(format!("$string: {} is not a string.", v).into()),
|
v => Err(format!("$string: {} is not a string.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "to-lower-case", |args, _| {
|
decl!(f "to-lower-case", |args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let s: &Value = arg!(args, 0, "string");
|
match arg!(args, 0, "string") {
|
||||||
match s.eval() {
|
|
||||||
Value::Ident(i, q) => Ok(Value::Ident(i.to_ascii_lowercase(), q)),
|
Value::Ident(i, q) => Ok(Value::Ident(i.to_ascii_lowercase(), q)),
|
||||||
v => Err(format!("$string: {} is not a string.", v).into()),
|
v => Err(format!("$string: {} is not a string.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "str-length", |args, _| {
|
decl!(f "str-length", |args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let s: &Value = arg!(args, 0, "string");
|
match arg!(args, 0, "string") {
|
||||||
match s.eval() {
|
|
||||||
Value::Ident(i, _) => Ok(Value::Dimension(Number::from(i.len()), Unit::None)),
|
Value::Ident(i, _) => Ok(Value::Dimension(Number::from(i.len()), Unit::None)),
|
||||||
v => Err(format!("$string: {} is not a string.", v).into()),
|
v => Err(format!("$string: {} is not a string.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "quote", |args, _| {
|
decl!(f "quote", |args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let s = arg!(args, 0, "string").eval();
|
match arg!(args, 0, "string") {
|
||||||
match s {
|
|
||||||
Value::Ident(i, _) => Ok(Value::Ident(i, QuoteKind::Double)),
|
Value::Ident(i, _) => Ok(Value::Ident(i, QuoteKind::Double)),
|
||||||
v => Err(format!("$string: {} is not a string.", v).into()),
|
v => Err(format!("$string: {} is not a string.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "unquote", |args, _| {
|
decl!(f "unquote", |args, _| {
|
||||||
max_args!(args, 1);
|
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),
|
Value::Ident(i, _) if i.is_empty() => Ok(Value::Null),
|
||||||
i @ Value::Ident(..) => Ok(i.unquote()),
|
i @ Value::Ident(..) => Ok(i.unquote()),
|
||||||
v => Err(format!("$string: {} is not a string.", v).into()),
|
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, _| {
|
decl!(f "str-slice", |args, _| {
|
||||||
max_args!(args, 3);
|
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),
|
Value::Ident(s, q) => (s, q),
|
||||||
v => return Err(format!("$string: {} is not a string.", v).into()),
|
v => return Err(format!("$string: {} is not a string.", v).into()),
|
||||||
};
|
};
|
||||||
let str_len = string.len();
|
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.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.to_integer().is_positive() => n.to_integer().to_usize().unwrap(),
|
||||||
Value::Dimension(n, Unit::None) if n == Number::from(0) => 1_usize,
|
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 @ 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()),
|
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.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.to_integer().is_positive() => n.to_integer().to_usize().unwrap(),
|
||||||
Value::Dimension(n, Unit::None) if n == Number::from(0) => 0_usize,
|
Value::Dimension(n, Unit::None) if n == Number::from(0) => 0_usize,
|
||||||
|
@ -223,7 +223,7 @@ impl Value {
|
|||||||
let func = match scope.get_fn(&s) {
|
let func = match scope.get_fn(&s) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(_) => match GLOBAL_FUNCTIONS.get(&s) {
|
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 => {
|
None => {
|
||||||
s.push('(');
|
s.push('(');
|
||||||
let mut unclosed_parens = 0;
|
let mut unclosed_parens = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user