diff --git a/src/function.rs b/src/function.rs index 4a90ada..d6a3a53 100644 --- a/src/function.rs +++ b/src/function.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::iter::Peekable; use crate::common::Symbol; @@ -19,8 +20,8 @@ impl FuncArgs { } } -#[derive(Debug, Clone)] -pub struct CallArgs(pub Vec); +#[derive(Debug, Clone, std::default::Default)] +pub struct CallArgs(pub BTreeMap); #[derive(Debug, Clone)] pub struct CallArg { @@ -35,13 +36,17 @@ impl CallArg { } impl CallArgs { - pub const fn new() -> Self { - CallArgs(Vec::new()) + pub fn new() -> Self { + CallArgs(BTreeMap::new()) } pub fn is_empty(&self) -> bool { self.0.is_empty() } + + pub fn get(&self, val: &str) -> Option<&CallArg> { + self.0.get(val) + } } pub fn eat_func_args>(toks: &mut Peekable) -> FuncArgs { @@ -54,27 +59,48 @@ pub fn eat_func_args>(toks: &mut Peekable) -> FuncA TokenKind::Symbol(Symbol::CloseParen) => break, _ => todo!(), }; + let mut default: Vec = Vec::new(); devour_whitespace(toks); - let kind = if let Some(Token { kind, .. }) = toks.next() { - kind - } else { - todo!() + let kind = match toks.next() { + Some(Token { kind, .. }) => kind, + _ => todo!("unexpected eof"), }; match kind { TokenKind::Symbol(Symbol::Colon) => { - todo!("handle default values") - // let mut val: Vec = Vec::new(); - // while let Some(tok) = toks.next() { - // match &kind { - // _ => val.push(tok), - // } - // } + devour_whitespace(toks); + while let Some(tok) = toks.peek() { + match &tok.kind { + TokenKind::Symbol(Symbol::Comma) => { + toks.next(); + args.push(FuncArg { + name, + default: Some(default), + }); + break; + } + TokenKind::Symbol(Symbol::CloseParen) => { + args.push(FuncArg { + name, + default: Some(default), + }); + break; + } + _ => { + let tok = toks.next().expect("we know this exists!"); + default.push(tok) + } + } + } } TokenKind::Symbol(Symbol::Period) => todo!("handle varargs"), TokenKind::Symbol(Symbol::CloseParen) => { args.push(FuncArg { name, - default: None, + default: if default.is_empty() { + None + } else { + Some(default) + }, }); break; } @@ -99,7 +125,7 @@ pub fn eat_func_args>(toks: &mut Peekable) -> FuncA } pub fn eat_call_args>(toks: &mut Peekable) -> CallArgs { - let mut args: Vec = Vec::new(); + let mut args: BTreeMap = BTreeMap::new(); devour_whitespace(toks); let mut name: Option = None; let mut val = Vec::new(); @@ -116,14 +142,31 @@ pub fn eat_call_args>(toks: &mut Peekable) -> CallA // } } TokenKind::Symbol(Symbol::CloseParen) => { - args.push(CallArg { name, val }); + if name.is_some() { + args.insert(name.clone().unwrap(), CallArg { name, val }); + } else { + args.insert(format!("{}", args.len()), CallArg { name, val }); + } break; } TokenKind::Symbol(Symbol::Comma) => { - args.push(CallArg { - name: name.clone(), - val: val.clone(), - }); + if name.is_some() { + args.insert( + name.clone().unwrap(), + CallArg { + name: name.clone(), + val: val.clone(), + }, + ); + } else { + args.insert( + format!("{}", args.len()), + CallArg { + name: name.clone(), + val: val.clone(), + }, + ); + } if let Some(ref mut s) = name { s.clear(); } diff --git a/src/mixin.rs b/src/mixin.rs index 479ea73..7c9e2be 100644 --- a/src/mixin.rs +++ b/src/mixin.rs @@ -75,20 +75,15 @@ impl Mixin { } pub fn args(mut self, args: &CallArgs) -> Mixin { - for (idx, arg) in args.0.iter().enumerate() { - if arg.is_named() { - todo!("keyword args") - } else { - self.scope.vars.insert( - self.args - .0 - .get(idx) - .expect("too many args passed to mixin") - .name - .clone(), - arg.val.clone(), - ); - } + for (idx, arg) in self.args.0.iter().enumerate() { + let val = match args.get(&format!("{}", idx)) { + Some(v) => v.val.clone(), + None => match args.get(&arg.name) { + Some(v) => v.val.clone(), + None => arg.default.clone().expect("missing variable!"), + }, + }; + self.scope.vars.insert(arg.name.clone(), val); } self }