Remove decl! macro
This lets rustfmt work and gives better autocomplete and error messages inside builtin functions.
This commit is contained in:
parent
d8db937470
commit
51585235c3
@ -7,7 +7,9 @@ use crate::units::Unit;
|
|||||||
use crate::value::{Number, Value};
|
use crate::value::{Number, Value};
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
decl!(f "hsl", |args, _| {
|
f.insert(
|
||||||
|
"hsl".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
let hue = match arg!(args, 0, "hue") {
|
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()),
|
||||||
@ -20,15 +22,26 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
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"=Value::Dimension(Number::from(1), Unit::None)) {
|
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())
|
||||||
|
}
|
||||||
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(Color::from_hsla(hue, saturation, luminance, alpha)))
|
Ok(Value::Color(Color::from_hsla(
|
||||||
});
|
hue, saturation, luminance, alpha,
|
||||||
decl!(f "hsla", |args, _| {
|
)))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
f.insert(
|
||||||
|
"hsla".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
let hue = match arg!(args, 0, "hue") {
|
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()),
|
||||||
@ -44,33 +57,49 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
let alpha = match arg!(args, 3, "alpha") {
|
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())
|
||||||
|
}
|
||||||
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(Color::from_hsla(hue, saturation, luminance, alpha)))
|
Ok(Value::Color(Color::from_hsla(
|
||||||
});
|
hue, saturation, luminance, alpha,
|
||||||
decl!(f "hue", |args, _| {
|
)))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
f.insert(
|
||||||
|
"hue".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Ok(Value::Dimension(c.hue(), Unit::Deg)),
|
Value::Color(c) => Ok(Value::Dimension(c.hue(), Unit::Deg)),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "saturation", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"saturation".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Ok(Value::Dimension(c.saturation(), Unit::Percent)),
|
Value::Color(c) => Ok(Value::Dimension(c.saturation(), Unit::Percent)),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "lightness", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"lightness".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Ok(Value::Dimension(c.lightness(), Unit::Percent)),
|
Value::Color(c) => Ok(Value::Dimension(c.lightness(), Unit::Percent)),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "adjust-hue", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"adjust-hue".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -81,8 +110,11 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
v => return Err(format!("$degrees: {} is not a number.", v).into()),
|
v => return Err(format!("$degrees: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.adjust_hue(degrees)))
|
Ok(Value::Color(color.adjust_hue(degrees)))
|
||||||
});
|
}),
|
||||||
decl!(f "lighten", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"lighten".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -90,11 +122,14 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
};
|
};
|
||||||
let amount = match arg!(args, 1, "amount") {
|
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()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.lighten(amount)))
|
Ok(Value::Color(color.lighten(amount)))
|
||||||
});
|
}),
|
||||||
decl!(f "darken", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"darken".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -102,24 +137,35 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
};
|
};
|
||||||
let amount = match arg!(args, 1, "amount") {
|
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()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.darken(amount)))
|
Ok(Value::Color(color.darken(amount)))
|
||||||
});
|
}),
|
||||||
decl!(f "saturate", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"saturate".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let amount = match arg!(args, 1, "amount") {
|
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") {
|
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()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.saturate(amount)))
|
Ok(Value::Color(color.saturate(amount)))
|
||||||
});
|
}),
|
||||||
decl!(f "desaturate", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"desaturate".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -127,38 +173,61 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
};
|
};
|
||||||
let amount = match arg!(args, 1, "amount") {
|
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()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.desaturate(amount)))
|
Ok(Value::Color(color.desaturate(amount)))
|
||||||
});
|
}),
|
||||||
decl!(f "grayscale", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"grayscale".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let color = match arg!(args, 0, "color") {
|
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()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.desaturate(Number::from(1))))
|
Ok(Value::Color(color.desaturate(Number::from(1))))
|
||||||
});
|
}),
|
||||||
decl!(f "complement", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"complement".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let color = match arg!(args, 0, "color") {
|
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()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.complement()))
|
Ok(Value::Color(color.complement()))
|
||||||
});
|
}),
|
||||||
decl!(f "invert", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"invert".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let weight = match arg!(args, 1, "weight"=Value::Dimension(Number::from(100), Unit::Percent)) {
|
let weight = match arg!(
|
||||||
|
args,
|
||||||
|
1,
|
||||||
|
"weight" = Value::Dimension(Number::from(100), Unit::Percent)
|
||||||
|
) {
|
||||||
Value::Dimension(n, u) => bound!("weight", n, u, 0, 100) / Number::from(100),
|
Value::Dimension(n, u) => bound!("weight", n, u, 0, 100) / Number::from(100),
|
||||||
v => return Err(format!("$weight: {} is not a number.", v).into()),
|
v => return Err(format!("$weight: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Ok(Value::Color(c.invert(weight))),
|
Value::Color(c) => Ok(Value::Color(c.invert(weight))),
|
||||||
Value::Dimension(n, Unit::Percent) => Ok(Value::Ident(format!("invert({}%)", n), QuoteKind::None)),
|
Value::Dimension(n, Unit::Percent) => {
|
||||||
Value::Dimension(..) => Err("Only one argument may be passed to the plain-CSS invert() function.".into()),
|
Ok(Value::Ident(format!("invert({}%)", n), QuoteKind::None))
|
||||||
|
}
|
||||||
|
Value::Dimension(..) => Err(
|
||||||
|
"Only one argument may be passed to the plain-CSS invert() function.".into(),
|
||||||
|
),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,22 +7,33 @@ use crate::value::Number;
|
|||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
decl!(f "alpha", |args, _| {
|
f.insert(
|
||||||
|
"alpha".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None)),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "opacity", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"opacity".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 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(format!("opacity({}{})", num , unit), QuoteKind::None)),
|
Value::Dimension(num, unit) => Ok(Value::Ident(
|
||||||
|
format!("opacity({}{})", num, unit),
|
||||||
|
QuoteKind::None,
|
||||||
|
)),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "opacify", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"opacify".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -33,8 +44,11 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.fade_in(amount)))
|
Ok(Value::Color(color.fade_in(amount)))
|
||||||
});
|
}),
|
||||||
decl!(f "fade-in", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"fade-in".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -45,8 +59,11 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.fade_in(amount)))
|
Ok(Value::Color(color.fade_in(amount)))
|
||||||
});
|
}),
|
||||||
decl!(f "transparentize", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"transparentize".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -57,8 +74,11 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.fade_out(amount)))
|
Ok(Value::Color(color.fade_out(amount)))
|
||||||
});
|
}),
|
||||||
decl!(f "fade-out", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"fade-out".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let color = match arg!(args, 0, "color") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -69,5 +89,6 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
v => return Err(format!("$amount: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.fade_out(amount)))
|
Ok(Value::Color(color.fade_out(amount)))
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ macro_rules! opt_arg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
decl!(f "change-color", |args, _| {
|
f.insert("change-color".to_owned(), Box::new(|args, _| {
|
||||||
if args.get("1").is_some() {
|
if args.get("1").is_some() {
|
||||||
return Err("Only one positional argument is allowed. All other arguments must be passed by name.".into());
|
return Err("Only one positional argument is allowed. All other arguments must be passed by name.".into());
|
||||||
}
|
}
|
||||||
@ -75,8 +75,10 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
} else {
|
} else {
|
||||||
color
|
color
|
||||||
}))
|
}))
|
||||||
});
|
}));
|
||||||
decl!(f "adjust-color", |args, _| {
|
f.insert(
|
||||||
|
"adjust-color".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
let color = match arg!(args, 0, "color") {
|
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,15 +90,12 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
opt_arg!(args, blue, "blue", -255, 255);
|
opt_arg!(args, blue, "blue", -255, 255);
|
||||||
|
|
||||||
if red.is_some() || green.is_some() || blue.is_some() {
|
if red.is_some() || green.is_some() || blue.is_some() {
|
||||||
return
|
return Ok(Value::Color(Color::from_rgba(
|
||||||
Ok(Value::Color(
|
|
||||||
Color::from_rgba(
|
|
||||||
color.red() + red.unwrap_or(Number::from(0)),
|
color.red() + red.unwrap_or(Number::from(0)),
|
||||||
color.green() + green.unwrap_or(Number::from(0)),
|
color.green() + green.unwrap_or(Number::from(0)),
|
||||||
color.blue() + blue.unwrap_or(Number::from(0)),
|
color.blue() + blue.unwrap_or(Number::from(0)),
|
||||||
color.alpha() + alpha.unwrap_or(Number::from(0))
|
color.alpha() + alpha.unwrap_or(Number::from(0)),
|
||||||
)
|
)));
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let hue = match arg!(args, -1, "hue" = Value::Null) {
|
let hue = match arg!(args, -1, "hue" = Value::Null) {
|
||||||
@ -113,14 +112,12 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
if hue.is_some() || saturation.is_some() || luminance.is_some() {
|
if hue.is_some() || saturation.is_some() || luminance.is_some() {
|
||||||
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
||||||
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
||||||
return Ok(Value::Color(
|
return Ok(Value::Color(Color::from_hsla(
|
||||||
Color::from_hsla(
|
|
||||||
this_hue + hue.unwrap_or(Number::from(0)),
|
this_hue + hue.unwrap_or(Number::from(0)),
|
||||||
this_saturation + saturation.unwrap_or(Number::from(0)),
|
this_saturation + saturation.unwrap_or(Number::from(0)),
|
||||||
this_luminance + luminance.unwrap_or(Number::from(0)),
|
this_luminance + luminance.unwrap_or(Number::from(0)),
|
||||||
this_alpha + alpha.unwrap_or(Number::from(0))
|
this_alpha + alpha.unwrap_or(Number::from(0)),
|
||||||
)
|
)));
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Color(if let Some(a) = alpha {
|
Ok(Value::Color(if let Some(a) = alpha {
|
||||||
@ -129,8 +126,11 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
} else {
|
} else {
|
||||||
color
|
color
|
||||||
}))
|
}))
|
||||||
});
|
}),
|
||||||
decl!(f "scale-color", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"scale-color".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
let color = match arg!(args, 0, "color") {
|
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,15 +142,28 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
opt_arg!(scale: args, blue, "blue", -100, 100);
|
opt_arg!(scale: args, blue, "blue", -100, 100);
|
||||||
|
|
||||||
if red.is_some() || green.is_some() || blue.is_some() {
|
if red.is_some() || green.is_some() || blue.is_some() {
|
||||||
return
|
return Ok(Value::Color(Color::from_rgba(
|
||||||
Ok(Value::Color(
|
scale(
|
||||||
Color::from_rgba(
|
color.red(),
|
||||||
scale(color.red(), red.unwrap_or(Number::from(0)), Number::from(255)),
|
red.unwrap_or(Number::from(0)),
|
||||||
scale(color.green(), green.unwrap_or(Number::from(0)), Number::from(255)),
|
Number::from(255),
|
||||||
scale(color.blue(), blue.unwrap_or(Number::from(0)), Number::from(255)),
|
),
|
||||||
scale(color.alpha(), alpha.unwrap_or(Number::from(0)), Number::from(1)),
|
scale(
|
||||||
)
|
color.green(),
|
||||||
))
|
green.unwrap_or(Number::from(0)),
|
||||||
|
Number::from(255),
|
||||||
|
),
|
||||||
|
scale(
|
||||||
|
color.blue(),
|
||||||
|
blue.unwrap_or(Number::from(0)),
|
||||||
|
Number::from(255),
|
||||||
|
),
|
||||||
|
scale(
|
||||||
|
color.alpha(),
|
||||||
|
alpha.unwrap_or(Number::from(0)),
|
||||||
|
Number::from(1),
|
||||||
|
),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let hue = match arg!(args, -1, "hue" = Value::Null) {
|
let hue = match arg!(args, -1, "hue" = Value::Null) {
|
||||||
@ -167,14 +180,24 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
if hue.is_some() || saturation.is_some() || luminance.is_some() {
|
if hue.is_some() || saturation.is_some() || luminance.is_some() {
|
||||||
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
||||||
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
||||||
return Ok(Value::Color(
|
return Ok(Value::Color(Color::from_hsla(
|
||||||
Color::from_hsla(
|
|
||||||
scale(this_hue, hue.unwrap_or(Number::from(0)), Number::from(360)),
|
scale(this_hue, hue.unwrap_or(Number::from(0)), Number::from(360)),
|
||||||
scale(this_saturation, saturation.unwrap_or(Number::from(0)), Number::from(1)),
|
scale(
|
||||||
scale(this_luminance, luminance.unwrap_or(Number::from(0)), Number::from(1)),
|
this_saturation,
|
||||||
scale(this_alpha, alpha.unwrap_or(Number::from(0)), Number::from(1)),
|
saturation.unwrap_or(Number::from(0)),
|
||||||
)
|
Number::from(1),
|
||||||
))
|
),
|
||||||
|
scale(
|
||||||
|
this_luminance,
|
||||||
|
luminance.unwrap_or(Number::from(0)),
|
||||||
|
Number::from(1),
|
||||||
|
),
|
||||||
|
scale(
|
||||||
|
this_alpha,
|
||||||
|
alpha.unwrap_or(Number::from(0)),
|
||||||
|
Number::from(1),
|
||||||
|
),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Color(if let Some(a) = alpha {
|
Ok(Value::Color(if let Some(a) = alpha {
|
||||||
@ -183,15 +206,19 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
} else {
|
} else {
|
||||||
color
|
color
|
||||||
}))
|
}))
|
||||||
});
|
}),
|
||||||
decl!(f "ie-hex-str", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"ie-hex-str".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let color = match arg!(args, 0, "color") {
|
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()),
|
||||||
};
|
};
|
||||||
Ok(Value::Ident(color.to_ie_hex_str(), QuoteKind::None))
|
Ok(Value::Ident(color.to_ie_hex_str(), QuoteKind::None))
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale(val: Number, by: Number, max: Number) -> Number {
|
fn scale(val: Number, by: Number, max: Number) -> Number {
|
||||||
|
@ -6,11 +6,13 @@ use crate::units::Unit;
|
|||||||
use crate::value::{Number, Value};
|
use crate::value::{Number, Value};
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
decl!(f "rgb", |args, _| {
|
f.insert(
|
||||||
|
"rgb".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let mut channels = match arg!(args, 0, "channels") {
|
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()),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(channels.len(), 3_usize);
|
assert_eq!(channels.len(), 3_usize);
|
||||||
@ -39,7 +41,6 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
let color = Color::from_rgba(red, green, blue, Number::from(1));
|
let color = Color::from_rgba(red, green, blue, Number::from(1));
|
||||||
|
|
||||||
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") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -48,43 +49,76 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
let alpha = match arg!(args, 1, "alpha") {
|
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()
|
||||||
|
)
|
||||||
|
}
|
||||||
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.with_alpha(alpha)))
|
Ok(Value::Color(color.with_alpha(alpha)))
|
||||||
} else {
|
} else {
|
||||||
let red = match arg!(args, 0, "red") {
|
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) => {
|
||||||
v @ Value::Dimension(..) => return Err(format!("$red: Expected {} to have no units or \"%\".", v).into()),
|
(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()),
|
v => return Err(format!("$red: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
let green = match arg!(args, 1, "green") {
|
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) => {
|
||||||
v @ Value::Dimension(..) => return Err(format!("$green: Expected {} to have no units or \"%\".", v).into()),
|
(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()),
|
v => return Err(format!("$green: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
let blue = match arg!(args, 2, "blue") {
|
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) => {
|
||||||
v @ Value::Dimension(..) => return Err(format!("$blue: Expected {} to have no units or \"%\".", v).into()),
|
(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()),
|
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)) {
|
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()
|
||||||
|
)
|
||||||
|
}
|
||||||
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
Ok(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "rgba", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"rgba".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let mut channels = match arg!(args, 0, "channels") {
|
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()),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(channels.len(), 3_usize);
|
assert_eq!(channels.len(), 3_usize);
|
||||||
@ -113,7 +147,6 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
let color = Color::from_rgba(red, green, blue, Number::from(1));
|
let color = Color::from_rgba(red, green, blue, Number::from(1));
|
||||||
|
|
||||||
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") {
|
let color = match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -122,60 +155,102 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
let alpha = match arg!(args, 1, "alpha") {
|
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()
|
||||||
|
)
|
||||||
|
}
|
||||||
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color.with_alpha(alpha)))
|
Ok(Value::Color(color.with_alpha(alpha)))
|
||||||
} else {
|
} else {
|
||||||
let red = match arg!(args, 0, "red") {
|
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) => {
|
||||||
v @ Value::Dimension(..) => return Err(format!("$red: Expected {} to have no units or \"%\".", v).into()),
|
(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()),
|
v => return Err(format!("$red: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
let green = match arg!(args, 1, "green") {
|
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) => {
|
||||||
v @ Value::Dimension(..) => return Err(format!("$green: Expected {} to have no units or \"%\".", v).into()),
|
(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()),
|
v => return Err(format!("$green: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
let blue = match arg!(args, 2, "blue") {
|
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) => {
|
||||||
v @ Value::Dimension(..) => return Err(format!("$blue: Expected {} to have no units or \"%\".", v).into()),
|
(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()),
|
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)) {
|
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()
|
||||||
|
)
|
||||||
|
}
|
||||||
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
v => return Err(format!("$alpha: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
Ok(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "red", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"red".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Ok(Value::Dimension(c.red(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.red(), Unit::None)),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "green", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"green".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Ok(Value::Dimension(c.green(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.green(), Unit::None)),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "blue", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"blue".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Ok(Value::Dimension(c.blue(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.blue(), Unit::None)),
|
||||||
v => Err(format!("$color: {} is not a color.", v).into()),
|
v => Err(format!("$color: {} is not a color.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "mix", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"mix".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 3);
|
max_args!(args, 3);
|
||||||
let color1 = match arg!(args, 0, "color1") {
|
let color1 = match arg!(args, 0, "color1") {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
@ -187,10 +262,15 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
v => return Err(format!("$color2: {} is not a color.", v).into()),
|
v => return Err(format!("$color2: {} is not a color.", v).into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let weight = match arg!(args, 2, "weight"=Value::Dimension(Number::from(50), Unit::None)) {
|
let weight = match arg!(
|
||||||
|
args,
|
||||||
|
2,
|
||||||
|
"weight" = Value::Dimension(Number::from(50), Unit::None)
|
||||||
|
) {
|
||||||
Value::Dimension(n, u) => bound!("weight", n, u, 0, 100) / Number::from(100),
|
Value::Dimension(n, u) => bound!("weight", n, u, 0, 100) / Number::from(100),
|
||||||
v => return Err(format!("$weight: {} is not a number.", v).into()),
|
v => return Err(format!("$weight: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
Ok(Value::Color(color1.mix(&color2, weight)))
|
Ok(Value::Color(color1.mix(&color2, weight)))
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,14 @@ use crate::units::Unit;
|
|||||||
use crate::value::{Number, Value};
|
use crate::value::{Number, Value};
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
decl!(f "length", |args, _| {
|
f.insert(
|
||||||
|
"length".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
let len = match arg!(args, 0, "list") {
|
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),
|
||||||
};
|
};
|
||||||
Ok(Value::Dimension(len, Unit::None))
|
Ok(Value::Dimension(len, Unit::None))
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,6 @@ macro_rules! arg {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! decl {
|
|
||||||
($f:ident $name:literal, $body:expr) => {
|
|
||||||
$f.insert($name.to_owned(), Box::new($body));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! max_args {
|
macro_rules! max_args {
|
||||||
($args:ident, $count:literal) => {
|
($args:ident, $count:literal) => {
|
||||||
if $args.len() > $count {
|
if $args.len() > $count {
|
||||||
|
@ -5,44 +5,63 @@ use crate::units::Unit;
|
|||||||
use crate::value::{Number, Value};
|
use crate::value::{Number, Value};
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
decl!(f "percentage", |args, _| {
|
f.insert(
|
||||||
|
"percentage".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let num = match arg!(args, 0, "number") {
|
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()),
|
||||||
};
|
};
|
||||||
Ok(Value::Dimension(num, Unit::Percent))
|
Ok(Value::Dimension(num, Unit::Percent))
|
||||||
});
|
}),
|
||||||
decl!(f "round", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"round".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "number") {
|
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 => Err(format!("$number: {} is not a number.", v).into()),
|
v => Err(format!("$number: {} is not a number.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "ceil", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"ceil".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "number") {
|
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 => Err(format!("$number: {} is not a number.", v).into()),
|
v => Err(format!("$number: {} is not a number.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "floor", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"floor".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "number") {
|
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 => Err(format!("$number: {} is not a number.", v).into()),
|
v => Err(format!("$number: {} is not a number.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "abs", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"abs".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "number") {
|
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 => Err(format!("$number: {} is not a number.", v).into()),
|
v => Err(format!("$number: {} is not a number.", v).into()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "comparable", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"comparable".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 2);
|
max_args!(args, 2);
|
||||||
let unit1 = match arg!(args, 0, "number1") {
|
let unit1 = match arg!(args, 0, "number1") {
|
||||||
Value::Dimension(_, u) => u,
|
Value::Dimension(_, u) => u,
|
||||||
@ -54,5 +73,6 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(Value::bool(unit1.comparable(&unit2)))
|
Ok(Value::bool(unit1.comparable(&unit2)))
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,20 @@ use crate::units::Unit;
|
|||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
decl!(f "if", |args, _| {
|
f.insert(
|
||||||
|
"if".to_owned(),
|
||||||
|
Box::new(|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"))
|
Ok(arg!(args, 1, "if-true"))
|
||||||
} else {
|
} else {
|
||||||
Ok(arg!(args, 2, "if-false"))
|
Ok(arg!(args, 2, "if-false"))
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "feature-exists", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"feature-exists".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "feature").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
|
||||||
@ -34,50 +39,74 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
"custom-property" => Ok(Value::False),
|
"custom-property" => Ok(Value::False),
|
||||||
_ => Ok(Value::False),
|
_ => Ok(Value::False),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "unit", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"unit".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let unit = match arg!(args, 0, "number") {
|
let unit = match arg!(args, 0, "number") {
|
||||||
Value::Dimension(_, u) => u.to_string(),
|
Value::Dimension(_, u) => u.to_string(),
|
||||||
_ => String::new()
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
Ok(Value::Ident(unit, QuoteKind::Double))
|
Ok(Value::Ident(unit, QuoteKind::Double))
|
||||||
});
|
}),
|
||||||
decl!(f "type-of", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"type-of".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let value = arg!(args, 0, "value");
|
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, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"unitless".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "number") {
|
match arg!(args, 0, "number") {
|
||||||
Value::Dimension(_, Unit::None) => Ok(Value::True),
|
Value::Dimension(_, Unit::None) => Ok(Value::True),
|
||||||
Value::Dimension(_, _) => Ok(Value::False),
|
Value::Dimension(_, _) => Ok(Value::False),
|
||||||
_ => Ok(Value::True)
|
_ => Ok(Value::True),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "inspect", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"inspect".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let value = arg!(args, 0, "value");
|
let value = arg!(args, 0, "value");
|
||||||
Ok(Value::Ident(value.to_string(), QuoteKind::None))
|
Ok(Value::Ident(value.to_string(), QuoteKind::None))
|
||||||
});
|
}),
|
||||||
decl!(f "variable-exists", |args, scope| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"variable-exists".to_owned(),
|
||||||
|
Box::new(|args, scope| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let value = arg!(args, 0, "name");
|
let value = arg!(args, 0, "name");
|
||||||
Ok(Value::bool(scope.var_exists(&value.to_string())))
|
Ok(Value::bool(scope.var_exists(&value.to_string())))
|
||||||
});
|
}),
|
||||||
decl!(f "mixin-exists", |args, scope| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"mixin-exists".to_owned(),
|
||||||
|
Box::new(|args, scope| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
let value = arg!(args, 0, "name");
|
let value = arg!(args, 0, "name");
|
||||||
Ok(Value::bool(scope.mixin_exists(&value.to_string())))
|
Ok(Value::bool(scope.mixin_exists(&value.to_string())))
|
||||||
});
|
}),
|
||||||
decl!(f "function-exists", |args, scope| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"function-exists".to_owned(),
|
||||||
|
Box::new(|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.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| {
|
))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
f.insert("call".to_owned(), Box::new(|_args, _scope| {
|
||||||
todo!("builtin function `call()` is blocked on refactoring how call args are stored and parsed")
|
todo!("builtin function `call()` is blocked on refactoring how call args are stored and parsed")
|
||||||
// let func = arg!(args, 0, "function").to_string();
|
// let func = arg!(args, 0, "function").to_string();
|
||||||
// let func = match scope.get_fn(&func) {
|
// let func = match scope.get_fn(&func) {
|
||||||
@ -88,5 +117,5 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
// },
|
// },
|
||||||
// };
|
// };
|
||||||
// Some(func.clone().args(&args).call())
|
// Some(func.clone().args(&args).call())
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
@ -10,43 +10,60 @@ use crate::units::Unit;
|
|||||||
use crate::value::{Number, Value};
|
use crate::value::{Number, Value};
|
||||||
|
|
||||||
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||||
decl!(f "to-upper-case", |args, _| {
|
f.insert(
|
||||||
|
"to-upper-case".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "string") {
|
match arg!(args, 0, "string") {
|
||||||
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, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"to-lower-case".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "string") {
|
match arg!(args, 0, "string") {
|
||||||
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, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"str-length".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "string") {
|
match arg!(args, 0, "string") {
|
||||||
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, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"quote".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "string") {
|
match arg!(args, 0, "string") {
|
||||||
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, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"unquote".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 1);
|
max_args!(args, 1);
|
||||||
match arg!(args, 0, "string") {
|
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()),
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
decl!(f "str-slice", |args, _| {
|
);
|
||||||
|
f.insert(
|
||||||
|
"str-slice".to_owned(),
|
||||||
|
Box::new(|args, _| {
|
||||||
max_args!(args, 3);
|
max_args!(args, 3);
|
||||||
let (string, quotes) = match arg!(args, 0, "string") {
|
let (string, quotes) = match arg!(args, 0, "string") {
|
||||||
Value::Ident(s, q) => (s, q),
|
Value::Ident(s, q) => (s, q),
|
||||||
@ -54,21 +71,37 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
};
|
};
|
||||||
let str_len = string.len();
|
let str_len = string.len();
|
||||||
let start = match arg!(args, 1, "start-at") {
|
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() => {
|
||||||
Value::Dimension(n, Unit::None) if n.to_integer().is_positive() => n.to_integer().to_usize().unwrap(),
|
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,
|
Value::Dimension(n, Unit::None) if n == Number::from(0) => 1_usize,
|
||||||
Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 1_usize,
|
Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 1_usize,
|
||||||
Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer()).to_usize().unwrap(),
|
Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer())
|
||||||
v @ Value::Dimension(..) => return Err(format!("$start: Expected {} to have no units.", v).into()),
|
.to_usize()
|
||||||
|
.unwrap(),
|
||||||
|
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) {
|
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() => {
|
||||||
Value::Dimension(n, Unit::None) if n.to_integer().is_positive() => n.to_integer().to_usize().unwrap(),
|
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,
|
Value::Dimension(n, Unit::None) if n == Number::from(0) => 0_usize,
|
||||||
Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 0_usize,
|
Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 0_usize,
|
||||||
Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer()).to_usize().unwrap(),
|
Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer())
|
||||||
v @ Value::Dimension(..) => return Err(format!("$end: Expected {} to have no units.", v).into()),
|
.to_usize()
|
||||||
|
.unwrap(),
|
||||||
|
v @ Value::Dimension(..) => {
|
||||||
|
return Err(format!("$end: Expected {} to have no units.", v).into())
|
||||||
|
}
|
||||||
Value::Null => str_len,
|
Value::Null => str_len,
|
||||||
v => return Err(format!("$end-at: {} is not a number.", v).into()),
|
v => return Err(format!("$end-at: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
@ -79,7 +112,9 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
|
|
||||||
if start > end || start > str_len {
|
if start > end || start > str_len {
|
||||||
match quotes {
|
match quotes {
|
||||||
QuoteKind::Double | QuoteKind::Single => Ok(Value::Ident(String::new(), QuoteKind::Double)),
|
QuoteKind::Double | QuoteKind::Single => {
|
||||||
|
Ok(Value::Ident(String::new(), QuoteKind::Double))
|
||||||
|
}
|
||||||
QuoteKind::None => Ok(Value::Null),
|
QuoteKind::None => Ok(Value::Null),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -89,5 +124,6 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
QuoteKind::None => Ok(Value::Ident(s, QuoteKind::None)),
|
QuoteKind::None => Ok(Value::Ident(s, QuoteKind::None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user