parse variadic arguments

This commit is contained in:
ConnorSkees 2020-04-02 12:07:54 -04:00
parent b440258027
commit c16b8f448b
2 changed files with 52 additions and 5 deletions

View File

@ -1,4 +1,4 @@
use std::collections::BTreeMap; use std::collections::HashMap;
use std::iter::Peekable; use std::iter::Peekable;
use crate::common::Pos; use crate::common::Pos;
@ -19,6 +19,7 @@ pub(crate) struct FuncArgs(pub Vec<FuncArg>);
pub(crate) struct FuncArg { pub(crate) struct FuncArg {
pub name: String, pub name: String,
pub default: Option<Value>, pub default: Option<Value>,
pub is_variadic: bool,
} }
impl FuncArgs { impl FuncArgs {
@ -28,11 +29,11 @@ impl FuncArgs {
} }
#[derive(Debug, Clone, std::default::Default)] #[derive(Debug, Clone, std::default::Default)]
pub(crate) struct CallArgs(pub BTreeMap<String, Value>); pub(crate) struct CallArgs(pub HashMap<String, Value>);
impl CallArgs { impl CallArgs {
pub fn new() -> Self { pub fn new() -> Self {
CallArgs(BTreeMap::new()) CallArgs(HashMap::new())
} }
pub fn get(&self, val: &str) -> Option<&Value> { pub fn get(&self, val: &str) -> Option<&Value> {
@ -67,6 +68,7 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
_ => todo!(), _ => todo!(),
}; };
let mut default: Vec<Token> = Vec::new(); let mut default: Vec<Token> = Vec::new();
let mut is_variadic = false;
devour_whitespace(toks); devour_whitespace(toks);
let kind = match toks.next() { let kind = match toks.next() {
Some(Token { kind, .. }) => kind, Some(Token { kind, .. }) => kind,
@ -86,6 +88,7 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
scope, scope,
super_selector, super_selector,
)?), )?),
is_variadic,
}); });
break; break;
} }
@ -97,6 +100,7 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
scope, scope,
super_selector, super_selector,
)?), )?),
is_variadic,
}); });
break; break;
} }
@ -107,7 +111,31 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
} }
} }
} }
'.' => todo!("handle varargs"), '.' => {
if toks.next().ok_or("expected \".\".")?.kind != '.' {
return Err("expected \".\".".into());
}
if toks.next().ok_or("expected \".\".")?.kind != '.' {
return Err("expected \".\".".into());
}
devour_whitespace(toks);
if toks.next().ok_or("expected \")\".")?.kind != ')' {
return Err("expected \")\".".into());
}
is_variadic = true;
args.push(FuncArg {
name: name.replace('_', "-"),
default: Some(Value::from_tokens(
&mut default.into_iter().peekable(),
scope,
super_selector,
)?),
is_variadic,
});
break;
}
')' => { ')' => {
args.push(FuncArg { args.push(FuncArg {
name: name.replace('_', "-"), name: name.replace('_', "-"),
@ -120,12 +148,14 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
super_selector, super_selector,
)?) )?)
}, },
is_variadic,
}); });
break; break;
} }
',' => args.push(FuncArg { ',' => args.push(FuncArg {
name: name.replace('_', "-"), name: name.replace('_', "-"),
default: None, default: None,
is_variadic,
}), }),
_ => {} _ => {}
} }
@ -144,7 +174,7 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
scope: &Scope, scope: &Scope,
super_selector: &Selector, super_selector: &Selector,
) -> SassResult<CallArgs> { ) -> SassResult<CallArgs> {
let mut args: BTreeMap<String, Value> = BTreeMap::new(); let mut args: HashMap<String, Value> = HashMap::new();
devour_whitespace_or_comment(toks)?; devour_whitespace_or_comment(toks)?;
let mut name: String; let mut name: String;
let mut val: Vec<Token> = Vec::new(); let mut val: Vec<Token> = Vec::new();

17
tests/args.rs Normal file
View File

@ -0,0 +1,17 @@
#![cfg(test)]
#[macro_use]
mod macros;
error!(
variable_after_varargs,
"@function foo($a..., $b) {\n @return $a;\n}\n", "Error: expected \")\"."
);
error!(
varargs_one_period,
"@function foo($a.) {\n @return $a;\n}\n", "Error: expected \".\"."
);
error!(
varargs_two_periods,
"@function foo($a..) {\n @return $a;\n}\n", "Error: expected \".\"."
);