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),
|
Positional(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CallArg {
|
||||||
|
pub fn position(&self) -> SassResult<usize> {
|
||||||
|
match self {
|
||||||
|
Self::Named(..) => todo!(),
|
||||||
|
Self::Positional(p) => Ok(*p),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CallArgs {
|
impl CallArgs {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
CallArgs(HashMap::new())
|
CallArgs(HashMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn get_named(&self, val: String) -> Option<&Value> {
|
pub fn get_named(&self, val: String) -> Option<&Value> {
|
||||||
self.0.get(&CallArg::Named(val))
|
self.0.get(&CallArg::Named(val))
|
||||||
}
|
}
|
||||||
@ -50,6 +60,20 @@ impl CallArgs {
|
|||||||
self.0.get(&CallArg::Positional(val))
|
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 {
|
pub fn len(&self) -> usize {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,12 @@ impl Function {
|
|||||||
Ok((name, Function::new(scope, args, body)))
|
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() {
|
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) {
|
let val = match args.remove_positional(idx) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => match args.remove_named(arg.name.clone()) {
|
None => match args.remove_named(arg.name.clone()) {
|
||||||
|
@ -59,8 +59,12 @@ impl Mixin {
|
|||||||
self
|
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() {
|
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) {
|
let val = match args.remove_positional(idx) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => match args.remove_named(arg.name.clone()) {
|
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 has_include = false;
|
||||||
|
|
||||||
let mut args = if let Some(tok) = toks.next() {
|
let args = if let Some(tok) = toks.next() {
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
';' => CallArgs::new(),
|
';' => CallArgs::new(),
|
||||||
'(' => {
|
'(' => {
|
||||||
@ -170,9 +174,6 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
let mixin = scope.get_mixin(&name)?.clone();
|
let mixin = scope.get_mixin(&name)?.clone();
|
||||||
|
|
||||||
let rules = mixin
|
let rules = mixin.args(args)?.content(content).call(super_selector)?;
|
||||||
.args(&mut args)?
|
|
||||||
.content(content)
|
|
||||||
.call(super_selector)?;
|
|
||||||
Ok(rules)
|
Ok(rules)
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ pub(crate) enum Value {
|
|||||||
Paren(Box<Value>),
|
Paren(Box<Value>),
|
||||||
Ident(String, QuoteKind),
|
Ident(String, QuoteKind),
|
||||||
Map(SassMap),
|
Map(SassMap),
|
||||||
|
ArgList(Vec<Value>),
|
||||||
// Returned by `get-function()`
|
// Returned by `get-function()`
|
||||||
// Function(String)
|
// Function(String)
|
||||||
}
|
}
|
||||||
@ -120,6 +121,15 @@ impl Display for Value {
|
|||||||
Self::True => write!(f, "true"),
|
Self::True => write!(f, "true"),
|
||||||
Self::False => write!(f, "false"),
|
Self::False => write!(f, "false"),
|
||||||
Self::Null => write!(f, "null"),
|
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::Dimension(..) => Ok("number"),
|
||||||
Self::List(..) => Ok("list"),
|
Self::List(..) => Ok("list"),
|
||||||
// Self::Function(..) => Ok("function"),
|
// Self::Function(..) => Ok("function"),
|
||||||
|
Self::ArgList(..) => Ok("arglist"),
|
||||||
Self::True | Self::False => Ok("bool"),
|
Self::True | Self::False => Ok("bool"),
|
||||||
Self::Null => Ok("null"),
|
Self::Null => Ok("null"),
|
||||||
Self::Map(..) => Ok("map"),
|
Self::Map(..) => Ok("map"),
|
||||||
|
@ -14,7 +14,7 @@ impl Add for Value {
|
|||||||
}
|
}
|
||||||
let precedence = Op::Plus.precedence();
|
let precedence = Op::Plus.precedence();
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Self::Map(..) => todo!(),
|
Self::ArgList(..) | Self::Map(..) => todo!(),
|
||||||
Self::Important | Self::True | Self::False => match other {
|
Self::Important | Self::True | Self::False => match other {
|
||||||
Self::Ident(s, QuoteKind::Double) | Self::Ident(s, QuoteKind::Single) => {
|
Self::Ident(s, QuoteKind::Double) | Self::Ident(s, QuoteKind::Single) => {
|
||||||
Value::Ident(format!("{}{}", self, s), QuoteKind::Double)
|
Value::Ident(format!("{}{}", self, s), QuoteKind::Double)
|
||||||
@ -86,7 +86,7 @@ impl Add for Value {
|
|||||||
Self::List(..) => Value::Ident(format!("{}{}", s1, other), quotes1),
|
Self::List(..) => Value::Ident(format!("{}{}", s1, other), quotes1),
|
||||||
Self::UnaryOp(..) | Self::BinaryOp(..) => todo!(),
|
Self::UnaryOp(..) | Self::BinaryOp(..) => todo!(),
|
||||||
Self::Paren(..) => (Self::Ident(s1, quotes1) + other.eval()?)?,
|
Self::Paren(..) => (Self::Ident(s1, quotes1) + other.eval()?)?,
|
||||||
Self::Map(..) => todo!(),
|
Self::ArgList(..) | Self::Map(..) => todo!(),
|
||||||
},
|
},
|
||||||
Self::List(..) => match other {
|
Self::List(..) => match other {
|
||||||
Self::Ident(s, q) => Value::Ident(format!("{}{}", self, s), q.normalize()),
|
Self::Ident(s, q) => Value::Ident(format!("{}{}", self, s), q.normalize()),
|
||||||
|
@ -406,7 +406,7 @@ impl Value {
|
|||||||
};
|
};
|
||||||
Ok(IntermediateValue::Value(
|
Ok(IntermediateValue::Value(
|
||||||
func.clone()
|
func.clone()
|
||||||
.args(&mut eat_call_args(toks, scope, super_selector)?)?
|
.args(eat_call_args(toks, scope, super_selector)?)?
|
||||||
.call(super_selector, func.body())?,
|
.call(super_selector, func.body())?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -15,3 +15,13 @@ error!(
|
|||||||
varargs_two_periods,
|
varargs_two_periods,
|
||||||
"@function foo($a..) {\n @return $a;\n}\n", "Error: expected \".\"."
|
"@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: type-of(hi + bye)\n}\n",
|
||||||
"a {\n color: string;\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!(
|
test!(
|
||||||
unitless_px,
|
unitless_px,
|
||||||
"a {\n color: unitless(1px)\n}\n",
|
"a {\n color: unitless(1px)\n}\n",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user