eagerly evaluate call args
This commit is contained in:
parent
125c85a69c
commit
927faf30c6
11
src/args.rs
11
src/args.rs
@ -6,6 +6,7 @@ use crate::{
|
|||||||
common::Identifier,
|
common::Identifier,
|
||||||
error::SassResult,
|
error::SassResult,
|
||||||
parse::Parser,
|
parse::Parser,
|
||||||
|
value::Value,
|
||||||
{Cow, Token},
|
{Cow, Token},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ impl FuncArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct CallArgs(pub HashMap<CallArg, Vec<Token>>, pub Span);
|
pub(crate) struct CallArgs(pub HashMap<CallArg, Spanned<Value>>, pub Span);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub(crate) enum CallArg {
|
pub(crate) enum CallArg {
|
||||||
@ -100,25 +101,25 @@ impl CallArgs {
|
|||||||
/// Get argument by name
|
/// Get argument by name
|
||||||
///
|
///
|
||||||
/// Removes the argument
|
/// Removes the argument
|
||||||
pub fn get_named<T: Into<Identifier>>(&mut self, val: T) -> Option<Vec<Token>> {
|
pub fn get_named<T: Into<Identifier>>(&mut self, val: T) -> Option<Spanned<Value>> {
|
||||||
self.0.remove(&CallArg::Named(val.into()))
|
self.0.remove(&CallArg::Named(val.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a positional argument by 0-indexed position
|
/// Get a positional argument by 0-indexed position
|
||||||
///
|
///
|
||||||
/// Removes the argument
|
/// Removes the argument
|
||||||
pub fn get_positional(&mut self, val: usize) -> Option<Vec<Token>> {
|
pub fn get_positional(&mut self, val: usize) -> Option<Spanned<Value>> {
|
||||||
self.0.remove(&CallArg::Positional(val))
|
self.0.remove(&CallArg::Positional(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<T: Into<Identifier>>(&mut self, position: usize, name: T) -> Option<Vec<Token>> {
|
pub fn get<T: Into<Identifier>>(&mut self, position: usize, name: T) -> Option<Spanned<Value>> {
|
||||||
match self.get_named(name) {
|
match self.get_named(name) {
|
||||||
Some(v) => Some(v),
|
Some(v) => Some(v),
|
||||||
None => self.get_positional(position),
|
None => self.get_positional(position),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_err(&mut self, position: usize, name: &'static str) -> SassResult<Vec<Token>> {
|
pub fn get_err(&mut self, position: usize, name: &'static str) -> SassResult<Spanned<Value>> {
|
||||||
match self.get_named(name) {
|
match self.get_named(name) {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => match self.get_positional(position) {
|
None => match self.get_positional(position) {
|
||||||
|
@ -125,7 +125,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn parse_call_args(&mut self) -> SassResult<CallArgs> {
|
pub(super) fn parse_call_args(&mut self) -> SassResult<CallArgs> {
|
||||||
let mut args: HashMap<CallArg, Vec<Token>> = HashMap::new();
|
let mut args = HashMap::new();
|
||||||
self.whitespace_or_comment();
|
self.whitespace_or_comment();
|
||||||
let mut name = String::new();
|
let mut name = String::new();
|
||||||
let mut val: Vec<Token> = Vec::new();
|
let mut val: Vec<Token> = Vec::new();
|
||||||
@ -176,7 +176,10 @@ impl<'a> Parser<'a> {
|
|||||||
} else {
|
} else {
|
||||||
CallArg::Named(name.into())
|
CallArg::Named(name.into())
|
||||||
},
|
},
|
||||||
val,
|
{
|
||||||
|
let val = self.parse_value_from_vec(val)?;
|
||||||
|
val.node.eval(val.span)?
|
||||||
|
},
|
||||||
);
|
);
|
||||||
span = span.merge(tok.pos());
|
span = span.merge(tok.pos());
|
||||||
return Ok(CallArgs(args, span));
|
return Ok(CallArgs(args, span));
|
||||||
@ -204,7 +207,10 @@ impl<'a> Parser<'a> {
|
|||||||
} else {
|
} else {
|
||||||
CallArg::Named(name.as_str().into())
|
CallArg::Named(name.as_str().into())
|
||||||
},
|
},
|
||||||
mem::take(&mut val),
|
{
|
||||||
|
let val = self.parse_value_from_vec(mem::take(&mut val))?;
|
||||||
|
val.node.eval(val.span)?
|
||||||
|
},
|
||||||
);
|
);
|
||||||
self.whitespace();
|
self.whitespace();
|
||||||
|
|
||||||
@ -222,11 +228,7 @@ impl<'a> Parser<'a> {
|
|||||||
position: usize,
|
position: usize,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> SassResult<Value> {
|
) -> SassResult<Value> {
|
||||||
Ok(self
|
Ok(args.get_err(position, name)?.node)
|
||||||
.parse_value_from_vec(args.get_err(position, name)?)?
|
|
||||||
.node
|
|
||||||
.eval(args.span())?
|
|
||||||
.node)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_arg(
|
pub fn default_arg(
|
||||||
@ -237,12 +239,7 @@ impl<'a> Parser<'a> {
|
|||||||
default: Value,
|
default: Value,
|
||||||
) -> SassResult<Value> {
|
) -> SassResult<Value> {
|
||||||
Ok(match args.get(position, name) {
|
Ok(match args.get(position, name) {
|
||||||
Some(toks) => {
|
Some(val) => val.node,
|
||||||
self.parse_value_from_vec(toks)?
|
|
||||||
.node
|
|
||||||
.eval(args.span())?
|
|
||||||
.node
|
|
||||||
}
|
|
||||||
None => default,
|
None => default,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -251,17 +248,13 @@ impl<'a> Parser<'a> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
args: &mut CallArgs,
|
args: &mut CallArgs,
|
||||||
position: usize,
|
position: usize,
|
||||||
) -> Option<SassResult<Spanned<Value>>> {
|
) -> Option<Spanned<Value>> {
|
||||||
Some(self.parse_value_from_vec(args.get_positional(position)?))
|
args.get_positional(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn named_arg(
|
fn named_arg(&mut self, args: &mut CallArgs, name: &'static str) -> Option<Spanned<Value>> {
|
||||||
&mut self,
|
args.get_named(name)
|
||||||
args: &mut CallArgs,
|
|
||||||
name: &'static str,
|
|
||||||
) -> Option<SassResult<Spanned<Value>>> {
|
|
||||||
Some(self.parse_value_from_vec(args.get_named(name)?))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_named_arg(
|
pub fn default_named_arg(
|
||||||
@ -271,31 +264,25 @@ impl<'a> Parser<'a> {
|
|||||||
default: Value,
|
default: Value,
|
||||||
) -> SassResult<Value> {
|
) -> SassResult<Value> {
|
||||||
Ok(match args.get_named(name) {
|
Ok(match args.get_named(name) {
|
||||||
Some(toks) => {
|
Some(val) => val.node,
|
||||||
self.parse_value_from_vec(toks)?
|
|
||||||
.node
|
|
||||||
.eval(args.span())?
|
|
||||||
.node
|
|
||||||
}
|
|
||||||
None => default,
|
None => default,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variadic_args(&mut self, args: CallArgs) -> SassResult<Vec<Spanned<Value>>> {
|
pub fn variadic_args(&mut self, args: CallArgs) -> SassResult<Vec<Spanned<Value>>> {
|
||||||
let mut vals = Vec::new();
|
let mut vals = Vec::new();
|
||||||
let span = args.span();
|
|
||||||
let mut args = match args
|
let mut args = match args
|
||||||
.0
|
.0
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(a, v)| Ok((a.position()?, v)))
|
.map(|(a, v)| Ok((a.position()?, v)))
|
||||||
.collect::<Result<Vec<(usize, Vec<Token>)>, String>>()
|
.collect::<Result<Vec<(usize, Spanned<Value>)>, String>>()
|
||||||
{
|
{
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => return Err((format!("No argument named ${}.", e), args.1).into()),
|
Err(e) => return Err((format!("No argument named ${}.", e), args.1).into()),
|
||||||
};
|
};
|
||||||
args.sort_by(|(a1, _), (a2, _)| a1.cmp(a2));
|
args.sort_by(|(a1, _), (a2, _)| a1.cmp(a2));
|
||||||
for arg in args {
|
for arg in args {
|
||||||
vals.push(self.parse_value_from_vec(arg.1)?.node.eval(span)?);
|
vals.push(arg.1);
|
||||||
}
|
}
|
||||||
Ok(vals)
|
Ok(vals)
|
||||||
}
|
}
|
||||||
@ -322,9 +309,12 @@ impl<'a> Parser<'a> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let val = match args.get(idx, arg.name.clone()) {
|
let val = match args.get(idx, arg.name.clone()) {
|
||||||
Some(v) => self.parse_value_from_vec(v)?,
|
Some(v) => v,
|
||||||
None => match arg.default.as_mut() {
|
None => match arg.default.as_mut() {
|
||||||
Some(v) => self.parse_value_from_vec(mem::take(v))?,
|
Some(v) => {
|
||||||
|
let val = self.parse_value_from_vec(mem::take(v))?;
|
||||||
|
val.node.eval(val.span)?
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
return Err(
|
return Err(
|
||||||
(format!("Missing argument ${}.", &arg.name), args.span()).into()
|
(format!("Missing argument ${}.", &arg.name), args.span()).into()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user