eagerly evaluate call args

This commit is contained in:
Connor Skees 2020-07-02 16:32:43 -04:00
parent 125c85a69c
commit 927faf30c6
2 changed files with 29 additions and 38 deletions

View File

@ -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) {

View File

@ -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()