From c16b8f448bd04ec7f41309bd11e28bcc38fde3ad Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Thu, 2 Apr 2020 12:07:54 -0400 Subject: [PATCH] parse variadic arguments --- src/args.rs | 40 +++++++++++++++++++++++++++++++++++----- tests/args.rs | 17 +++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 tests/args.rs diff --git a/src/args.rs b/src/args.rs index 0a56bd8..429e489 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use std::iter::Peekable; use crate::common::Pos; @@ -19,6 +19,7 @@ pub(crate) struct FuncArgs(pub Vec); pub(crate) struct FuncArg { pub name: String, pub default: Option, + pub is_variadic: bool, } impl FuncArgs { @@ -28,11 +29,11 @@ impl FuncArgs { } #[derive(Debug, Clone, std::default::Default)] -pub(crate) struct CallArgs(pub BTreeMap); +pub(crate) struct CallArgs(pub HashMap); impl CallArgs { pub fn new() -> Self { - CallArgs(BTreeMap::new()) + CallArgs(HashMap::new()) } pub fn get(&self, val: &str) -> Option<&Value> { @@ -67,6 +68,7 @@ pub(crate) fn eat_func_args>( _ => todo!(), }; let mut default: Vec = Vec::new(); + let mut is_variadic = false; devour_whitespace(toks); let kind = match toks.next() { Some(Token { kind, .. }) => kind, @@ -86,6 +88,7 @@ pub(crate) fn eat_func_args>( scope, super_selector, )?), + is_variadic, }); break; } @@ -97,6 +100,7 @@ pub(crate) fn eat_func_args>( scope, super_selector, )?), + is_variadic, }); break; } @@ -107,7 +111,31 @@ pub(crate) fn eat_func_args>( } } } - '.' => 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 { name: name.replace('_', "-"), @@ -120,12 +148,14 @@ pub(crate) fn eat_func_args>( super_selector, )?) }, + is_variadic, }); break; } ',' => args.push(FuncArg { name: name.replace('_', "-"), default: None, + is_variadic, }), _ => {} } @@ -144,7 +174,7 @@ pub(crate) fn eat_call_args>( scope: &Scope, super_selector: &Selector, ) -> SassResult { - let mut args: BTreeMap = BTreeMap::new(); + let mut args: HashMap = HashMap::new(); devour_whitespace_or_comment(toks)?; let mut name: String; let mut val: Vec = Vec::new(); diff --git a/tests/args.rs b/tests/args.rs new file mode 100644 index 0000000..b2e4d21 --- /dev/null +++ b/tests/args.rs @@ -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 \".\"." +);