simplify builtin fn argument handling
This commit is contained in:
parent
95efc582b5
commit
f5a654fe5b
@ -2,7 +2,10 @@ use std::collections::{BTreeMap, BTreeSet};
|
|||||||
|
|
||||||
use crate::{builtin::builtin_imports::*, serializer::serialize_number, value::SassNumber};
|
use crate::{builtin::builtin_imports::*, serializer::serialize_number, value::SassNumber};
|
||||||
|
|
||||||
use super::rgb::{function_string, parse_channels, percentage_or_unitless, ParsedChannels};
|
use super::{
|
||||||
|
rgb::{function_string, parse_channels, percentage_or_unitless},
|
||||||
|
ParsedChannels,
|
||||||
|
};
|
||||||
|
|
||||||
fn hsl_3_args(
|
fn hsl_3_args(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
@ -14,15 +17,7 @@ fn hsl_3_args(
|
|||||||
let hue = args.get_err(0, "hue")?;
|
let hue = args.get_err(0, "hue")?;
|
||||||
let saturation = args.get_err(1, "saturation")?;
|
let saturation = args.get_err(1, "saturation")?;
|
||||||
let lightness = args.get_err(2, "lightness")?;
|
let lightness = args.get_err(2, "lightness")?;
|
||||||
let alpha = args.default_arg(
|
let alpha = args.default_arg(3, "alpha", Value::Dimension(SassNumber::new_unitless(1.0)));
|
||||||
3,
|
|
||||||
"alpha",
|
|
||||||
Value::Dimension(SassNumber {
|
|
||||||
num: (Number::one()),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if [&hue, &saturation, &lightness, &alpha]
|
if [&hue, &saturation, &lightness, &alpha]
|
||||||
.iter()
|
.iter()
|
||||||
@ -195,25 +190,15 @@ fn darken(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value>
|
|||||||
.get_err(0, "color")?
|
.get_err(0, "color")?
|
||||||
.assert_color_with_name("color", args.span())?;
|
.assert_color_with_name("color", args.span())?;
|
||||||
|
|
||||||
let amount = match args.get_err(1, "amount")? {
|
let mut amount = args
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => todo!(),
|
.get_err(1, "amount")?
|
||||||
Value::Dimension(SassNumber {
|
.assert_number_with_name("amount", args.span())?;
|
||||||
num: n,
|
|
||||||
unit: u,
|
amount.assert_bounds("amount", 0.0, 100.0, args.span())?;
|
||||||
as_slash: _,
|
|
||||||
}) => bound!(args, "amount", n, u, 0, 100) / Number(100.0),
|
amount.num /= Number(100.0);
|
||||||
v => {
|
|
||||||
return Err((
|
Ok(Value::Color(Arc::new(color.darken(amount.num))))
|
||||||
format!(
|
|
||||||
"$amount: {} is not a number.",
|
|
||||||
v.to_css_string(args.span(), false)?
|
|
||||||
),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Value::Color(Arc::new(color.darken(amount))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn saturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
fn saturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -232,24 +217,14 @@ fn saturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let amount = match args.get_err(1, "amount")? {
|
let mut amount = args
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => todo!(),
|
.get_err(1, "amount")?
|
||||||
Value::Dimension(SassNumber {
|
.assert_number_with_name("amount", args.span())?;
|
||||||
num: n,
|
|
||||||
unit: u,
|
amount.assert_bounds("amount", 0.0, 100.0, args.span())?;
|
||||||
as_slash: _,
|
|
||||||
}) => bound!(args, "amount", n, u, 0, 100) / Number(100.0),
|
amount.num /= Number(100.0);
|
||||||
v => {
|
|
||||||
return Err((
|
|
||||||
format!(
|
|
||||||
"$amount: {} is not a number.",
|
|
||||||
v.to_css_string(args.span(), false)?
|
|
||||||
),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let color = match args.get_err(0, "color")? {
|
let color = match args.get_err(0, "color")? {
|
||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber {
|
||||||
@ -271,7 +246,7 @@ fn saturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value
|
|||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(Value::Color(Arc::new(color.saturate(amount))))
|
Ok(Value::Color(Arc::new(color.saturate(amount.num))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desaturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
fn desaturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -279,25 +254,16 @@ fn desaturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Val
|
|||||||
let color = args
|
let color = args
|
||||||
.get_err(0, "color")?
|
.get_err(0, "color")?
|
||||||
.assert_color_with_name("color", args.span())?;
|
.assert_color_with_name("color", args.span())?;
|
||||||
let amount = match args.get_err(1, "amount")? {
|
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => todo!(),
|
let mut amount = args
|
||||||
Value::Dimension(SassNumber {
|
.get_err(1, "amount")?
|
||||||
num: n,
|
.assert_number_with_name("amount", args.span())?;
|
||||||
unit: u,
|
|
||||||
as_slash: _,
|
amount.assert_bounds("amount", 0.0, 100.0, args.span())?;
|
||||||
}) => bound!(args, "amount", n, u, 0, 100) / Number(100.0),
|
|
||||||
v => {
|
amount.num /= Number(100.0);
|
||||||
return Err((
|
|
||||||
format!(
|
Ok(Value::Color(Arc::new(color.desaturate(amount.num))))
|
||||||
"$amount: {} is not a number.",
|
|
||||||
v.to_css_string(args.span(), visitor.options.is_compressed())?
|
|
||||||
),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Value::Color(Arc::new(color.desaturate(amount))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn grayscale(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn grayscale(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -335,32 +301,20 @@ pub(crate) fn complement(mut args: ArgumentResult, visitor: &mut Visitor) -> Sas
|
|||||||
|
|
||||||
pub(crate) fn invert(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn invert(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(2)?;
|
args.max_args(2)?;
|
||||||
let weight = match args.get(1, "weight") {
|
let span = args.span();
|
||||||
Some(Spanned {
|
let weight = args
|
||||||
node: Value::Dimension(SassNumber { num: n, .. }),
|
.get(1, "weight")
|
||||||
..
|
.map::<SassResult<_>, _>(|weight| {
|
||||||
}) if n.is_nan() => todo!(),
|
let mut weight = weight.node.assert_number_with_name("weight", span)?;
|
||||||
Some(Spanned {
|
|
||||||
node:
|
weight.assert_bounds("weight", 0.0, 100.0, span)?;
|
||||||
Value::Dimension(SassNumber {
|
|
||||||
num: n,
|
weight.num /= Number(100.0);
|
||||||
unit: u,
|
|
||||||
as_slash: _,
|
Ok(weight.num)
|
||||||
}),
|
})
|
||||||
..
|
.transpose()?;
|
||||||
}) => Some(bound!(args, "weight", n, u, 0, 100) / Number(100.0)),
|
|
||||||
None => None,
|
|
||||||
Some(v) => {
|
|
||||||
return Err((
|
|
||||||
format!(
|
|
||||||
"$weight: {} is not a number.",
|
|
||||||
v.to_css_string(args.span(), visitor.options.is_compressed())?
|
|
||||||
),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match args.get_err(0, "color")? {
|
match args.get_err(0, "color")? {
|
||||||
Value::Color(c) => Ok(Value::Color(Arc::new(
|
Value::Color(c) => Ok(Value::Color(Arc::new(
|
||||||
c.invert(weight.unwrap_or_else(Number::one)),
|
c.invert(weight.unwrap_or_else(Number::one)),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::builtin::builtin_imports::*;
|
use crate::builtin::builtin_imports::*;
|
||||||
|
|
||||||
use super::rgb::{parse_channels, ParsedChannels};
|
use super::{rgb::parse_channels, ParsedChannels};
|
||||||
|
|
||||||
pub(crate) fn blackness(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn blackness(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use crate::value::Value;
|
||||||
|
|
||||||
use super::GlobalFunctionMap;
|
use super::GlobalFunctionMap;
|
||||||
|
|
||||||
pub mod hsl;
|
pub mod hsl;
|
||||||
@ -6,6 +8,12 @@ pub mod opacity;
|
|||||||
pub mod other;
|
pub mod other;
|
||||||
pub mod rgb;
|
pub mod rgb;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum ParsedChannels {
|
||||||
|
String(String),
|
||||||
|
List(Vec<Value>),
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn declare(f: &mut GlobalFunctionMap) {
|
pub(crate) fn declare(f: &mut GlobalFunctionMap) {
|
||||||
hsl::declare(f);
|
hsl::declare(f);
|
||||||
opacity::declare(f);
|
opacity::declare(f);
|
||||||
|
@ -32,21 +32,17 @@ mod test {
|
|||||||
|
|
||||||
pub(crate) fn alpha(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn alpha(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
if args.len() <= 1 {
|
if args.len() <= 1 {
|
||||||
match args.get_err(0, "color")? {
|
let color = args.get_err(0, "color")?;
|
||||||
Value::Color(c) => Ok(Value::Dimension(SassNumber {
|
|
||||||
num: c.alpha(),
|
if let Value::String(s, QuoteKind::None) = &color {
|
||||||
unit: Unit::None,
|
if is_ms_filter(s) {
|
||||||
as_slash: None,
|
return Ok(Value::String(format!("alpha({})", s), QuoteKind::None));
|
||||||
})),
|
|
||||||
Value::String(s, QuoteKind::None) if is_ms_filter(&s) => {
|
|
||||||
Ok(Value::String(format!("alpha({})", s), QuoteKind::None))
|
|
||||||
}
|
}
|
||||||
v => Err((
|
|
||||||
format!("$color: {} is not a color.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let color = color.assert_color_with_name("color", args.span())?;
|
||||||
|
|
||||||
|
Ok(Value::Dimension(SassNumber::new_unitless(color.alpha())))
|
||||||
} else {
|
} else {
|
||||||
let err = args.max_args(1);
|
let err = args.max_args(1);
|
||||||
let args = args
|
let args = args
|
||||||
@ -72,11 +68,7 @@ pub(crate) fn opacity(mut args: ArgumentResult, visitor: &mut Visitor) -> SassRe
|
|||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "color")? {
|
match args.get_err(0, "color")? {
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => todo!(),
|
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => todo!(),
|
||||||
Value::Color(c) => Ok(Value::Dimension(SassNumber {
|
Value::Color(c) => Ok(Value::Dimension(SassNumber::new_unitless(c.alpha()))),
|
||||||
num: c.alpha(),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
})),
|
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber {
|
||||||
num,
|
num,
|
||||||
unit,
|
unit,
|
||||||
@ -102,9 +94,9 @@ fn opacify(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value>
|
|||||||
.get_err(1, "amount")?
|
.get_err(1, "amount")?
|
||||||
.assert_number_with_name("amount", args.span())?;
|
.assert_number_with_name("amount", args.span())?;
|
||||||
|
|
||||||
let amount = bound!(args, "amount", amount.num, amount.unit(), 0, 1);
|
amount.assert_bounds("amount", 0.0, 1.0, args.span())?;
|
||||||
|
|
||||||
Ok(Value::Color(Arc::new(color.fade_in(amount))))
|
Ok(Value::Color(Arc::new(color.fade_in(amount.num))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transparentize(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
fn transparentize(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -112,22 +104,14 @@ fn transparentize(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult
|
|||||||
let color = args
|
let color = args
|
||||||
.get_err(0, "color")?
|
.get_err(0, "color")?
|
||||||
.assert_color_with_name("color", args.span())?;
|
.assert_color_with_name("color", args.span())?;
|
||||||
let amount = match args.get_err(1, "amount")? {
|
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => todo!(),
|
let amount = args
|
||||||
Value::Dimension(SassNumber {
|
.get_err(1, "amount")?
|
||||||
num: n,
|
.assert_number_with_name("amount", args.span())?;
|
||||||
unit: u,
|
|
||||||
as_slash: _,
|
amount.assert_bounds("amount", 0.0, 1.0, args.span())?;
|
||||||
}) => bound!(args, "amount", n, u, 0, 1),
|
|
||||||
v => {
|
Ok(Value::Color(Arc::new(color.fade_out(amount.num))))
|
||||||
return Err((
|
|
||||||
format!("$amount: {} is not a number.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Value::Color(Arc::new(color.fade_out(amount))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn declare(f: &mut GlobalFunctionMap) {
|
pub(crate) fn declare(f: &mut GlobalFunctionMap) {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::{builtin::builtin_imports::*, serializer::inspect_number, value::fuzzy_round};
|
use crate::{builtin::builtin_imports::*, serializer::inspect_number, value::fuzzy_round};
|
||||||
|
|
||||||
|
use super::ParsedChannels;
|
||||||
|
|
||||||
pub(crate) fn function_string(
|
pub(crate) fn function_string(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
@ -173,12 +175,6 @@ pub(crate) fn percentage_or_unitless(
|
|||||||
Ok(value.clamp(0.0, max).0)
|
Ok(value.clamp(0.0, max).0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub(crate) enum ParsedChannels {
|
|
||||||
String(String),
|
|
||||||
List(Vec<Value>),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_var_slash(value: &Value) -> bool {
|
fn is_var_slash(value: &Value) -> bool {
|
||||||
match value {
|
match value {
|
||||||
Value::String(text, QuoteKind::Quoted) => {
|
Value::String(text, QuoteKind::Quoted) => {
|
||||||
@ -313,7 +309,6 @@ pub(crate) fn parse_channels(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// name: Either `rgb` or `rgba` depending on the caller
|
|
||||||
fn inner_rgb(
|
fn inner_rgb(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
mut args: ArgumentResult,
|
mut args: ArgumentResult,
|
||||||
@ -363,11 +358,7 @@ pub(crate) fn red(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult
|
|||||||
.get_err(0, "color")?
|
.get_err(0, "color")?
|
||||||
.assert_color_with_name("color", args.span())?;
|
.assert_color_with_name("color", args.span())?;
|
||||||
|
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(color.red())))
|
||||||
num: color.red(),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn green(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn green(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -376,11 +367,7 @@ pub(crate) fn green(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResu
|
|||||||
.get_err(0, "color")?
|
.get_err(0, "color")?
|
||||||
.assert_color_with_name("color", args.span())?;
|
.assert_color_with_name("color", args.span())?;
|
||||||
|
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(color.green())))
|
||||||
num: color.green(),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn blue(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn blue(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -389,11 +376,7 @@ pub(crate) fn blue(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResul
|
|||||||
.get_err(0, "color")?
|
.get_err(0, "color")?
|
||||||
.assert_color_with_name("color", args.span())?;
|
.assert_color_with_name("color", args.span())?;
|
||||||
|
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(color.blue())))
|
||||||
num: color.blue(),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mix(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn mix(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -409,11 +392,7 @@ pub(crate) fn mix(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult
|
|||||||
let weight = match args.default_arg(
|
let weight = match args.default_arg(
|
||||||
2,
|
2,
|
||||||
"weight",
|
"weight",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(50.0)),
|
||||||
num: (Number(50.0)),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
) {
|
) {
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => todo!(),
|
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => todo!(),
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber {
|
||||||
|
@ -2,11 +2,10 @@ use crate::builtin::builtin_imports::*;
|
|||||||
|
|
||||||
pub(crate) fn length(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn length(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
Ok(Value::Dimension(SassNumber {
|
|
||||||
num: (Number::from(args.get_err(0, "list")?.as_list().len())),
|
let len = args.get_err(0, "list")?.as_list().len();
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
Ok(Value::Dimension(SassNumber::new_unitless(len)))
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn nth(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn nth(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -260,14 +259,10 @@ pub(crate) fn index(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResu
|
|||||||
let list = args.get_err(0, "list")?.as_list();
|
let list = args.get_err(0, "list")?.as_list();
|
||||||
let value = args.get_err(1, "value")?;
|
let value = args.get_err(1, "value")?;
|
||||||
let index = match list.into_iter().position(|v| v == value) {
|
let index = match list.into_iter().position(|v| v == value) {
|
||||||
Some(v) => Number::from(v + 1),
|
Some(v) => v + 1,
|
||||||
None => return Ok(Value::Null),
|
None => return Ok(Value::Null),
|
||||||
};
|
};
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(index)))
|
||||||
num: (index),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn zip(args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn zip(args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
|
@ -16,74 +16,47 @@ pub(crate) fn percentage(mut args: ArgumentResult, visitor: &mut Visitor) -> Sas
|
|||||||
|
|
||||||
pub(crate) fn round(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn round(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "number")? {
|
let mut number = args
|
||||||
// todo: better error message, consider finities
|
.get_err(0, "number")?
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => {
|
.assert_number_with_name("number", args.span())?;
|
||||||
Err(("Infinity or NaN toInt", args.span()).into())
|
|
||||||
}
|
if !number.num.is_finite() {
|
||||||
Value::Dimension(SassNumber {
|
return Err(("Infinity or NaN toInt", args.span()).into());
|
||||||
num: n,
|
|
||||||
unit: u,
|
|
||||||
as_slash: _,
|
|
||||||
}) => Ok(Value::Dimension(SassNumber {
|
|
||||||
num: (n.round()),
|
|
||||||
unit: u,
|
|
||||||
as_slash: None,
|
|
||||||
})),
|
|
||||||
v => Err((
|
|
||||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
number.num = number.num.round();
|
||||||
|
|
||||||
|
Ok(Value::Dimension(number))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn ceil(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn ceil(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "number")? {
|
let mut number = args
|
||||||
// todo: better error message, consider finities
|
.get_err(0, "number")?
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => {
|
.assert_number_with_name("number", args.span())?;
|
||||||
Err(("Infinity or NaN toInt", args.span()).into())
|
|
||||||
}
|
if !number.num.is_finite() {
|
||||||
Value::Dimension(SassNumber {
|
return Err(("Infinity or NaN toInt", args.span()).into());
|
||||||
num: n,
|
|
||||||
unit: u,
|
|
||||||
as_slash: _,
|
|
||||||
}) => Ok(Value::Dimension(SassNumber {
|
|
||||||
num: (n.ceil()),
|
|
||||||
unit: u,
|
|
||||||
as_slash: None,
|
|
||||||
})),
|
|
||||||
v => Err((
|
|
||||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
number.num = number.num.ceil();
|
||||||
|
|
||||||
|
Ok(Value::Dimension(number))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn floor(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn floor(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "number")? {
|
let mut number = args
|
||||||
// todo: better error message, consider finities
|
.get_err(0, "number")?
|
||||||
Value::Dimension(SassNumber { num: n, .. }) if n.is_nan() => {
|
.assert_number_with_name("number", args.span())?;
|
||||||
Err(("Infinity or NaN toInt", args.span()).into())
|
|
||||||
}
|
if !number.num.is_finite() {
|
||||||
Value::Dimension(SassNumber {
|
return Err(("Infinity or NaN toInt", args.span()).into());
|
||||||
num: n,
|
|
||||||
unit: u,
|
|
||||||
as_slash: _,
|
|
||||||
}) => Ok(Value::Dimension(SassNumber {
|
|
||||||
num: (n.floor()),
|
|
||||||
unit: u,
|
|
||||||
as_slash: None,
|
|
||||||
})),
|
|
||||||
v => Err((
|
|
||||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
number.num = number.num.floor();
|
||||||
|
|
||||||
|
Ok(Value::Dimension(number))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn abs(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn abs(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -92,6 +65,7 @@ pub(crate) fn abs(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult
|
|||||||
.get_err(0, "number")?
|
.get_err(0, "number")?
|
||||||
.assert_number_with_name("number", args.span())?;
|
.assert_number_with_name("number", args.span())?;
|
||||||
|
|
||||||
|
// todo: test for nan+infinity
|
||||||
num.num = num.num.abs();
|
num.num = num.num.abs();
|
||||||
|
|
||||||
Ok(Value::Dimension(num))
|
Ok(Value::Dimension(num))
|
||||||
@ -120,22 +94,16 @@ pub(crate) fn random(mut args: ArgumentResult, visitor: &mut Visitor) -> SassRes
|
|||||||
|
|
||||||
if matches!(limit, Value::Null) {
|
if matches!(limit, Value::Null) {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
return Ok(Value::Dimension(SassNumber {
|
return Ok(Value::Dimension(SassNumber::new_unitless(
|
||||||
num: (Number::from(rng.gen_range(0.0..1.0))),
|
rng.gen_range(0.0..1.0),
|
||||||
unit: Unit::None,
|
)));
|
||||||
as_slash: None,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let limit = limit.assert_number_with_name("limit", args.span())?.num;
|
let limit = limit.assert_number_with_name("limit", args.span())?.num;
|
||||||
let limit_int = limit.assert_int_with_name("limit", args.span())?;
|
let limit_int = limit.assert_int_with_name("limit", args.span())?;
|
||||||
|
|
||||||
if limit.is_one() {
|
if limit.is_one() {
|
||||||
return Ok(Value::Dimension(SassNumber {
|
return Ok(Value::Dimension(SassNumber::new_unitless(1.0)));
|
||||||
num: (Number::one()),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if limit.is_zero() || limit.is_negative() {
|
if limit.is_zero() || limit.is_negative() {
|
||||||
@ -147,11 +115,9 @@ pub(crate) fn random(mut args: ArgumentResult, visitor: &mut Visitor) -> SassRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(
|
||||||
num: (Number::from(rng.gen_range(0..limit_int) + 1)),
|
rng.gen_range(0..limit_int) + 1,
|
||||||
unit: Unit::None,
|
)))
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn min(args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn min(args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
|
@ -33,9 +33,13 @@ fn if_(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
|||||||
|
|
||||||
pub(crate) fn feature_exists(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn feature_exists(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "feature")? {
|
let feature = args
|
||||||
|
.get_err(0, "feature")?
|
||||||
|
.assert_string_with_name("feature", args.span())?
|
||||||
|
.0;
|
||||||
|
|
||||||
#[allow(clippy::match_same_arms)]
|
#[allow(clippy::match_same_arms)]
|
||||||
Value::String(s, _) => Ok(match s.as_str() {
|
Ok(match feature.as_str() {
|
||||||
// A local variable will shadow a global variable unless
|
// A local variable will shadow a global variable unless
|
||||||
// `!global` is used.
|
// `!global` is used.
|
||||||
"global-variable-shadowing" => Value::True,
|
"global-variable-shadowing" => Value::True,
|
||||||
@ -52,32 +56,17 @@ pub(crate) fn feature_exists(mut args: ArgumentResult, visitor: &mut Visitor) ->
|
|||||||
// interpolation treated as SassScript.
|
// interpolation treated as SassScript.
|
||||||
"custom-property" => Value::True,
|
"custom-property" => Value::True,
|
||||||
_ => Value::False,
|
_ => Value::False,
|
||||||
}),
|
})
|
||||||
v => Err((
|
|
||||||
format!("$feature: {} is not a string.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unit(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn unit(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
let unit = match args.get_err(0, "number")? {
|
|
||||||
Value::Dimension(SassNumber {
|
let number = args
|
||||||
num: _,
|
.get_err(0, "number")?
|
||||||
unit: u,
|
.assert_number_with_name("number", args.span())?;
|
||||||
as_slash: _,
|
|
||||||
}) => u.to_string(),
|
Ok(Value::String(number.unit.to_string(), QuoteKind::Quoted))
|
||||||
v => {
|
|
||||||
return Err((
|
|
||||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Value::String(unit, QuoteKind::Quoted))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn type_of(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn type_of(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -88,19 +77,11 @@ pub(crate) fn type_of(mut args: ArgumentResult, visitor: &mut Visitor) -> SassRe
|
|||||||
|
|
||||||
pub(crate) fn unitless(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn unitless(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
Ok(match args.get_err(0, "number")? {
|
let number = args
|
||||||
Value::Dimension(SassNumber {
|
.get_err(0, "number")?
|
||||||
unit: Unit::None, ..
|
.assert_number_with_name("number", args.span())?;
|
||||||
}) => Value::True,
|
|
||||||
Value::Dimension(SassNumber { .. }) => Value::False,
|
Ok(Value::bool(number.unit == Unit::None))
|
||||||
v => {
|
|
||||||
return Err((
|
|
||||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn inspect(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn inspect(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -116,14 +97,14 @@ pub(crate) fn variable_exists(
|
|||||||
visitor: &mut Visitor,
|
visitor: &mut Visitor,
|
||||||
) -> SassResult<Value> {
|
) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "name")? {
|
|
||||||
Value::String(s, _) => Ok(Value::bool(visitor.env.var_exists(s.into(), None)?)),
|
let name = Identifier::from(
|
||||||
v => Err((
|
args.get_err(0, "name")?
|
||||||
format!("$name: {} is not a string.", v.inspect(args.span())?),
|
.assert_string_with_name("name", args.span())?
|
||||||
args.span(),
|
.0,
|
||||||
)
|
);
|
||||||
.into()),
|
|
||||||
}
|
Ok(Value::bool(visitor.env.var_exists(name, None)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn global_variable_exists(
|
pub(crate) fn global_variable_exists(
|
||||||
@ -163,16 +144,11 @@ pub(crate) fn global_variable_exists(
|
|||||||
|
|
||||||
pub(crate) fn mixin_exists(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn mixin_exists(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(2)?;
|
args.max_args(2)?;
|
||||||
let name: Identifier = match args.get_err(0, "name")? {
|
let name = Identifier::from(
|
||||||
Value::String(s, _) => s.into(),
|
args.get_err(0, "name")?
|
||||||
v => {
|
.assert_string_with_name("name", args.span())?
|
||||||
return Err((
|
.0,
|
||||||
format!("$name: {} is not a string.", v.inspect(args.span())?),
|
);
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let module = match args.default_arg(1, "module", Value::Null) {
|
let module = match args.default_arg(1, "module", Value::Null) {
|
||||||
Value::String(s, _) => Some(s),
|
Value::String(s, _) => Some(s),
|
||||||
@ -203,16 +179,11 @@ pub(crate) fn function_exists(
|
|||||||
) -> SassResult<Value> {
|
) -> SassResult<Value> {
|
||||||
args.max_args(2)?;
|
args.max_args(2)?;
|
||||||
|
|
||||||
let name: Identifier = match args.get_err(0, "name")? {
|
let name = Identifier::from(
|
||||||
Value::String(s, _) => s.into(),
|
args.get_err(0, "name")?
|
||||||
v => {
|
.assert_string_with_name("name", args.span())?
|
||||||
return Err((
|
.0,
|
||||||
format!("$name: {} is not a string.", v.inspect(args.span())?),
|
);
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let module = match args.default_arg(1, "module", Value::Null) {
|
let module = match args.default_arg(1, "module", Value::Null) {
|
||||||
Value::String(s, _) => Some(s),
|
Value::String(s, _) => Some(s),
|
||||||
|
@ -2,72 +2,59 @@ use crate::builtin::builtin_imports::*;
|
|||||||
|
|
||||||
pub(crate) fn to_upper_case(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn to_upper_case(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "string")? {
|
let (mut s, q) = args
|
||||||
Value::String(mut i, q) => {
|
.get_err(0, "string")?
|
||||||
i.make_ascii_uppercase();
|
.assert_string_with_name("string", args.span())?;
|
||||||
Ok(Value::String(i, q))
|
|
||||||
}
|
s.make_ascii_uppercase();
|
||||||
v => Err((
|
|
||||||
format!("$string: {} is not a string.", v.inspect(args.span())?),
|
Ok(Value::String(s, q))
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_lower_case(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn to_lower_case(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "string")? {
|
|
||||||
Value::String(mut i, q) => {
|
let (mut s, q) = args
|
||||||
i.make_ascii_lowercase();
|
.get_err(0, "string")?
|
||||||
Ok(Value::String(i, q))
|
.assert_string_with_name("string", args.span())?;
|
||||||
}
|
|
||||||
v => Err((
|
s.make_ascii_lowercase();
|
||||||
format!("$string: {} is not a string.", v.inspect(args.span())?),
|
|
||||||
args.span(),
|
Ok(Value::String(s, q))
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn str_length(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn str_length(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "string")? {
|
let s = args
|
||||||
Value::String(i, _) => Ok(Value::Dimension(SassNumber {
|
.get_err(0, "string")?
|
||||||
num: (Number::from(i.chars().count())),
|
.assert_string_with_name("string", args.span())?
|
||||||
unit: Unit::None,
|
.0;
|
||||||
as_slash: None,
|
|
||||||
})),
|
Ok(Value::Dimension(SassNumber::new_unitless(
|
||||||
v => Err((
|
s.chars().count(),
|
||||||
format!("$string: {} is not a string.", v.inspect(args.span())?),
|
)))
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn quote(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn quote(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "string")? {
|
|
||||||
Value::String(i, _) => Ok(Value::String(i, QuoteKind::Quoted)),
|
let s = args
|
||||||
v => Err((
|
.get_err(0, "string")?
|
||||||
format!("$string: {} is not a string.", v.inspect(args.span())?),
|
.assert_string_with_name("string", args.span())?
|
||||||
args.span(),
|
.0;
|
||||||
)
|
|
||||||
.into()),
|
Ok(Value::String(s, QuoteKind::Quoted))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unquote(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn unquote(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
match args.get_err(0, "string")? {
|
|
||||||
i @ Value::String(..) => Ok(i.unquote()),
|
let s = args
|
||||||
v => Err((
|
.get_err(0, "string")?
|
||||||
format!("$string: {} is not a string.", v.inspect(args.span())?),
|
.assert_string_with_name("string", args.span())?
|
||||||
args.span(),
|
.0;
|
||||||
)
|
|
||||||
.into()),
|
Ok(Value::String(s, QuoteKind::None))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn str_slice(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn str_slice(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -100,11 +87,7 @@ pub(crate) fn str_slice(mut args: ArgumentResult, visitor: &mut Visitor) -> Sass
|
|||||||
.default_arg(
|
.default_arg(
|
||||||
2,
|
2,
|
||||||
"end-at",
|
"end-at",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(-1.0)),
|
||||||
num: Number(-1.0),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
.assert_number_with_name("end-at", span)?;
|
.assert_number_with_name("end-at", span)?;
|
||||||
|
|
||||||
@ -149,11 +132,7 @@ pub(crate) fn str_index(mut args: ArgumentResult, visitor: &mut Visitor) -> Sass
|
|||||||
None => return Ok(Value::Null),
|
None => return Ok(Value::Null),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(char_position)))
|
||||||
num: Number::from(char_position),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn str_insert(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
pub(crate) fn str_insert(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
|
@ -206,8 +206,8 @@ fn log(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(
|
||||||
num: if let Some(base) = base {
|
if let Some(base) = base {
|
||||||
if base.is_zero() {
|
if base.is_zero() {
|
||||||
Number::zero()
|
Number::zero()
|
||||||
} else {
|
} else {
|
||||||
@ -221,9 +221,7 @@ fn log(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
|||||||
} else {
|
} else {
|
||||||
number.ln()
|
number.ln()
|
||||||
},
|
},
|
||||||
unit: Unit::None,
|
)))
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pow(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
fn pow(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -241,11 +239,9 @@ fn pow(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
|||||||
.assert_number_with_name("exponent", span)?;
|
.assert_number_with_name("exponent", span)?;
|
||||||
exponent.assert_no_units("exponent", span)?;
|
exponent.assert_no_units("exponent", span)?;
|
||||||
|
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(
|
||||||
num: base.num.pow(exponent.num),
|
base.num.pow(exponent.num),
|
||||||
unit: Unit::None,
|
)))
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sqrt(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
fn sqrt(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
||||||
@ -255,11 +251,9 @@ fn sqrt(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
|||||||
.assert_number_with_name("number", args.span())?;
|
.assert_number_with_name("number", args.span())?;
|
||||||
number.assert_no_units("number", args.span())?;
|
number.assert_no_units("number", args.span())?;
|
||||||
|
|
||||||
Ok(Value::Dimension(SassNumber {
|
Ok(Value::Dimension(SassNumber::new_unitless(
|
||||||
num: number.num.sqrt(),
|
number.num.sqrt(),
|
||||||
unit: Unit::None,
|
)))
|
||||||
as_slash: None,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! trig_fn {
|
macro_rules! trig_fn {
|
||||||
@ -274,11 +268,9 @@ macro_rules! trig_fn {
|
|||||||
num,
|
num,
|
||||||
unit: unit @ (Unit::None | Unit::Rad | Unit::Deg | Unit::Grad | Unit::Turn),
|
unit: unit @ (Unit::None | Unit::Rad | Unit::Deg | Unit::Grad | Unit::Turn),
|
||||||
..
|
..
|
||||||
}) => Value::Dimension(SassNumber {
|
}) => {
|
||||||
num: Number(coerce_to_rad(num.0, unit).$name()),
|
Value::Dimension(SassNumber::new_unitless(coerce_to_rad(num.0, unit).$name()))
|
||||||
unit: Unit::None,
|
}
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
v @ Value::Dimension(..) => {
|
v @ Value::Dimension(..) => {
|
||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
@ -482,58 +474,30 @@ pub(crate) fn declare(f: &mut Module) {
|
|||||||
|
|
||||||
f.insert_builtin_var(
|
f.insert_builtin_var(
|
||||||
"e",
|
"e",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(std::f64::consts::E)),
|
||||||
num: Number(std::f64::consts::E),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
f.insert_builtin_var(
|
f.insert_builtin_var(
|
||||||
"pi",
|
"pi",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(std::f64::consts::PI)),
|
||||||
num: Number(std::f64::consts::PI),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
f.insert_builtin_var(
|
f.insert_builtin_var(
|
||||||
"epsilon",
|
"epsilon",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(std::f64::EPSILON)),
|
||||||
num: Number(std::f64::EPSILON),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
f.insert_builtin_var(
|
f.insert_builtin_var(
|
||||||
"max-safe-integer",
|
"max-safe-integer",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(9007199254740991.0)),
|
||||||
num: Number(9007199254740991.0),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
f.insert_builtin_var(
|
f.insert_builtin_var(
|
||||||
"min-safe-integer",
|
"min-safe-integer",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(-9007199254740991.0)),
|
||||||
num: Number(-9007199254740991.0),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
f.insert_builtin_var(
|
f.insert_builtin_var(
|
||||||
"max-number",
|
"max-number",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(f64::MAX)),
|
||||||
num: Number(f64::MAX),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
f.insert_builtin_var(
|
f.insert_builtin_var(
|
||||||
"min-number",
|
"min-number",
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(SassNumber::new_unitless(f64::MIN_POSITIVE)),
|
||||||
num: Number(f64::MIN_POSITIVE),
|
|
||||||
unit: Unit::None,
|
|
||||||
as_slash: None,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,10 @@ fn load_css(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<()> {
|
|||||||
|
|
||||||
let span = args.span();
|
let span = args.span();
|
||||||
|
|
||||||
let url = match args.get_err(0, "module")? {
|
let url = args
|
||||||
Value::String(s, ..) => s,
|
.get_err(0, "module")?
|
||||||
v => {
|
.assert_string_with_name("module", args.span())?
|
||||||
return Err((
|
.0;
|
||||||
format!("$module: {} is not a string.", v.inspect(span)?),
|
|
||||||
span,
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let with = match args.default_arg(1, "with", Value::Null) {
|
let with = match args.default_arg(1, "with", Value::Null) {
|
||||||
Value::Map(map) => Some(map),
|
Value::Map(map) => Some(map),
|
||||||
@ -45,16 +39,8 @@ fn load_css(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<()> {
|
|||||||
|
|
||||||
let mut values = BTreeMap::new();
|
let mut values = BTreeMap::new();
|
||||||
for (key, value) in with {
|
for (key, value) in with {
|
||||||
let name = match key.node {
|
let name =
|
||||||
Value::String(s, ..) => Identifier::from(s),
|
Identifier::from(key.node.assert_string_with_name("with key", args.span())?.0);
|
||||||
v => {
|
|
||||||
return Err((
|
|
||||||
format!("$with key: {} is not a string.", v.inspect(span)?),
|
|
||||||
span,
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if values.contains_key(&name) {
|
if values.contains_key(&name) {
|
||||||
// todo: write test for this
|
// todo: write test for this
|
||||||
@ -97,16 +83,11 @@ fn load_css(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<()> {
|
|||||||
fn module_functions(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
fn module_functions(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
|
|
||||||
let module = match args.get_err(0, "module")? {
|
let module = Identifier::from(
|
||||||
Value::String(s, ..) => s,
|
args.get_err(0, "module")?
|
||||||
v => {
|
.assert_string_with_name("module", args.span())?
|
||||||
return Err((
|
.0,
|
||||||
format!("$module: {} is not a string.", v.inspect(args.span())?),
|
);
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Value::Map(
|
Ok(Value::Map(
|
||||||
(*(*visitor.env.modules)
|
(*(*visitor.env.modules)
|
||||||
@ -120,16 +101,11 @@ fn module_functions(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResu
|
|||||||
fn module_variables(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
fn module_variables(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult<Value> {
|
||||||
args.max_args(1)?;
|
args.max_args(1)?;
|
||||||
|
|
||||||
let module = match args.get_err(0, "module")? {
|
let module = Identifier::from(
|
||||||
Value::String(s, ..) => s,
|
args.get_err(0, "module")?
|
||||||
v => {
|
.assert_string_with_name("module", args.span())?
|
||||||
return Err((
|
.0,
|
||||||
format!("$module: {} is not a string.", v.inspect(args.span())?),
|
);
|
||||||
args.span(),
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Value::Map(
|
Ok(Value::Map(
|
||||||
(*(*visitor.env.modules)
|
(*(*visitor.env.modules)
|
||||||
|
@ -30,6 +30,14 @@ pub(crate) fn conversion_factor(from: &Unit, to: &Unit) -> Option<f64> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SassNumber {
|
impl SassNumber {
|
||||||
|
pub fn new_unitless<N: Into<Number>>(n: N) -> Self {
|
||||||
|
Self {
|
||||||
|
num: n.into(),
|
||||||
|
unit: Unit::None,
|
||||||
|
as_slash: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_comparable_units(&self, other_unit: &Unit) -> bool {
|
pub fn has_comparable_units(&self, other_unit: &Unit) -> bool {
|
||||||
self.unit.comparable(other_unit)
|
self.unit.comparable(other_unit)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user