initial implementation of varargs
This commit is contained in:
parent
f9fc0ed8cb
commit
39031aefff
24
src/args.rs
24
src/args.rs
@ -37,11 +37,21 @@ enum CallArg {
|
||||
Positional(usize),
|
||||
}
|
||||
|
||||
impl CallArg {
|
||||
pub fn position(&self) -> SassResult<usize> {
|
||||
match self {
|
||||
Self::Named(..) => todo!(),
|
||||
Self::Positional(p) => Ok(*p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CallArgs {
|
||||
pub fn new() -> Self {
|
||||
CallArgs(HashMap::new())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_named(&self, val: String) -> Option<&Value> {
|
||||
self.0.get(&CallArg::Named(val))
|
||||
}
|
||||
@ -50,6 +60,20 @@ impl CallArgs {
|
||||
self.0.get(&CallArg::Positional(val))
|
||||
}
|
||||
|
||||
pub fn get_variadic(self) -> SassResult<Value> {
|
||||
let mut vals = Vec::new();
|
||||
let mut args = self
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|(a, v)| Ok((a.position()?, v)))
|
||||
.collect::<SassResult<Vec<(usize, Value)>>>()?;
|
||||
args.sort_by(|(a1, _), (a2, _)| a1.cmp(a2));
|
||||
for arg in args {
|
||||
vals.push(arg.1);
|
||||
}
|
||||
Ok(Value::ArgList(vals))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
@ -43,8 +43,12 @@ impl Function {
|
||||
Ok((name, Function::new(scope, args, body)))
|
||||
}
|
||||
|
||||
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Function> {
|
||||
pub fn args(mut self, mut args: CallArgs) -> SassResult<Function> {
|
||||
for (idx, arg) in self.args.0.iter().enumerate() {
|
||||
if arg.is_variadic {
|
||||
self.scope.insert_var(&arg.name, args.get_variadic()?)?;
|
||||
break;
|
||||
}
|
||||
let val = match args.remove_positional(idx) {
|
||||
Some(v) => v,
|
||||
None => match args.remove_named(arg.name.clone()) {
|
||||
|
@ -59,8 +59,12 @@ impl Mixin {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Mixin> {
|
||||
pub fn args(mut self, mut args: CallArgs) -> SassResult<Mixin> {
|
||||
for (idx, arg) in self.args.0.iter().enumerate() {
|
||||
if arg.is_variadic {
|
||||
self.scope.insert_var(&arg.name, args.get_variadic()?)?;
|
||||
break;
|
||||
}
|
||||
let val = match args.remove_positional(idx) {
|
||||
Some(v) => v,
|
||||
None => match args.remove_named(arg.name.clone()) {
|
||||
@ -128,7 +132,7 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
||||
|
||||
let mut has_include = false;
|
||||
|
||||
let mut args = if let Some(tok) = toks.next() {
|
||||
let args = if let Some(tok) = toks.next() {
|
||||
match tok.kind {
|
||||
';' => CallArgs::new(),
|
||||
'(' => {
|
||||
@ -170,9 +174,6 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
||||
|
||||
let mixin = scope.get_mixin(&name)?.clone();
|
||||
|
||||
let rules = mixin
|
||||
.args(&mut args)?
|
||||
.content(content)
|
||||
.call(super_selector)?;
|
||||
let rules = mixin.args(args)?.content(content).call(super_selector)?;
|
||||
Ok(rules)
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ pub(crate) enum Value {
|
||||
Paren(Box<Value>),
|
||||
Ident(String, QuoteKind),
|
||||
Map(SassMap),
|
||||
ArgList(Vec<Value>),
|
||||
// Returned by `get-function()`
|
||||
// Function(String)
|
||||
}
|
||||
@ -120,6 +121,15 @@ impl Display for Value {
|
||||
Self::True => write!(f, "true"),
|
||||
Self::False => write!(f, "false"),
|
||||
Self::Null => write!(f, "null"),
|
||||
Self::ArgList(args) => write!(
|
||||
f,
|
||||
"{}",
|
||||
args.iter()
|
||||
.filter(|x| !x.is_null())
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,6 +167,7 @@ impl Value {
|
||||
Self::Dimension(..) => Ok("number"),
|
||||
Self::List(..) => Ok("list"),
|
||||
// Self::Function(..) => Ok("function"),
|
||||
Self::ArgList(..) => Ok("arglist"),
|
||||
Self::True | Self::False => Ok("bool"),
|
||||
Self::Null => Ok("null"),
|
||||
Self::Map(..) => Ok("map"),
|
||||
|
@ -14,7 +14,7 @@ impl Add for Value {
|
||||
}
|
||||
let precedence = Op::Plus.precedence();
|
||||
Ok(match self {
|
||||
Self::Map(..) => todo!(),
|
||||
Self::ArgList(..) | Self::Map(..) => todo!(),
|
||||
Self::Important | Self::True | Self::False => match other {
|
||||
Self::Ident(s, QuoteKind::Double) | Self::Ident(s, QuoteKind::Single) => {
|
||||
Value::Ident(format!("{}{}", self, s), QuoteKind::Double)
|
||||
@ -86,7 +86,7 @@ impl Add for Value {
|
||||
Self::List(..) => Value::Ident(format!("{}{}", s1, other), quotes1),
|
||||
Self::UnaryOp(..) | Self::BinaryOp(..) => todo!(),
|
||||
Self::Paren(..) => (Self::Ident(s1, quotes1) + other.eval()?)?,
|
||||
Self::Map(..) => todo!(),
|
||||
Self::ArgList(..) | Self::Map(..) => todo!(),
|
||||
},
|
||||
Self::List(..) => match other {
|
||||
Self::Ident(s, q) => Value::Ident(format!("{}{}", self, s), q.normalize()),
|
||||
|
@ -406,7 +406,7 @@ impl Value {
|
||||
};
|
||||
Ok(IntermediateValue::Value(
|
||||
func.clone()
|
||||
.args(&mut eat_call_args(toks, scope, super_selector)?)?
|
||||
.args(eat_call_args(toks, scope, super_selector)?)?
|
||||
.call(super_selector, func.body())?,
|
||||
))
|
||||
}
|
||||
|
@ -15,3 +15,13 @@ error!(
|
||||
varargs_two_periods,
|
||||
"@function foo($a..) {\n @return $a;\n}\n", "Error: expected \".\"."
|
||||
);
|
||||
test!(
|
||||
mixin_varargs_are_comma_separated,
|
||||
"@mixin foo($a...) {\n color: $a;\n}\n\na {\n @include foo(1, 2, 3, 4, 5);\n}\n",
|
||||
"a {\n color: 1, 2, 3, 4, 5;\n}\n"
|
||||
);
|
||||
test!(
|
||||
function_varargs_are_comma_separated,
|
||||
"@function foo($a...) {\n @return $a;\n}\n\na {\n color: foo(1, 2, 3, 4, 5);\n}\n",
|
||||
"a {\n color: 1, 2, 3, 4, 5;\n}\n"
|
||||
);
|
||||
|
@ -164,6 +164,11 @@ test!(
|
||||
"a {\n color: type-of(hi + bye)\n}\n",
|
||||
"a {\n color: string;\n}\n"
|
||||
);
|
||||
test!(
|
||||
type_of_arglist,
|
||||
"@mixin foo($a...) {color: type-of($a);}\na {@include foo(1, 2, 3, 4, 5);}",
|
||||
"a {\n color: arglist;\n}\n"
|
||||
);
|
||||
test!(
|
||||
unitless_px,
|
||||
"a {\n color: unitless(1px)\n}\n",
|
||||
|
Loading…
x
Reference in New Issue
Block a user