arg methods are now inherent to CallArgs, rather than parser

This commit is contained in:
Connor Skees 2020-07-10 21:42:10 -04:00
parent 3c756f661d
commit 5902ebd642
14 changed files with 245 additions and 314 deletions

View File

@ -5,7 +5,6 @@ use codemap::{Span, Spanned};
use crate::{ use crate::{
common::Identifier, common::Identifier,
error::SassResult, error::SassResult,
parse::Parser,
value::Value, value::Value,
{Cow, Token}, {Cow, Token},
}; };
@ -65,7 +64,7 @@ impl CallArgs {
CallArgs(HashMap::new(), span) CallArgs(HashMap::new(), span)
} }
pub fn to_css_string(self, parser: &mut Parser<'_>) -> SassResult<Spanned<String>> { pub fn to_css_string(self) -> SassResult<Spanned<String>> {
let mut string = String::with_capacity(2 + self.len() * 10); let mut string = String::with_capacity(2 + self.len() * 10);
string.push('('); string.push('(');
let mut span = self.1; let mut span = self.1;
@ -77,7 +76,7 @@ impl CallArgs {
}); });
} }
let args = match parser.variadic_args(self) { let args = match self.get_variadic() {
Ok(v) => v, Ok(v) => v,
Err(..) => { Err(..) => {
return Err(("Plain CSS functions don't support keyword arguments.", span).into()) return Err(("Plain CSS functions don't support keyword arguments.", span).into())
@ -123,11 +122,11 @@ impl CallArgs {
} }
} }
pub fn get_err(&mut self, position: usize, name: &'static str) -> SassResult<Spanned<Value>> { pub fn get_err(&mut self, position: usize, name: &'static str) -> SassResult<Value> {
match self.get_named(name) { match self.get_named(name) {
Some(v) => v, Some(v) => Ok(v?.node),
None => match self.get_positional(position) { None => match self.get_positional(position) {
Some(v) => v, Some(v) => Ok(v?.node),
None => Err((format!("Missing argument ${}.", name), self.span()).into()), None => Err((format!("Missing argument ${}.", name), self.span()).into()),
}, },
} }
@ -190,4 +189,50 @@ impl CallArgs {
} }
Ok(()) Ok(())
} }
pub fn default_arg(
&mut self,
position: usize,
name: &'static str,
default: Value,
) -> SassResult<Value> {
Ok(match self.get(position, name) {
Some(val) => val?.node,
None => default,
})
}
pub fn positional_arg(&mut self, position: usize) -> Option<SassResult<Spanned<Value>>> {
self.get_positional(position)
}
#[allow(dead_code, clippy::unused_self)]
fn named_arg(&mut self, name: &'static str) -> Option<SassResult<Spanned<Value>>> {
self.get_named(name)
}
pub fn default_named_arg(&mut self, name: &'static str, default: Value) -> SassResult<Value> {
Ok(match self.get_named(name) {
Some(val) => val?.node,
None => default,
})
}
pub fn get_variadic(self) -> SassResult<Vec<Spanned<Value>>> {
let mut vals = Vec::new();
let mut args = match self
.0
.into_iter()
.map(|(a, v)| Ok((a.position()?, v)))
.collect::<Result<Vec<(usize, SassResult<Spanned<Value>>)>, String>>()
{
Ok(v) => v,
Err(e) => return Err((format!("No argument named ${}.", e), self.1).into()),
};
args.sort_by(|(a1, _), (a2, _)| a1.cmp(a2));
for arg in args {
vals.push(arg.1?);
}
Ok(vals)
}
} }

View File

