Use SassError over Option inside builtins
This commit is contained in:
parent
ff0b05d74a
commit
d300cd046a
@ -28,7 +28,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("non-number alpha given to builtin function `rgb()`")
|
_ => todo!("non-number alpha given to builtin function `rgb()`")
|
||||||
};
|
};
|
||||||
Some(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").eval() {
|
||||||
@ -52,23 +52,23 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for alpha"),
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(Color::from_hsla(hue, saturation, luminance, alpha)))
|
Ok(Value::Color(Color::from_hsla(hue, saturation, luminance, alpha)))
|
||||||
});
|
});
|
||||||
decl!(f "hue", |args, _| {
|
decl!(f "hue", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(c.hue(), Unit::Deg)),
|
Value::Color(c) => Ok(Value::Dimension(c.hue(), Unit::Deg)),
|
||||||
_ => todo!("non-color given to builtin function `hue()`")
|
_ => todo!("non-color given to builtin function `hue()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "saturation", |args, _| {
|
decl!(f "saturation", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(c.saturation(), Unit::Percent)),
|
Value::Color(c) => Ok(Value::Dimension(c.saturation(), Unit::Percent)),
|
||||||
_ => todo!("non-color given to builtin function `saturation()`")
|
_ => todo!("non-color given to builtin function `saturation()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "lightness", |args, _| {
|
decl!(f "lightness", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(c.lightness(), Unit::Percent)),
|
Value::Color(c) => Ok(Value::Dimension(c.lightness(), Unit::Percent)),
|
||||||
_ => todo!("non-color given to builtin function `lightness()`")
|
_ => todo!("non-color given to builtin function `lightness()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -83,7 +83,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
| Value::Dimension(n, Unit::Deg) => n,
|
| Value::Dimension(n, Unit::Deg) => n,
|
||||||
_ => todo!("expected either unitless or % number for degrees"),
|
_ => todo!("expected either unitless or % number for degrees"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.adjust_hue(degrees)))
|
Ok(Value::Color(color.adjust_hue(degrees)))
|
||||||
});
|
});
|
||||||
decl!(f "lighten", |args, _| {
|
decl!(f "lighten", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
@ -95,7 +95,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for amount"),
|
_ => todo!("expected either unitless or % number for amount"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.lighten(amount)))
|
Ok(Value::Color(color.lighten(amount)))
|
||||||
});
|
});
|
||||||
decl!(f "darken", |args, _| {
|
decl!(f "darken", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
@ -107,7 +107,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for amount"),
|
_ => todo!("expected either unitless or % number for amount"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.darken(amount)))
|
Ok(Value::Color(color.darken(amount)))
|
||||||
});
|
});
|
||||||
decl!(f "saturate", |args, _| {
|
decl!(f "saturate", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
@ -119,7 +119,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for amount"),
|
_ => todo!("expected either unitless or % number for amount"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.saturate(amount)))
|
Ok(Value::Color(color.saturate(amount)))
|
||||||
});
|
});
|
||||||
decl!(f "desaturate", |args, _| {
|
decl!(f "desaturate", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
@ -131,21 +131,21 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for amount"),
|
_ => todo!("expected either unitless or % number for amount"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.desaturate(amount)))
|
Ok(Value::Color(color.desaturate(amount)))
|
||||||
});
|
});
|
||||||
decl!(f "grayscale", |args, _| {
|
decl!(f "grayscale", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
_ => todo!("non-color given to builtin function `grayscale()`")
|
_ => todo!("non-color given to builtin function `grayscale()`")
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.desaturate(Number::from(1))))
|
Ok(Value::Color(color.desaturate(Number::from(1))))
|
||||||
});
|
});
|
||||||
decl!(f "complement", |args, _| {
|
decl!(f "complement", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
_ => todo!("non-color given to builtin function `complement()`")
|
_ => todo!("non-color given to builtin function `complement()`")
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.complement()))
|
Ok(Value::Color(color.complement()))
|
||||||
});
|
});
|
||||||
decl!(f "invert", |args, _| {
|
decl!(f "invert", |args, _| {
|
||||||
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)) {
|
||||||
@ -154,7 +154,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
_ => todo!("non-number weight given to builtin function `invert()`")
|
_ => todo!("non-number weight given to builtin function `invert()`")
|
||||||
};
|
};
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Color(c.invert(weight))),
|
Value::Color(c) => Ok(Value::Color(c.invert(weight))),
|
||||||
_ => todo!("non-color given to builtin function `invert()`")
|
_ => todo!("non-color given to builtin function `invert()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8,14 +8,14 @@ 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 "alpha", |args, _| {
|
decl!(f "alpha", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(c.alpha(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `alpha()`")
|
_ => todo!("non-color given to builtin function `alpha()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "opacity", |args, _| {
|
decl!(f "opacity", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(c.alpha(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None)),
|
||||||
Value::Dimension(num, unit) => Some(Value::Ident(format!("opacity({}{})", num , unit), QuoteKind::None)),
|
Value::Dimension(num, unit) => Ok(Value::Ident(format!("opacity({}{})", num , unit), QuoteKind::None)),
|
||||||
_ => todo!("non-color given to builtin function `opacity()`")
|
_ => todo!("non-color given to builtin function `opacity()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -29,7 +29,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for amount"),
|
_ => todo!("expected either unitless or % number for amount"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.fade_in(amount)))
|
Ok(Value::Color(color.fade_in(amount)))
|
||||||
});
|
});
|
||||||
decl!(f "fade-in", |args, _| {
|
decl!(f "fade-in", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
@ -41,7 +41,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for amount"),
|
_ => todo!("expected either unitless or % number for amount"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.fade_in(amount)))
|
Ok(Value::Color(color.fade_in(amount)))
|
||||||
});
|
});
|
||||||
decl!(f "transparentize", |args, _| {
|
decl!(f "transparentize", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
@ -53,7 +53,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for amount"),
|
_ => todo!("expected either unitless or % number for amount"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.fade_out(amount)))
|
Ok(Value::Color(color.fade_out(amount)))
|
||||||
});
|
});
|
||||||
decl!(f "fade-out", |args, _| {
|
decl!(f "fade-out", |args, _| {
|
||||||
let color = match arg!(args, 0, "color").eval() {
|
let color = match arg!(args, 0, "color").eval() {
|
||||||
@ -65,6 +65,6 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for amount"),
|
_ => todo!("expected either unitless or % number for amount"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(color.fade_out(amount)))
|
Ok(Value::Color(color.fade_out(amount)))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
opt_arg!(args, blue, "blue");
|
opt_arg!(args, blue, "blue");
|
||||||
|
|
||||||
if red.is_some() || green.is_some() || blue.is_some() {
|
if red.is_some() || green.is_some() || blue.is_some() {
|
||||||
return Some(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).eval() {
|
||||||
@ -56,10 +56,10 @@ pub(crate) fn register(f: &mut BTreeMap<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 Some(Value::Color(Color::from_hsla(hue.unwrap_or(this_hue), saturation.unwrap_or(this_saturation), luminance.unwrap_or(this_luminance), alpha.unwrap_or(this_alpha))))
|
return Ok(Value::Color(Color::from_hsla(hue.unwrap_or(this_hue), saturation.unwrap_or(this_saturation), luminance.unwrap_or(this_luminance), alpha.unwrap_or(this_alpha))))
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Value::Color(if let Some(a) = alpha {
|
Ok(Value::Color(if let Some(a) = alpha {
|
||||||
color.with_alpha(a)
|
color.with_alpha(a)
|
||||||
} else {
|
} else {
|
||||||
color
|
color
|
||||||
@ -78,7 +78,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
|
|
||||||
if red.is_some() || green.is_some() || blue.is_some() {
|
if red.is_some() || green.is_some() || blue.is_some() {
|
||||||
return
|
return
|
||||||
Some(Value::Color(
|
Ok(Value::Color(
|
||||||
Color::from_rgba(
|
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)),
|
||||||
@ -102,7 +102,7 @@ pub(crate) fn register(f: &mut BTreeMap<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 Some(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)),
|
||||||
@ -112,7 +112,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Value::Color(if let Some(a) = alpha {
|
Ok(Value::Color(if let Some(a) = alpha {
|
||||||
let temp_alpha = color.alpha();
|
let temp_alpha = color.alpha();
|
||||||
color.with_alpha(temp_alpha + a)
|
color.with_alpha(temp_alpha + a)
|
||||||
} else {
|
} else {
|
||||||
@ -132,7 +132,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
|
|
||||||
if red.is_some() || green.is_some() || blue.is_some() {
|
if red.is_some() || green.is_some() || blue.is_some() {
|
||||||
return
|
return
|
||||||
Some(Value::Color(
|
Ok(Value::Color(
|
||||||
Color::from_rgba(
|
Color::from_rgba(
|
||||||
scale(color.red(), red.unwrap_or(Number::from(0)), Number::from(255)),
|
scale(color.red(), red.unwrap_or(Number::from(0)), Number::from(255)),
|
||||||
scale(color.green(), green.unwrap_or(Number::from(0)), Number::from(255)),
|
scale(color.green(), green.unwrap_or(Number::from(0)), Number::from(255)),
|
||||||
@ -156,7 +156,7 @@ pub(crate) fn register(f: &mut BTreeMap<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 Some(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(this_saturation, saturation.unwrap_or(Number::from(0)), Number::from(1)),
|
||||||
@ -166,7 +166,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Value::Color(if let Some(a) = alpha {
|
Ok(Value::Color(if let Some(a) = alpha {
|
||||||
let temp_alpha = color.alpha();
|
let temp_alpha = color.alpha();
|
||||||
color.with_alpha(scale(temp_alpha, a, Number::from(1)))
|
color.with_alpha(scale(temp_alpha, a, Number::from(1)))
|
||||||
} else {
|
} else {
|
||||||
@ -178,7 +178,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Color(c) => c.clone(),
|
Value::Color(c) => c.clone(),
|
||||||
_ => todo!("non-color given to builtin function `ie-hex-str()`")
|
_ => todo!("non-color given to builtin function `ie-hex-str()`")
|
||||||
};
|
};
|
||||||
Some(Value::Ident(color.to_ie_hex_str(), QuoteKind::None))
|
Ok(Value::Ident(color.to_ie_hex_str(), QuoteKind::None))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
|
|
||||||
let color = Color::from_rgba(red, green, blue, Number::from(1));
|
let color = Color::from_rgba(red, green, blue, Number::from(1));
|
||||||
|
|
||||||
Some(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").eval() {
|
||||||
@ -47,7 +47,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for alpha"),
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
};
|
};
|
||||||
Some(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").eval() {
|
||||||
Value::Dimension(n, Unit::None) => n,
|
Value::Dimension(n, Unit::None) => n,
|
||||||
@ -69,7 +69,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for alpha")
|
_ => todo!("expected either unitless or % number for alpha")
|
||||||
};
|
};
|
||||||
Some(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
Ok(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "rgba", |args, _| {
|
decl!(f "rgba", |args, _| {
|
||||||
@ -101,7 +101,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
|
|
||||||
let color = Color::from_rgba(red, green, blue, Number::from(1));
|
let color = Color::from_rgba(red, green, blue, Number::from(1));
|
||||||
|
|
||||||
Some(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").eval() {
|
||||||
@ -113,7 +113,7 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for alpha"),
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
};
|
};
|
||||||
Some(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").eval() {
|
||||||
Value::Dimension(n, Unit::None) => n,
|
Value::Dimension(n, Unit::None) => n,
|
||||||
@ -135,24 +135,24 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for alpha")
|
_ => todo!("expected either unitless or % number for alpha")
|
||||||
};
|
};
|
||||||
Some(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
Ok(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "red", |args, _| {
|
decl!(f "red", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(c.red(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.red(), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `red()`")
|
_ => todo!("non-color given to builtin function `red()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "green", |args, _| {
|
decl!(f "green", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(c.green(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.green(), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `green()`")
|
_ => todo!("non-color given to builtin function `green()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "blue", |args, _| {
|
decl!(f "blue", |args, _| {
|
||||||
match arg!(args, 0, "color") {
|
match arg!(args, 0, "color") {
|
||||||
Value::Color(c) => Some(Value::Dimension(c.blue(), Unit::None)),
|
Value::Color(c) => Ok(Value::Dimension(c.blue(), Unit::None)),
|
||||||
_ => todo!("non-color given to builtin function `blue()`")
|
_ => todo!("non-color given to builtin function `blue()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -172,6 +172,6 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for $weight")
|
_ => todo!("expected either unitless or % number for $weight")
|
||||||
};
|
};
|
||||||
Some(Value::Color(color1.mix(color2, weight)))
|
Ok(Value::Color(color1.mix(color2, weight)))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,6 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::List(v, _) => Number::from(v.len()),
|
Value::List(v, _) => Number::from(v.len()),
|
||||||
_ => Number::from(1)
|
_ => Number::from(1)
|
||||||
};
|
};
|
||||||
Some(Value::Dimension(len, Unit::None))
|
Ok(Value::Dimension(len, Unit::None))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -10,29 +10,29 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(n, Unit::None) => n * Number::from(100),
|
Value::Dimension(n, Unit::None) => n * Number::from(100),
|
||||||
_ => todo!("expected unitless number in builtin function `percentage()`")
|
_ => todo!("expected unitless number in builtin function `percentage()`")
|
||||||
};
|
};
|
||||||
Some(Value::Dimension(num, Unit::Percent))
|
Ok(Value::Dimension(num, Unit::Percent))
|
||||||
});
|
});
|
||||||
decl!(f "round", |args, _| {
|
decl!(f "round", |args, _| {
|
||||||
match arg!(args, 0, "number").eval() {
|
match arg!(args, 0, "number").eval() {
|
||||||
Value::Dimension(n, u) => Some(Value::Dimension(n.round(), u)),
|
Value::Dimension(n, u) => Ok(Value::Dimension(n.round(), u)),
|
||||||
_ => todo!("expected number in builtin function `round()`")
|
_ => todo!("expected number in builtin function `round()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "ceil", |args, _| {
|
decl!(f "ceil", |args, _| {
|
||||||
match arg!(args, 0, "number").eval() {
|
match arg!(args, 0, "number").eval() {
|
||||||
Value::Dimension(n, u) => Some(Value::Dimension(n.ceil(), u)),
|
Value::Dimension(n, u) => Ok(Value::Dimension(n.ceil(), u)),
|
||||||
_ => todo!("expected number in builtin function `ceil()`")
|
_ => todo!("expected number in builtin function `ceil()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "floor", |args, _| {
|
decl!(f "floor", |args, _| {
|
||||||
match arg!(args, 0, "number").eval() {
|
match arg!(args, 0, "number").eval() {
|
||||||
Value::Dimension(n, u) => Some(Value::Dimension(n.floor(), u)),
|
Value::Dimension(n, u) => Ok(Value::Dimension(n.floor(), u)),
|
||||||
_ => todo!("expected number in builtin function `floor()`")
|
_ => todo!("expected number in builtin function `floor()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "abs", |args, _| {
|
decl!(f "abs", |args, _| {
|
||||||
match arg!(args, 0, "number").eval() {
|
match arg!(args, 0, "number").eval() {
|
||||||
Value::Dimension(n, u) => Some(Value::Dimension(n.abs(), u)),
|
Value::Dimension(n, u) => Ok(Value::Dimension(n.abs(), u)),
|
||||||
_ => todo!("expected number in builtin function `abs()`")
|
_ => todo!("expected number in builtin function `abs()`")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -46,6 +46,6 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
_ => todo!("$number2: ____ is not a number.")
|
_ => todo!("$number2: ____ is not a number.")
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Value::bool(unit1.comparable(&unit2)))
|
Ok(Value::bool(unit1.comparable(&unit2)))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
let if_true = arg!(args, 1, "if-true").clone();
|
let if_true = arg!(args, 1, "if-true").clone();
|
||||||
let if_false = arg!(args, 2, "if-false").clone();
|
let if_false = arg!(args, 2, "if-false").clone();
|
||||||
if cond.is_true() {
|
if cond.is_true() {
|
||||||
Some(if_true)
|
Ok(if_true)
|
||||||
} else {
|
} else {
|
||||||
Some(if_false)
|
Ok(if_false)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "feature-exists", |args, _| {
|
decl!(f "feature-exists", |args, _| {
|
||||||
@ -21,20 +21,20 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
match feature.clone().unquote().to_string().as_str() {
|
match feature.clone().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" => Some(Value::False),
|
"global-variable-shadowing" => Ok(Value::False),
|
||||||
// the @extend rule will affect selectors nested in pseudo-classes
|
// the @extend rule will affect selectors nested in pseudo-classes
|
||||||
// like :not()
|
// like :not()
|
||||||
"extend-selector-pseudoclass" => Some(Value::False),
|
"extend-selector-pseudoclass" => Ok(Value::False),
|
||||||
// Full support for unit arithmetic using units defined in the
|
// Full support for unit arithmetic using units defined in the
|
||||||
// [Values and Units Level 3][] spec.
|
// [Values and Units Level 3][] spec.
|
||||||
"units-level-3" => Some(Value::False),
|
"units-level-3" => Ok(Value::False),
|
||||||
// The Sass `@error` directive is supported.
|
// The Sass `@error` directive is supported.
|
||||||
"at-error" => Some(Value::True),
|
"at-error" => Ok(Value::True),
|
||||||
// The "Custom Properties Level 1" spec is supported. This means
|
// The "Custom Properties Level 1" spec is supported. This means
|
||||||
// that custom properties are parsed statically, with only
|
// that custom properties are parsed statically, with only
|
||||||
// interpolation treated as SassScript.
|
// interpolation treated as SassScript.
|
||||||
"custom-property" => Some(Value::False),
|
"custom-property" => Ok(Value::False),
|
||||||
_ => Some(Value::False),
|
_ => Ok(Value::False),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "unit", |args, _| {
|
decl!(f "unit", |args, _| {
|
||||||
@ -43,36 +43,36 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
Value::Dimension(_, u) => u.to_string(),
|
Value::Dimension(_, u) => u.to_string(),
|
||||||
_ => String::new()
|
_ => String::new()
|
||||||
};
|
};
|
||||||
Some(Value::Ident(unit, QuoteKind::Double))
|
Ok(Value::Ident(unit, QuoteKind::Double))
|
||||||
});
|
});
|
||||||
decl!(f "type-of", |args, _| {
|
decl!(f "type-of", |args, _| {
|
||||||
let value = arg!(args, 0, "value");
|
let value = arg!(args, 0, "value");
|
||||||
Some(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, _| {
|
||||||
let number = arg!(args, 0, "number");
|
let number = arg!(args, 0, "number");
|
||||||
match number {
|
match number {
|
||||||
Value::Dimension(_, Unit::None) => Some(Value::True),
|
Value::Dimension(_, Unit::None) => Ok(Value::True),
|
||||||
Value::Dimension(_, _) => Some(Value::False),
|
Value::Dimension(_, _) => Ok(Value::False),
|
||||||
_ => Some(Value::True)
|
_ => Ok(Value::True)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "inspect", |args, _| {
|
decl!(f "inspect", |args, _| {
|
||||||
let value = arg!(args, 0, "value");
|
let value = arg!(args, 0, "value");
|
||||||
Some(Value::Ident(value.to_string(), QuoteKind::None))
|
Ok(Value::Ident(value.to_string(), QuoteKind::None))
|
||||||
});
|
});
|
||||||
decl!(f "variable-exists", |args, scope| {
|
decl!(f "variable-exists", |args, scope| {
|
||||||
let value = arg!(args, 0, "name");
|
let value = arg!(args, 0, "name");
|
||||||
Some(Value::bool(scope.var_exists(&value.to_string())))
|
Ok(Value::bool(scope.var_exists(&value.to_string())))
|
||||||
});
|
});
|
||||||
decl!(f "mixin-exists", |args, scope| {
|
decl!(f "mixin-exists", |args, scope| {
|
||||||
let value = arg!(args, 0, "name");
|
let value = arg!(args, 0, "name");
|
||||||
Some(Value::bool(scope.mixin_exists(&value.to_string())))
|
Ok(Value::bool(scope.mixin_exists(&value.to_string())))
|
||||||
});
|
});
|
||||||
decl!(f "function-exists", |args, scope| {
|
decl!(f "function-exists", |args, scope| {
|
||||||
let value = arg!(args, 0, "name");
|
let value = arg!(args, 0, "name");
|
||||||
let s = value.eval().unquote().to_string();
|
let s = value.eval().unquote().to_string();
|
||||||
Some(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| {
|
||||||
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")
|
||||||
|
@ -3,6 +3,7 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use crate::args::CallArgs;
|
use crate::args::CallArgs;
|
||||||
use crate::common::Scope;
|
use crate::common::Scope;
|
||||||
|
use crate::error::SassResult;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -16,7 +17,7 @@ mod meta;
|
|||||||
mod selector;
|
mod selector;
|
||||||
mod string;
|
mod string;
|
||||||
|
|
||||||
pub(crate) type Builtin = Box<dyn Fn(&CallArgs, &Scope) -> Option<Value> + Send + Sync>;
|
pub(crate) type Builtin = Box<dyn Fn(&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> = {
|
||||||
|
@ -13,33 +13,33 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
decl!(f "to-upper-case", |args, _| {
|
decl!(f "to-upper-case", |args, _| {
|
||||||
let s: &Value = arg!(args, 0, "string");
|
let s: &Value = arg!(args, 0, "string");
|
||||||
match s.eval() {
|
match s.eval() {
|
||||||
Value::Ident(i, q) => Some(Value::Ident(i.to_ascii_uppercase(), q)),
|
Value::Ident(i, q) => Ok(Value::Ident(i.to_ascii_uppercase(), q)),
|
||||||
_ => todo!("")
|
_ => todo!("")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "to-lower-case", |args, _| {
|
decl!(f "to-lower-case", |args, _| {
|
||||||
let s: &Value = arg!(args, 0, "string");
|
let s: &Value = arg!(args, 0, "string");
|
||||||
match s.eval() {
|
match s.eval() {
|
||||||
Value::Ident(i, q) => Some(Value::Ident(i.to_ascii_lowercase(), q)),
|
Value::Ident(i, q) => Ok(Value::Ident(i.to_ascii_lowercase(), q)),
|
||||||
_ => todo!("")
|
_ => todo!("")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "str-length", |args, _| {
|
decl!(f "str-length", |args, _| {
|
||||||
let s: &Value = arg!(args, 0, "string");
|
let s: &Value = arg!(args, 0, "string");
|
||||||
match s.eval() {
|
match s.eval() {
|
||||||
Value::Ident(i, _) => Some(Value::Dimension(Number::from(i.len()), Unit::None)),
|
Value::Ident(i, _) => Ok(Value::Dimension(Number::from(i.len()), Unit::None)),
|
||||||
_ => todo!("")
|
_ => todo!("")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "quote", |args, _| {
|
decl!(f "quote", |args, _| {
|
||||||
let s = arg!(args, 0, "string").eval();
|
let s = arg!(args, 0, "string").eval();
|
||||||
match s {
|
match s {
|
||||||
Value::Ident(i, _) => Some(Value::Ident(i, QuoteKind::Double)),
|
Value::Ident(i, _) => Ok(Value::Ident(i, QuoteKind::Double)),
|
||||||
_ => todo!("")
|
_ => todo!("")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
decl!(f "unquote", |args, _| {
|
decl!(f "unquote", |args, _| {
|
||||||
Some(arg!(args, 0, "string").eval().unquote())
|
Ok(arg!(args, 0, "string").eval().unquote())
|
||||||
});
|
});
|
||||||
decl!(f "str-slice", |args, _| {
|
decl!(f "str-slice", |args, _| {
|
||||||
let (string, quotes) = match arg!(args, 0, "string").eval() {
|
let (string, quotes) = match arg!(args, 0, "string").eval() {
|
||||||
@ -71,14 +71,14 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
|
|
||||||
if start > end || start > str_len {
|
if start > end || start > str_len {
|
||||||
match quotes {
|
match quotes {
|
||||||
QuoteKind::Double | QuoteKind::Single => Some(Value::Ident(String::new(), QuoteKind::Double)),
|
QuoteKind::Double | QuoteKind::Single => Ok(Value::Ident(String::new(), QuoteKind::Double)),
|
||||||
QuoteKind::None => Some(Value::Null),
|
QuoteKind::None => Ok(Value::Null),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let s = string[start-1..end].to_string();
|
let s = string[start-1..end].to_string();
|
||||||
match quotes {
|
match quotes {
|
||||||
QuoteKind::Double | QuoteKind::Single => Some(Value::Ident(s, QuoteKind::Double)),
|
QuoteKind::Double | QuoteKind::Single => Ok(Value::Ident(s, QuoteKind::Double)),
|
||||||
QuoteKind::None => Some(Value::Ident(s, QuoteKind::None)),
|
QuoteKind::None => Ok(Value::Ident(s, QuoteKind::None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -222,7 +222,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(&eat_call_args(toks, scope), scope).ok(),
|
||||||
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