@ -18,7 +18,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
} }
if args.len() == 1 { if args.len() == 1 {
let mut channels = match parser.arg(&mut args, 0, "channels")? { let mut channels = match args.get_err(0, "channels")? {
Value::List(v, ..) => v, Value::List(v, ..) => v,
_ => return Err(("Missing argument $channels.", args.span()).into()), _ => return Err(("Missing argument $channels.", args.span()).into()),
}; };
@ -77,11 +77,11 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
Number::one(), Number::one(),
)))) ))))
} else { } else {
let hue = match parser.arg(&mut args, 0, "hue")? { let hue = match args.get_err(0, "hue")? {
Value::Dimension(n, ..) => n, Value::Dimension(n, ..) => n,
v if v.is_special_function() => { v if v.is_special_function() => {
let saturation = parser.arg(&mut args, 1, "saturation")?; let saturation = args.get_err(1, "saturation")?;
let lightness = parser.arg(&mut args, 2, "lightness")?; let lightness = args.get_err(2, "lightness")?;
let mut string = format!( let mut string = format!(
"{}({}, {}, {}", "{}({}, {}, {}",
name, name,
@ -91,11 +91,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
); );
if !args.is_empty() { if !args.is_empty() {
string.push_str(", "); string.push_str(", ");
string.push_str( string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
&parser
.arg(&mut args, 3, "alpha")?
.to_css_string(args.span())?,
);
} }
string.push(')'); string.push(')');
return Ok(Value::String(string, QuoteKind::None)); return Ok(Value::String(string, QuoteKind::None));
@ -108,10 +104,10 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
}; };
let saturation = match parser.arg(&mut args, 1, "saturation")? { let saturation = match args.get_err(1, "saturation")? {
Value::Dimension(n, ..) => n / Number::from(100), Value::Dimension(n, ..) => n / Number::from(100),
v if v.is_special_function() => { v if v.is_special_function() => {
let lightness = parser.arg(&mut args, 2, "lightness")?; let lightness = args.get_err(2, "lightness")?;
let mut string = format!( let mut string = format!(
"{}({}, {}, {}", "{}({}, {}, {}",
name, name,
@ -121,11 +117,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
); );
if !args.is_empty() { if !args.is_empty() {
string.push_str(", "); string.push_str(", ");
string.push_str( string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
&parser
.arg(&mut args, 3, "alpha")?
.to_css_string(args.span())?,
);
} }
string.push(')'); string.push(')');
return Ok(Value::String(string, QuoteKind::None)); return Ok(Value::String(string, QuoteKind::None));
@ -141,7 +133,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
}; };
let lightness = match parser.arg(&mut args, 2, "lightness")? { let lightness = match args.get_err(2, "lightness")? {
Value::Dimension(n, ..) => n / Number::from(100), Value::Dimension(n, ..) => n / Number::from(100),
v if v.is_special_function() => { v if v.is_special_function() => {
let mut string = format!( let mut string = format!(
@ -153,11 +145,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
); );
if !args.is_empty() { if !args.is_empty() {
string.push_str(", "); string.push_str(", ");
string.push_str( string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
&parser
.arg(&mut args, 3, "alpha")?
.to_css_string(args.span())?,
);
} }
string.push(')'); string.push(')');
return Ok(Value::String(string, QuoteKind::None)); return Ok(Value::String(string, QuoteKind::None));
@ -173,8 +161,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
}; };
let alpha = match parser.default_arg( let alpha = match args.default_arg(
&mut args,
3, 3,
"alpha", "alpha",
Value::Dimension(Number::one(), Unit::None, true), Value::Dimension(Number::one(), Unit::None, true),
@ -228,7 +215,7 @@ fn hsla(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.hue(), Unit::Deg, true)), Value::Color(c) => Ok(Value::Dimension(c.hue(), Unit::Deg, true)),
v => Err(( v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?), format!("$color: {} is not a color.", v.inspect(args.span())?),
@ -240,7 +227,7 @@ fn hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn saturation(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn saturation(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.saturation(), Unit::Percent, true)), Value::Color(c) => Ok(Value::Dimension(c.saturation(), Unit::Percent, true)),
v => Err(( v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?), format!("$color: {} is not a color.", v.inspect(args.span())?),
@ -252,7 +239,7 @@ fn saturation(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn lightness(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn lightness(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.lightness(), Unit::Percent, true)), Value::Color(c) => Ok(Value::Dimension(c.lightness(), Unit::Percent, true)),
v => Err(( v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?), format!("$color: {} is not a color.", v.inspect(args.span())?),
@ -264,7 +251,7 @@ fn lightness(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn adjust_hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn adjust_hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -274,7 +261,7 @@ fn adjust_hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
.into()) .into())
} }
}; };
let degrees = match parser.arg(&mut args, 1, "degrees")? { let degrees = match args.get_err(1, "degrees")? {
Value::Dimension(n, ..) => n, Value::Dimension(n, ..) => n,
v => { v => {
return Err(( return Err((
@ -292,7 +279,7 @@ fn adjust_hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn lighten(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn lighten(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -302,7 +289,7 @@ fn lighten(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
let amount = match parser.arg(&mut args, 1, "amount")? { let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100), Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
v => { v => {
return Err(( return Err((
@ -320,7 +307,7 @@ fn lighten(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn darken(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn darken(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -330,7 +317,7 @@ fn darken(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
let amount = match parser.arg(&mut args, 1, "amount")? { let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100), Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
v => { v => {
return Err(( return Err((
@ -352,15 +339,13 @@ fn saturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
return Ok(Value::String( return Ok(Value::String(
format!( format!(
"saturate({})", "saturate({})",
parser args.get_err(0, "amount")?.to_css_string(args.span())?
.arg(&mut args, 0, "amount")?
.to_css_string(args.span())?
), ),
QuoteKind::None, QuoteKind::None,
)); ));
} }
let amount = match parser.arg(&mut args, 1, "amount")? { let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100), Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
v => { v => {
return Err(( return Err((
@ -373,7 +358,7 @@ fn saturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
Value::Dimension(n, u, _) => { Value::Dimension(n, u, _) => {
return Ok(Value::String( return Ok(Value::String(
@ -394,7 +379,7 @@ fn saturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn desaturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn desaturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -404,7 +389,7 @@ fn desaturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
.into()) .into())
} }
}; };
let amount = match parser.arg(&mut args, 1, "amount")? { let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100), Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
v => { v => {
return Err(( return Err((
@ -422,7 +407,7 @@ fn desaturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn grayscale(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn grayscale(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
Value::Dimension(n, u, _) => { Value::Dimension(n, u, _) => {
return Ok(Value::String( return Ok(Value::String(
@ -443,7 +428,7 @@ fn grayscale(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn complement(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn complement(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -458,8 +443,7 @@ fn complement(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn invert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn invert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let weight = match parser.default_arg( let weight = match args.default_arg(
&mut args,
1, 1,
"weight", "weight",
Value::Dimension(Number::from(100), Unit::Percent, true), Value::Dimension(Number::from(100), Unit::Percent, true),
@ -476,7 +460,7 @@ fn invert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Color(Box::new(c.invert(weight)))), Value::Color(c) => Ok(Value::Color(Box::new(c.invert(weight)))),
Value::Dimension(n, Unit::Percent, _) => { Value::Dimension(n, Unit::Percent, _) => {
Ok(Value::String(format!("invert({}%)", n), QuoteKind::None)) Ok(Value::String(format!("invert({}%)", n), QuoteKind::None))

View File

@ -7,7 +7,7 @@ use crate::{
fn alpha(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn alpha(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None, true)), Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None, true)),
v => Err(( v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?), format!("$color: {} is not a color.", v.inspect(args.span())?),
@ -19,7 +19,7 @@ fn alpha(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn opacity(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn opacity(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None, true)), Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None, true)),
Value::Dimension(num, unit, _) => Ok(Value::String( Value::Dimension(num, unit, _) => Ok(Value::String(
format!("opacity({}{})", num, unit), format!("opacity({}{})", num, unit),
@ -35,7 +35,7 @@ fn opacity(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn opacify(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn opacify(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -45,7 +45,7 @@ fn opacify(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
let amount = match parser.arg(&mut args, 1, "amount")? { let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1), Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1),
v => { v => {
return Err(( return Err((
@ -60,7 +60,7 @@ fn opacify(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn fade_in(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn fade_in(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -70,7 +70,7 @@ fn fade_in(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
let amount = match parser.arg(&mut args, 1, "amount")? { let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1), Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1),
v => { v => {
return Err(( return Err((
@ -85,7 +85,7 @@ fn fade_in(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn transparentize(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn transparentize(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -95,7 +95,7 @@ fn transparentize(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
.into()) .into())
} }
}; };
let amount = match parser.arg(&mut args, 1, "amount")? { let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1), Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1),
v => { v => {
return Err(( return Err((
@ -110,7 +110,7 @@ fn transparentize(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
fn fade_out(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn fade_out(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -120,7 +120,7 @@ fn fade_out(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
let amount = match parser.arg(&mut args, 1, "amount")? { let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1), Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1),
v => { v => {
return Err(( return Err((

View File

@ -13,8 +13,8 @@ use crate::{
}; };
macro_rules! opt_rgba { macro_rules! opt_rgba {
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal, $parser:ident) => { ($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
let $name = match $parser.default_named_arg(&mut $args, $arg, Value::Null)? { let $name = match $args.default_named_arg($arg, Value::Null)? {
Value::Dimension(n, u, _) => Some(bound!($args, $arg, n, u, $low, $high)), Value::Dimension(n, u, _) => Some(bound!($args, $arg, n, u, $low, $high)),
Value::Null => None, Value::Null => None,
v => { v => {
@ -29,8 +29,8 @@ macro_rules! opt_rgba {
} }
macro_rules! opt_hsl { macro_rules! opt_hsl {
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal, $parser:ident) => { ($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
let $name = match $parser.default_named_arg(&mut $args, $arg, Value::Null)? { let $name = match $args.default_named_arg($arg, Value::Null)? {
Value::Dimension(n, u, _) => { Value::Dimension(n, u, _) => {
Some(bound!($args, $arg, n, u, $low, $high) / Number::from(100)) Some(bound!($args, $arg, n, u, $low, $high) / Number::from(100))
} }
@ -47,7 +47,7 @@ macro_rules! opt_hsl {
} }
fn change_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn change_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
if parser.positional_arg(&mut args, 1).is_some() { if args.positional_arg(1).is_some() {
return Err(( return Err((
"Only one positional argument is allowed. All other arguments must be passed by name.", "Only one positional argument is allowed. All other arguments must be passed by name.",
args.span(), args.span(),
@ -55,7 +55,7 @@ fn change_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
.into()); .into());
} }
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -66,10 +66,10 @@ fn change_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
} }
}; };
opt_rgba!(args, alpha, "alpha", 0, 1, parser); opt_rgba!(args, alpha, "alpha", 0, 1);
opt_rgba!(args, red, "red", 0, 255, parser); opt_rgba!(args, red, "red", 0, 255);
opt_rgba!(args, green, "green", 0, 255, parser); opt_rgba!(args, green, "green", 0, 255);
opt_rgba!(args, blue, "blue", 0, 255, parser); opt_rgba!(args, blue, "blue", 0, 255);
if red.is_some() || green.is_some() || blue.is_some() { if red.is_some() || green.is_some() || blue.is_some() {
return Ok(Value::Color(Box::new(Color::from_rgba( return Ok(Value::Color(Box::new(Color::from_rgba(
@ -80,7 +80,7 @@ fn change_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
)))); ))));
} }
let hue = match parser.default_named_arg(&mut args, "hue", Value::Null)? { let hue = match args.default_named_arg("hue", Value::Null)? {
Value::Dimension(n, ..) => Some(n), Value::Dimension(n, ..) => Some(n),
Value::Null => None, Value::Null => None,
v => { v => {
@ -92,8 +92,8 @@ fn change_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
} }
}; };
opt_hsl!(args, saturation, "saturation", 0, 100, parser); opt_hsl!(args, saturation, "saturation", 0, 100);
opt_hsl!(args, luminance, "lightness", 0, 100, parser); opt_hsl!(args, luminance, "lightness", 0, 100);
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.
@ -114,7 +114,7 @@ fn change_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
} }
fn adjust_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn adjust_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -125,10 +125,10 @@ fn adjust_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
} }
}; };
opt_rgba!(args, alpha, "alpha", -1, 1, parser); opt_rgba!(args, alpha, "alpha", -1, 1);
opt_rgba!(args, red, "red", -255, 255, parser); opt_rgba!(args, red, "red", -255, 255);
opt_rgba!(args, green, "green", -255, 255, parser); opt_rgba!(args, green, "green", -255, 255);
opt_rgba!(args, blue, "blue", -255, 255, parser); opt_rgba!(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 Ok(Value::Color(Box::new(Color::from_rgba( return Ok(Value::Color(Box::new(Color::from_rgba(
@ -139,7 +139,7 @@ fn adjust_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
)))); ))));
} }
let hue = match parser.default_named_arg(&mut args, "hue", Value::Null)? { let hue = match args.default_named_arg("hue", Value::Null)? {
Value::Dimension(n, ..) => Some(n), Value::Dimension(n, ..) => Some(n),
Value::Null => None, Value::Null => None,
v => { v => {
@ -151,8 +151,8 @@ fn adjust_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
} }
}; };
opt_hsl!(args, saturation, "saturation", -100, 100, parser); opt_hsl!(args, saturation, "saturation", -100, 100);
opt_hsl!(args, luminance, "lightness", -100, 100, parser); opt_hsl!(args, luminance, "lightness", -100, 100);
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.
@ -184,7 +184,7 @@ fn scale_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
} }
let span = args.span(); let span = args.span();
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -196,8 +196,8 @@ fn scale_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
}; };
macro_rules! opt_scale_arg { macro_rules! opt_scale_arg {
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal, $parser:ident) => { ($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
let $name = match $parser.default_named_arg(&mut $args, $arg, Value::Null)? { let $name = match $args.default_named_arg($arg, Value::Null)? {
Value::Dimension(n, Unit::Percent, _) => { Value::Dimension(n, Unit::Percent, _) => {
Some(bound!($args, $arg, n, Unit::Percent, $low, $high) / Number::from(100)) Some(bound!($args, $arg, n, Unit::Percent, $low, $high) / Number::from(100))
} }
@ -224,10 +224,10 @@ fn scale_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
}; };
} }
opt_scale_arg!(args, alpha, "alpha", -100, 100, parser); opt_scale_arg!(args, alpha, "alpha", -100, 100);
opt_scale_arg!(args, red, "red", -100, 100, parser); opt_scale_arg!(args, red, "red", -100, 100);
opt_scale_arg!(args, green, "green", -100, 100, parser); opt_scale_arg!(args, green, "green", -100, 100);
opt_scale_arg!(args, blue, "blue", -100, 100, parser); opt_scale_arg!(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 Ok(Value::Color(Box::new(Color::from_rgba( return Ok(Value::Color(Box::new(Color::from_rgba(
@ -254,8 +254,8 @@ fn scale_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
)))); ))));
} }
opt_scale_arg!(args, saturation, "saturation", -100, 100, parser); opt_scale_arg!(args, saturation, "saturation", -100, 100);
opt_scale_arg!(args, luminance, "lightness", -100, 100, parser); opt_scale_arg!(args, luminance, "lightness", -100, 100);
if saturation.is_some() || luminance.is_some() { if 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.
@ -290,7 +290,7 @@ fn scale_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn ie_hex_str(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn ie_hex_str(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((

View File

@ -21,7 +21,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
} }
if args.len() == 1 { if args.len() == 1 {
let mut channels = match parser.arg(&mut args, 0, "channels")? { let mut channels = match args.get_err(0, "channels")? {
Value::List(v, ..) => v, Value::List(v, ..) => v,
_ => return Err(("Missing argument $channels.", args.span()).into()), _ => return Err(("Missing argument $channels.", args.span()).into()),
}; };
@ -125,10 +125,10 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
Ok(Value::Color(Box::new(color))) Ok(Value::Color(Box::new(color)))
} else if args.len() == 2 { } else if args.len() == 2 {
let color = match parser.arg(&mut args, 0, "color")? { let color = match args.get_err(0, "color")? {
Value::Color(c) => c, Value::Color(c) => c,
v if v.is_special_function() => { v if v.is_special_function() => {
let alpha = parser.arg(&mut args, 1, "alpha")?; let alpha = args.get_err(1, "alpha")?;
return Ok(Value::String( return Ok(Value::String(
format!( format!(
"{}({}, {})", "{}({}, {})",
@ -147,7 +147,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
}; };
let alpha = match parser.arg(&mut args, 1, "alpha")? { let alpha = match args.get_err(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(..) => { v @ Value::Dimension(..) => {
@ -183,7 +183,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
}; };
Ok(Value::Color(Box::new(color.with_alpha(alpha)))) Ok(Value::Color(Box::new(color.with_alpha(alpha))))
} else { } else {
let red = match parser.arg(&mut args, 0, "red")? { let red = match args.get_err(0, "red")? {
Value::Dimension(n, Unit::None, _) => n, Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255), Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => { v @ Value::Dimension(..) => {
@ -197,8 +197,8 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
v if v.is_special_function() => { v if v.is_special_function() => {
let green = parser.arg(&mut args, 1, "green")?; let green = args.get_err(1, "green")?;
let blue = parser.arg(&mut args, 2, "blue")?; let blue = args.get_err(2, "blue")?;
let mut string = format!( let mut string = format!(
"{}({}, {}, {}", "{}({}, {}, {}",
name, name,
@ -208,11 +208,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
); );
if !args.is_empty() { if !args.is_empty() {
string.push_str(", "); string.push_str(", ");
string.push_str( string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
&parser
.arg(&mut args, 3, "alpha")?
.to_css_string(args.span())?,
);
} }
string.push(')'); string.push(')');
return Ok(Value::String(string, QuoteKind::None)); return Ok(Value::String(string, QuoteKind::None));
@ -225,7 +221,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
}; };
let green = match parser.arg(&mut args, 1, "green")? { let green = match args.get_err(1, "green")? {
Value::Dimension(n, Unit::None, _) => n, Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255), Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => { v @ Value::Dimension(..) => {
@ -239,7 +235,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
v if v.is_special_function() => { v if v.is_special_function() => {
let blue = parser.arg(&mut args, 2, "blue")?; let blue = args.get_err(2, "blue")?;
let mut string = format!( let mut string = format!(
"{}({}, {}, {}", "{}({}, {}, {}",
name, name,
@ -249,11 +245,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
); );
if !args.is_empty() { if !args.is_empty() {
string.push_str(", "); string.push_str(", ");
string.push_str( string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
&parser
.arg(&mut args, 3, "alpha")?
.to_css_string(args.span())?,
);
} }
string.push(')'); string.push(')');
return Ok(Value::String(string, QuoteKind::None)); return Ok(Value::String(string, QuoteKind::None));
@ -266,7 +258,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
}; };
let blue = match parser.arg(&mut args, 2, "blue")? { let blue = match args.get_err(2, "blue")? {
Value::Dimension(n, Unit::None, _) => n, Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255), Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255),
v @ Value::Dimension(..) => { v @ Value::Dimension(..) => {
@ -289,11 +281,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
); );
if !args.is_empty() { if !args.is_empty() {
string.push_str(", "); string.push_str(", ");
string.push_str( string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
&parser
.arg(&mut args, 3, "alpha")?
.to_css_string(args.span())?,
);
} }
string.push(')'); string.push(')');
return Ok(Value::String(string, QuoteKind::None)); return Ok(Value::String(string, QuoteKind::None));
@ -306,8 +294,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
.into()) .into())
} }
}; };
let alpha = match parser.default_arg( let alpha = match args.default_arg(
&mut args,
3, 3,
"alpha", "alpha",
Value::Dimension(Number::one(), Unit::None, true), Value::Dimension(Number::one(), Unit::None, true),
@ -359,7 +346,7 @@ fn rgba(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn red(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn red(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.red(), Unit::None, true)), Value::Color(c) => Ok(Value::Dimension(c.red(), Unit::None, true)),
v => Err(( v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?), format!("$color: {} is not a color.", v.inspect(args.span())?),
@ -371,7 +358,7 @@ fn red(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn green(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn green(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.green(), Unit::None, true)), Value::Color(c) => Ok(Value::Dimension(c.green(), Unit::None, true)),
v => Err(( v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?), format!("$color: {} is not a color.", v.inspect(args.span())?),
@ -383,7 +370,7 @@ fn green(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn blue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn blue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "color")? { match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.blue(), Unit::None, true)), Value::Color(c) => Ok(Value::Dimension(c.blue(), Unit::None, true)),
v => Err(( v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?), format!("$color: {} is not a color.", v.inspect(args.span())?),
@ -395,7 +382,7 @@ fn blue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn mix(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn mix(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let color1 = match parser.arg(&mut args, 0, "color1")? { let color1 = match args.get_err(0, "color1")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -406,7 +393,7 @@ fn mix(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
} }
}; };
let color2 = match parser.arg(&mut args, 1, "color2")? { let color2 = match args.get_err(1, "color2")? {
Value::Color(c) => c, Value::Color(c) => c,
v => { v => {
return Err(( return Err((
@ -417,8 +404,7 @@ fn mix(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
} }
}; };
let weight = match parser.default_arg( let weight = match args.default_arg(
&mut args,
2, 2,
"weight", "weight",
Value::Dimension(Number::from(50), Unit::None, true), Value::Dimension(Number::from(50), Unit::None, true),

View File

@ -14,7 +14,7 @@ use crate::{
fn length(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn length(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
Ok(Value::Dimension( Ok(Value::Dimension(
Number::from(parser.arg(&mut args, 0, "list")?.as_list().len()), Number::from(args.get_err(0, "list")?.as_list().len()),
Unit::None, Unit::None,
true, true,
)) ))
@ -22,8 +22,8 @@ fn length(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let mut list = parser.arg(&mut args, 0, "list")?.as_list(); let mut list = args.get_err(0, "list")?.as_list();
let n = match parser.arg(&mut args, 1, "n")? { let n = match args.get_err(1, "n")? {
Value::Dimension(num, ..) => num, Value::Dimension(num, ..) => num,
v => { v => {
return Err(( return Err((
@ -64,7 +64,7 @@ fn nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn list_separator(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn list_separator(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
Ok(Value::String( Ok(Value::String(
match parser.arg(&mut args, 0, "list")? { match args.get_err(0, "list")? {
Value::List(_, sep, ..) => sep.name(), Value::List(_, sep, ..) => sep.name(),
_ => ListSeparator::Space.name(), _ => ListSeparator::Space.name(),
} }
@ -75,12 +75,12 @@ fn list_separator(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
fn set_nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn set_nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let (mut list, sep, brackets) = match parser.arg(&mut args, 0, "list")? { let (mut list, sep, brackets) = match args.get_err(0, "list")? {
Value::List(v, sep, b) => (v, sep, b), Value::List(v, sep, b) => (v, sep, b),
Value::Map(m) => (m.as_list(), ListSeparator::Comma, Brackets::None), Value::Map(m) => (m.as_list(), ListSeparator::Comma, Brackets::None),
v => (vec![v], ListSeparator::Space, Brackets::None), v => (vec![v], ListSeparator::Space, Brackets::None),
}; };
let n = match parser.arg(&mut args, 1, "n")? { let n = match args.get_err(1, "n")? {
Value::Dimension(num, ..) => num, Value::Dimension(num, ..) => num,
v => { v => {
return Err(( return Err((
@ -109,7 +109,7 @@ fn set_nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
return Err((format!("$n: {} is not an int.", n), args.span()).into()); return Err((format!("$n: {} is not an int.", n), args.span()).into());
} }
let val = parser.arg(&mut args, 2, "value")?; let val = args.get_err(2, "value")?;
if n.is_positive() { if n.is_positive() {
list[n.to_integer().to_usize().unwrap_or(std::usize::MAX) - 1] = val; list[n.to_integer().to_usize().unwrap_or(std::usize::MAX) - 1] = val;
@ -122,13 +122,12 @@ fn set_nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn append(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn append(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let (mut list, sep, brackets) = match parser.arg(&mut args, 0, "list")? { let (mut list, sep, brackets) = match args.get_err(0, "list")? {
Value::List(v, sep, b) => (v, sep, b), Value::List(v, sep, b) => (v, sep, b),
v => (vec![v], ListSeparator::Space, Brackets::None), v => (vec![v], ListSeparator::Space, Brackets::None),
}; };
let val = parser.arg(&mut args, 1, "val")?; let val = args.get_err(1, "val")?;
let sep = match parser.default_arg( let sep = match args.default_arg(
&mut args,
2, 2,
"separator", "separator",
Value::String("auto".to_owned(), QuoteKind::None), Value::String("auto".to_owned(), QuoteKind::None),
@ -161,18 +160,17 @@ fn append(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn join(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn join(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(4)?; args.max_args(4)?;
let (mut list1, sep1, brackets) = match parser.arg(&mut args, 0, "list1")? { let (mut list1, sep1, brackets) = match args.get_err(0, "list1")? {
Value::List(v, sep, brackets) => (v, sep, brackets), Value::List(v, sep, brackets) => (v, sep, brackets),
Value::Map(m) => (m.as_list(), ListSeparator::Comma, Brackets::None), Value::Map(m) => (m.as_list(), ListSeparator::Comma, Brackets::None),
v => (vec![v], ListSeparator::Space, Brackets::None), v => (vec![v], ListSeparator::Space, Brackets::None),
}; };
let (list2, sep2) = match parser.arg(&mut args, 1, "list2")? { let (list2, sep2) = match args.get_err(1, "list2")? {
Value::List(v, sep, ..) => (v, sep), Value::List(v, sep, ..) => (v, sep),
Value::Map(m) => (m.as_list(), ListSeparator::Comma), Value::Map(m) => (m.as_list(), ListSeparator::Comma),
v => (vec![v], ListSeparator::Space), v => (vec![v], ListSeparator::Space),
}; };
let sep = match parser.default_arg( let sep = match args.default_arg(
&mut args,
2, 2,
"separator", "separator",
Value::String("auto".to_owned(), QuoteKind::None), Value::String("auto".to_owned(), QuoteKind::None),
@ -204,8 +202,7 @@ fn join(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
} }
}; };
let brackets = match parser.default_arg( let brackets = match args.default_arg(
&mut args,
3, 3,
"bracketed", "bracketed",
Value::String("auto".to_owned(), QuoteKind::None), Value::String("auto".to_owned(), QuoteKind::None),
@ -230,7 +227,7 @@ fn join(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn is_bracketed(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn is_bracketed(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
Ok(Value::bool(match parser.arg(&mut args, 0, "list")? { Ok(Value::bool(match args.get_err(0, "list")? {
Value::List(.., brackets) => match brackets { Value::List(.., brackets) => match brackets {
Brackets::Bracketed => true, Brackets::Bracketed => true,
Brackets::None => false, Brackets::None => false,
@ -241,8 +238,8 @@ fn is_bracketed(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
fn index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let list = parser.arg(&mut args, 0, "list")?.as_list(); let list = args.get_err(0, "list")?.as_list();
let value = parser.arg(&mut args, 1, "value")?; let value = args.get_err(1, "value")?;
// TODO: find a way to propagate any errors here // TODO: find a way to propagate any errors here
// Potential input to fuzz: index(1px 1in 1cm, 96px + 1rem) // Potential input to fuzz: index(1px 1in 1cm, 96px + 1rem)
let index = match list.into_iter().position(|v| v == value) { let index = match list.into_iter().position(|v| v == value) {
@ -253,8 +250,8 @@ fn index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
} }
fn zip(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn zip(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
let lists = parser let lists = args
.variadic_args(args)? .get_variadic()?
.into_iter() .into_iter()
.map(|x| x.node.as_list()) .map(|x| x.node.as_list())
.collect::<Vec<Vec<Value>>>(); .collect::<Vec<Vec<Value>>>();

View File

@ -10,8 +10,8 @@ use crate::{
fn map_get(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn map_get(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let key = parser.arg(&mut args, 1, "key")?; let key = args.get_err(1, "key")?;
let map = match parser.arg(&mut args, 0, "map")? { let map = match args.get_err(0, "map")? {
Value::Map(m) => m, Value::Map(m) => m,
Value::List(v, ..) if v.is_empty() => SassMap::new(), Value::List(v, ..) if v.is_empty() => SassMap::new(),
Value::ArgList(v) if v.is_empty() => SassMap::new(), Value::ArgList(v) if v.is_empty() => SassMap::new(),
@ -28,8 +28,8 @@ fn map_get(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn map_has_key(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn map_has_key(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let key = parser.arg(&mut args, 1, "key")?; let key = args.get_err(1, "key")?;
let map = match parser.arg(&mut args, 0, "map")? { let map = match args.get_err(0, "map")? {
Value::Map(m) => m, Value::Map(m) => m,
Value::List(v, ..) if v.is_empty() => SassMap::new(), Value::List(v, ..) if v.is_empty() => SassMap::new(),
Value::ArgList(v) if v.is_empty() => SassMap::new(), Value::ArgList(v) if v.is_empty() => SassMap::new(),
@ -46,7 +46,7 @@ fn map_has_key(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn map_keys(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn map_keys(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let map = match parser.arg(&mut args, 0, "map")? { let map = match args.get_err(0, "map")? {
Value::Map(m) => m, Value::Map(m) => m,
Value::List(v, ..) if v.is_empty() => SassMap::new(), Value::List(v, ..) if v.is_empty() => SassMap::new(),
Value::ArgList(v) if v.is_empty() => SassMap::new(), Value::ArgList(v) if v.is_empty() => SassMap::new(),
@ -67,7 +67,7 @@ fn map_keys(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn map_values(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn map_values(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let map = match parser.arg(&mut args, 0, "map")? { let map = match args.get_err(0, "map")? {
Value::Map(m) => m, Value::Map(m) => m,
Value::List(v, ..) if v.is_empty() => SassMap::new(), Value::List(v, ..) if v.is_empty() => SassMap::new(),
Value::ArgList(v) if v.is_empty() => SassMap::new(), Value::ArgList(v) if v.is_empty() => SassMap::new(),
@ -88,7 +88,7 @@ fn map_values(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn map_merge(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn map_merge(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let mut map1 = match parser.arg(&mut args, 0, "map1")? { let mut map1 = match args.get_err(0, "map1")? {
Value::Map(m) => m, Value::Map(m) => m,
Value::List(v, ..) if v.is_empty() => SassMap::new(), Value::List(v, ..) if v.is_empty() => SassMap::new(),
Value::ArgList(v) if v.is_empty() => SassMap::new(), Value::ArgList(v) if v.is_empty() => SassMap::new(),
@ -100,7 +100,7 @@ fn map_merge(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
let map2 = match parser.arg(&mut args, 1, "map2")? { let map2 = match args.get_err(1, "map2")? {
Value::Map(m) => m, Value::Map(m) => m,
Value::List(v, ..) if v.is_empty() => SassMap::new(), Value::List(v, ..) if v.is_empty() => SassMap::new(),
Value::ArgList(v) if v.is_empty() => SassMap::new(), Value::ArgList(v) if v.is_empty() => SassMap::new(),
@ -117,7 +117,7 @@ fn map_merge(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
} }
fn map_remove(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn map_remove(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
let mut map = match parser.arg(&mut args, 0, "map")? { let mut map = match args.get_err(0, "map")? {
Value::Map(m) => m, Value::Map(m) => m,
Value::List(v, ..) if v.is_empty() => SassMap::new(), Value::List(v, ..) if v.is_empty() => SassMap::new(),
Value::ArgList(v) if v.is_empty() => SassMap::new(), Value::ArgList(v) if v.is_empty() => SassMap::new(),
@ -129,7 +129,7 @@ fn map_remove(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
.into()) .into())
} }
}; };
let keys = parser.variadic_args(args)?; let keys = args.get_variadic()?;
for key in keys { for key in keys {
map.remove(&key); map.remove(&key);
} }

View File

@ -15,7 +15,7 @@ use crate::{
fn percentage(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn percentage(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let num = match parser.arg(&mut args, 0, "number")? { let num = match args.get_err(0, "number")? {
Value::Dimension(n, Unit::None, _) => n * Number::from(100), Value::Dimension(n, Unit::None, _) => n * Number::from(100),
v @ Value::Dimension(..) => { v @ Value::Dimension(..) => {
return Err(( return Err((
@ -40,7 +40,7 @@ fn percentage(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn round(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn round(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "number")? { match args.get_err(0, "number")? {
Value::Dimension(n, u, _) => Ok(Value::Dimension(n.round(), u, true)), Value::Dimension(n, u, _) => Ok(Value::Dimension(n.round(), u, true)),
v => Err(( v => Err((
format!("$number: {} is not a number.", v.inspect(args.span())?), format!("$number: {} is not a number.", v.inspect(args.span())?),
@ -52,7 +52,7 @@ fn round(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn ceil(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn ceil(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "number")? { match args.get_err(0, "number")? {
Value::Dimension(n, u, _) => Ok(Value::Dimension(n.ceil(), u, true)), Value::Dimension(n, u, _) => Ok(Value::Dimension(n.ceil(), u, true)),
v => Err(( v => Err((
format!("$number: {} is not a number.", v.inspect(args.span())?), format!("$number: {} is not a number.", v.inspect(args.span())?),
@ -64,7 +64,7 @@ fn ceil(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn floor(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn floor(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "number")? { match args.get_err(0, "number")? {
Value::Dimension(n, u, _) => Ok(Value::Dimension(n.floor(), u, true)), Value::Dimension(n, u, _) => Ok(Value::Dimension(n.floor(), u, true)),
v => Err(( v => Err((
format!("$number: {} is not a number.", v.inspect(args.span())?), format!("$number: {} is not a number.", v.inspect(args.span())?),
@ -76,7 +76,7 @@ fn floor(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn abs(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn abs(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "number")? { match args.get_err(0, "number")? {
Value::Dimension(n, u, _) => Ok(Value::Dimension(n.abs(), u, true)), Value::Dimension(n, u, _) => Ok(Value::Dimension(n.abs(), u, true)),
v => Err(( v => Err((
format!("$number: {} is not a number.", v.inspect(args.span())?), format!("$number: {} is not a number.", v.inspect(args.span())?),
@ -88,7 +88,7 @@ fn abs(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn comparable(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn comparable(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let unit1 = match parser.arg(&mut args, 0, "number1")? { let unit1 = match args.get_err(0, "number1")? {
Value::Dimension(_, u, _) => u, Value::Dimension(_, u, _) => u,
v => { v => {
return Err(( return Err((
@ -98,7 +98,7 @@ fn comparable(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
.into()) .into())
} }
}; };
let unit2 = match parser.arg(&mut args, 1, "number2")? { let unit2 = match args.get_err(1, "number2")? {
Value::Dimension(_, u, _) => u, Value::Dimension(_, u, _) => u,
v => { v => {
return Err(( return Err((
@ -116,7 +116,7 @@ fn comparable(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
#[cfg(feature = "random")] #[cfg(feature = "random")]
fn random(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn random(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let limit = match parser.default_arg(&mut args, 0, "limit", Value::Null)? { let limit = match args.default_arg(0, "limit", Value::Null)? {
Value::Dimension(n, ..) => n, Value::Dimension(n, ..) => n,
Value::Null => { Value::Null => {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
@ -173,8 +173,8 @@ fn random(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn min(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn min(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.min_args(1)?; args.min_args(1)?;
let span = args.span(); let span = args.span();
let mut nums = parser let mut nums = args
.variadic_args(args)? .get_variadic()?
.into_iter() .into_iter()
.map(|val| match val.node { .map(|val| match val.node {
Value::Dimension(number, unit, _) => Ok((number, unit)), Value::Dimension(number, unit, _) => Ok((number, unit)),
@ -211,8 +211,8 @@ fn min(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn max(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn max(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.min_args(1)?; args.min_args(1)?;
let span = args.span(); let span = args.span();
let mut nums = parser let mut nums = args
.variadic_args(args)? .get_variadic()?
.into_iter() .into_iter()
.map(|val| match val.node { .map(|val| match val.node {
Value::Dimension(number, unit, _) => Ok((number, unit)), Value::Dimension(number, unit, _) => Ok((number, unit)),

View File

@ -13,16 +13,16 @@ use crate::{
fn if_(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn if_(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
if parser.arg(&mut args, 0, "condition")?.is_true() { if args.get_err(0, "condition")?.is_true() {
Ok(parser.arg(&mut args, 1, "if-true")?) Ok(args.get_err(1, "if-true")?)
} else { } else {
Ok(parser.arg(&mut args, 2, "if-false")?) Ok(args.get_err(2, "if-false")?)
} }
} }
fn feature_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn feature_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "feature")? { match args.get_err(0, "feature")? {
#[allow(clippy::match_same_arms)] #[allow(clippy::match_same_arms)]
Value::String(s, _) => Ok(match s.as_str() { Value::String(s, _) => Ok(match s.as_str() {
// A local variable will shadow a global variable unless // A local variable will shadow a global variable unless
@ -52,7 +52,7 @@ fn feature_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
fn unit(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn unit(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let unit = match parser.arg(&mut args, 0, "number")? { let unit = match args.get_err(0, "number")? {
Value::Dimension(_, u, _) => u.to_string(), Value::Dimension(_, u, _) => u.to_string(),
v => { v => {
return Err(( return Err((
@ -67,14 +67,14 @@ fn unit(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn type_of(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn type_of(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
let value = parser.arg(&mut args, 0, "value")?; let value = args.get_err(0, "value")?;
Ok(Value::String(value.kind().to_owned(), QuoteKind::None)) Ok(Value::String(value.kind().to_owned(), QuoteKind::None))
} }
fn unitless(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn unitless(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
#[allow(clippy::match_same_arms)] #[allow(clippy::match_same_arms)]
Ok(match parser.arg(&mut args, 0, "number")? { Ok(match args.get_err(0, "number")? {
Value::Dimension(_, Unit::None, _) => Value::True, Value::Dimension(_, Unit::None, _) => Value::True,
Value::Dimension(..) => Value::False, Value::Dimension(..) => Value::False,
_ => Value::True, _ => Value::True,
@ -84,17 +84,14 @@ fn unitless(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn inspect(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn inspect(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
Ok(Value::String( Ok(Value::String(
parser args.get_err(0, "value")?.inspect(args.span())?.into_owned(),
.arg(&mut args, 0, "value")?
.inspect(args.span())?
.into_owned(),
QuoteKind::None, QuoteKind::None,
)) ))
} }
fn variable_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn variable_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "name")? { match args.get_err(0, "name")? {
Value::String(s, _) => Ok(Value::bool( Value::String(s, _) => Ok(Value::bool(
parser.scopes.var_exists(s.into(), parser.global_scope), parser.scopes.var_exists(s.into(), parser.global_scope),
)), )),
@ -108,7 +105,7 @@ fn variable_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Va
fn global_variable_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn global_variable_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "name")? { match args.get_err(0, "name")? {
Value::String(s, _) => Ok(Value::bool(parser.global_scope.var_exists(s.into()))), Value::String(s, _) => Ok(Value::bool(parser.global_scope.var_exists(s.into()))),
v => Err(( v => Err((
format!("$name: {} is not a string.", v.inspect(args.span())?), format!("$name: {} is not a string.", v.inspect(args.span())?),
@ -120,7 +117,7 @@ fn global_variable_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRe
fn mixin_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn mixin_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
match parser.arg(&mut args, 0, "name")? { match args.get_err(0, "name")? {
Value::String(s, _) => Ok(Value::bool( Value::String(s, _) => Ok(Value::bool(
parser.scopes.mixin_exists(s.into(), parser.global_scope), parser.scopes.mixin_exists(s.into(), parser.global_scope),
)), )),
@ -134,7 +131,7 @@ fn mixin_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
fn function_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn function_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
match parser.arg(&mut args, 0, "name")? { match args.get_err(0, "name")? {
Value::String(s, _) => Ok(Value::bool( Value::String(s, _) => Ok(Value::bool(
parser.scopes.fn_exists(s.into(), parser.global_scope), parser.scopes.fn_exists(s.into(), parser.global_scope),
)), )),
@ -148,7 +145,7 @@ fn function_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Va
fn get_function(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn get_function(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let name: Identifier = match parser.arg(&mut args, 0, "name")? { let name: Identifier = match args.get_err(0, "name")? {
Value::String(s, _) => s.into(), Value::String(s, _) => s.into(),
v => { v => {
return Err(( return Err((
@ -158,10 +155,8 @@ fn get_function(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
.into()) .into())
} }
}; };
let css = parser let css = args.default_arg(1, "css", Value::False)?.is_true();
.default_arg(&mut args, 1, "css", Value::False)? let module = match args.default_arg(2, "module", Value::Null)? {
.is_true();
let module = match parser.default_arg(&mut args, 2, "module", Value::Null)? {
Value::String(s, ..) => Some(s), Value::String(s, ..) => Some(s),
Value::Null => None, Value::Null => None,
v => { v => {
@ -199,7 +194,7 @@ fn get_function(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value
} }
fn call(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn call(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
let func = match parser.arg(&mut args, 0, "function")? { let func = match args.get_err(0, "function")? {
Value::FunctionRef(f) => f, Value::FunctionRef(f) => f,
v => { v => {
return Err(( return Err((

View File

@ -1,3 +1,6 @@
// A reference to the parser is only necessary for some functions
#![allow(unused_variables)]
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::atomic::{AtomicUsize, Ordering}, sync::atomic::{AtomicUsize, Ordering},

View File

@ -11,12 +11,10 @@ use crate::{
fn is_superselector(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn is_superselector(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let parent_selector = parser let parent_selector = args
.arg(&mut args, 0, "super")? .get_err(0, "super")?
.to_selector(parser, "super", false)?; .to_selector(parser, "super", false)?;
let child_selector = parser let child_selector = args.get_err(1, "sub")?.to_selector(parser, "sub", false)?;
.arg(&mut args, 1, "sub")?
.to_selector(parser, "sub", false)?;
Ok(Value::bool( Ok(Value::bool(
parent_selector.is_super_selector(&child_selector), parent_selector.is_super_selector(&child_selector),
@ -26,8 +24,8 @@ fn is_superselector(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
fn simple_selectors(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn simple_selectors(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
// todo: Value::to_compound_selector // todo: Value::to_compound_selector
let selector = parser let selector = args
.arg(&mut args, 0, "selector")? .get_err(0, "selector")?
.to_selector(parser, "selector", false)?; .to_selector(parser, "selector", false)?;
if selector.0.components.len() != 1 { if selector.0.components.len() != 1 {
@ -55,15 +53,15 @@ fn simple_selectors(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
fn selector_parse(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn selector_parse(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
Ok(parser Ok(args
.arg(&mut args, 0, "selector")? .get_err(0, "selector")?
.to_selector(parser, "selector", false)? .to_selector(parser, "selector", false)?
.into_value()) .into_value())
} }
fn selector_nest(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn selector_nest(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
let span = args.span(); let span = args.span();
let selectors = parser.variadic_args(args)?; let selectors = args.get_variadic()?;
if selectors.is_empty() { if selectors.is_empty() {
return Err(("$selectors: At least one selector must be passed.", span).into()); return Err(("$selectors: At least one selector must be passed.", span).into());
} }
@ -84,7 +82,7 @@ fn selector_nest(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn selector_append(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn selector_append(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
let span = args.span(); let span = args.span();
let selectors = parser.variadic_args(args)?; let selectors = args.get_variadic()?;
if selectors.is_empty() { if selectors.is_empty() {
return Err(("$selectors: At least one selector must be passed.", span).into()); return Err(("$selectors: At least one selector must be passed.", span).into());
} }
@ -142,14 +140,14 @@ fn selector_append(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn selector_extend(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn selector_extend(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let selector = parser let selector = args
.arg(&mut args, 0, "selector")? .get_err(0, "selector")?
.to_selector(parser, "selector", false)?; .to_selector(parser, "selector", false)?;
let target = parser let target = args
.arg(&mut args, 1, "extendee")? .get_err(1, "extendee")?
.to_selector(parser, "extendee", false)?; .to_selector(parser, "extendee", false)?;
let source = parser let source = args
.arg(&mut args, 2, "extender")? .get_err(2, "extender")?
.to_selector(parser, "extender", false)?; .to_selector(parser, "extender", false)?;
Ok(Extender::extend(selector.0, source.0, target.0, args.span())?.to_sass_list()) Ok(Extender::extend(selector.0, source.0, target.0, args.span())?.to_sass_list())
@ -157,25 +155,23 @@ fn selector_extend(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Va
fn selector_replace(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn selector_replace(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let selector = parser let selector = args
.arg(&mut args, 0, "selector")? .get_err(0, "selector")?
.to_selector(parser, "selector", false)?; .to_selector(parser, "selector", false)?;
let target = parser let target = args
.arg(&mut args, 1, "original")? .get_err(1, "original")?
.to_selector(parser, "original", false)?; .to_selector(parser, "original", false)?;
let source = let source = args
parser .get_err(2, "replacement")?
.arg(&mut args, 2, "replacement")? .to_selector(parser, "replacement", false)?;
.to_selector(parser, "replacement", false)?;
Ok(Extender::replace(selector.0, source.0, target.0, args.span())?.to_sass_list()) Ok(Extender::replace(selector.0, source.0, target.0, args.span())?.to_sass_list())
} }
fn selector_unify(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn selector_unify(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let selector1 = let selector1 = args
parser .get_err(0, "selector1")?
.arg(&mut args, 0, "selector1")? .to_selector(parser, "selector1", false)?;
.to_selector(parser, "selector1", false)?;
if selector1.contains_parent_selector() { if selector1.contains_parent_selector() {
return Err(( return Err((
@ -185,10 +181,9 @@ fn selector_unify(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
.into()); .into());
} }
let selector2 = let selector2 = args
parser .get_err(1, "selector2")?
.arg(&mut args, 1, "selector2")? .to_selector(parser, "selector2", false)?;
.to_selector(parser, "selector2", false)?;
if selector2.contains_parent_selector() { if selector2.contains_parent_selector() {
return Err(( return Err((

View File

@ -17,7 +17,7 @@ use crate::{
fn to_upper_case(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn to_upper_case(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "string")? { match args.get_err(0, "string")? {
Value::String(mut i, q) => { Value::String(mut i, q) => {
i.make_ascii_uppercase(); i.make_ascii_uppercase();
Ok(Value::String(i, q)) Ok(Value::String(i, q))
@ -32,7 +32,7 @@ fn to_upper_case(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Valu
fn to_lower_case(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn to_lower_case(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "string")? { match args.get_err(0, "string")? {
Value::String(mut i, q) => { Value::String(mut i, q) => {
i.make_ascii_lowercase(); i.make_ascii_lowercase();
Ok(Value::String(i, q)) Ok(Value::String(i, q))
@ -47,7 +47,7 @@ fn to_lower_case(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Valu
fn str_length(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn str_length(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "string")? { match args.get_err(0, "string")? {
Value::String(i, _) => Ok(Value::Dimension( Value::String(i, _) => Ok(Value::Dimension(
Number::from(i.chars().count()), Number::from(i.chars().count()),
Unit::None, Unit::None,
@ -63,7 +63,7 @@ fn str_length(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
fn quote(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn quote(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "string")? { match args.get_err(0, "string")? {
Value::String(i, _) => Ok(Value::String(i, QuoteKind::Quoted)), Value::String(i, _) => Ok(Value::String(i, QuoteKind::Quoted)),
v => Err(( v => Err((
format!("$string: {} is not a string.", v.inspect(args.span())?), format!("$string: {} is not a string.", v.inspect(args.span())?),
@ -75,7 +75,7 @@ fn quote(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn unquote(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn unquote(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?; args.max_args(1)?;
match parser.arg(&mut args, 0, "string")? { match args.get_err(0, "string")? {
i @ Value::String(..) => Ok(i.unquote()), i @ Value::String(..) => Ok(i.unquote()),
v => Err(( v => Err((
format!("$string: {} is not a string.", v.inspect(args.span())?), format!("$string: {} is not a string.", v.inspect(args.span())?),
@ -87,7 +87,7 @@ fn unquote(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let (string, quotes) = match parser.arg(&mut args, 0, "string")? { let (string, quotes) = match args.get_err(0, "string")? {
Value::String(s, q) => (s, q), Value::String(s, q) => (s, q),
v => { v => {
return Err(( return Err((
@ -98,7 +98,7 @@ fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
} }
}; };
let str_len = string.chars().count(); let str_len = string.chars().count();
let start = match parser.arg(&mut args, 1, "start-at")? { let start = match args.get_err(1, "start-at")? {
Value::Dimension(n, Unit::None, _) if n.is_decimal() => { Value::Dimension(n, Unit::None, _) if n.is_decimal() => {
return Err((format!("{} is not an int.", n), args.span()).into()) return Err((format!("{} is not an int.", n), args.span()).into())
} }
@ -128,7 +128,7 @@ fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
.into()) .into())
} }
}; };
let mut end = match parser.default_arg(&mut args, 2, "end-at", Value::Null)? { let mut end = match args.default_arg(2, "end-at", Value::Null)? {
Value::Dimension(n, Unit::None, _) if n.is_decimal() => { Value::Dimension(n, Unit::None, _) if n.is_decimal() => {
return Err((format!("{} is not an int.", n), args.span()).into()) return Err((format!("{} is not an int.", n), args.span()).into())
} }
@ -180,7 +180,7 @@ fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn str_index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn str_index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let s1 = match parser.arg(&mut args, 0, "string")? { let s1 = match args.get_err(0, "string")? {
Value::String(i, _) => i, Value::String(i, _) => i,
v => { v => {
return Err(( return Err((
@ -191,7 +191,7 @@ fn str_index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
} }
}; };
let substr = match parser.arg(&mut args, 1, "substring")? { let substr = match args.get_err(1, "substring")? {
Value::String(i, _) => i, Value::String(i, _) => i,
v => { v => {
return Err(( return Err((
@ -210,7 +210,7 @@ fn str_index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn str_insert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn str_insert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(3)?; args.max_args(3)?;
let (s1, quotes) = match parser.arg(&mut args, 0, "string")? { let (s1, quotes) = match args.get_err(0, "string")? {
Value::String(i, q) => (i, q), Value::String(i, q) => (i, q),
v => { v => {
return Err(( return Err((
@ -221,7 +221,7 @@ fn str_insert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
} }
}; };
let substr = match parser.arg(&mut args, 1, "insert")? { let substr = match args.get_err(1, "insert")? {
Value::String(i, _) => i, Value::String(i, _) => i,
v => { v => {
return Err(( return Err((
@ -232,7 +232,7 @@ fn str_insert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
} }
}; };
let index = match parser.arg(&mut args, 2, "index")? { let index = match args.get_err(2, "index")? {
Value::Dimension(n, Unit::None, _) if n.is_decimal() => { Value::Dimension(n, Unit::None, _) if n.is_decimal() => {
return Err((format!("$index: {} is not an int.", n), args.span()).into()) return Err((format!("$index: {} is not an int.", n), args.span()).into())
} }

View File

@ -277,80 +277,6 @@ impl<'a> Parser<'a> {
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
#[allow(clippy::unused_self)]
pub fn arg(
&self,
args: &mut CallArgs,
position: usize,
name: &'static str,
) -> SassResult<Value> {
Ok(args.get_err(position, name)?.node)
}
#[allow(clippy::unused_self)]
pub fn default_arg(
&self,
args: &mut CallArgs,
position: usize,
name: &'static str,
default: Value,
) -> SassResult<Value> {
Ok(match args.get(position, name) {
Some(val) => val?.node,
None => default,
})
}
#[allow(clippy::unused_self)]
pub fn positional_arg(
&self,
args: &mut CallArgs,
position: usize,
) -> Option<SassResult<Spanned<Value>>> {
args.get_positional(position)
}
#[allow(dead_code, clippy::unused_self)]
fn named_arg(
&self,
args: &mut CallArgs,
name: &'static str,
) -> Option<SassResult<Spanned<Value>>> {
args.get_named(name)
}
#[allow(clippy::unused_self)]
pub fn default_named_arg(
&self,
args: &mut CallArgs,
name: &'static str,
default: Value,
) -> SassResult<Value> {
Ok(match args.get_named(name) {
Some(val) => val?.node,
None => default,
})
}
#[allow(clippy::unused_self)]
pub fn variadic_args(&self, args: CallArgs) -> SassResult<Vec<Spanned<Value>>> {
let mut vals = Vec::new();
let mut args = match args
.0
.into_iter()
.map(|(a, v)| Ok((a.position()?, v)))
.collect::<Result<Vec<(usize, SassResult<Spanned<Value>>)>, String>>()
{
Ok(v) => v,
Err(e) => return Err((format!("No argument named ${}.", e), args.1).into()),
};
args.sort_by(|(a1, _), (a2, _)| a1.cmp(a2));
for arg in args {
vals.push(arg.1?);
}
Ok(vals)
}
pub(super) fn eval_args(&mut self, fn_args: FuncArgs, mut args: CallArgs) -> SassResult<Scope> { pub(super) fn eval_args(&mut self, fn_args: FuncArgs, mut args: CallArgs) -> SassResult<Scope> {
let mut scope = Scope::new(); let mut scope = Scope::new();
if fn_args.0.is_empty() { if fn_args.0.is_empty() {
@ -361,7 +287,7 @@ impl<'a> Parser<'a> {
for (idx, mut arg) in fn_args.0.into_iter().enumerate() { for (idx, mut arg) in fn_args.0.into_iter().enumerate() {
if arg.is_variadic { if arg.is_variadic {
let span = args.span(); let span = args.span();
let arg_list = Value::ArgList(self.variadic_args(args)?); let arg_list = Value::ArgList(args.get_variadic()?);
scope.insert_var( scope.insert_var(
arg.name, arg.name,
Spanned { Spanned {

View File

@ -284,9 +284,9 @@ impl<'a> Parser<'a> {
} }
"url" => match self.try_parse_url()? { "url" => match self.try_parse_url()? {
Some(val) => s = val, Some(val) => s = val,
None => s.push_str(&self.parse_call_args()?.to_css_string(self)?), None => s.push_str(&self.parse_call_args()?.to_css_string()?),
}, },
_ => s.push_str(&self.parse_call_args()?.to_css_string(self)?), _ => s.push_str(&self.parse_call_args()?.to_css_string()?),
} }
return Ok(IntermediateValue::Value(HigherIntermediateValue::Literal( return Ok(IntermediateValue::Value(HigherIntermediateValue::Literal(