use alloc::{string::String, vec, vec::Vec}; use hashbrown::HashSet; use crate::ast; use crate::error::{LexicalError, LexicalErrorType}; type ParameterDefs = (Vec, Vec); type ParameterDef = (ast::Parameter, Option); pub fn parse_params( params: (Vec, Vec), ) -> Result { let mut names = vec![]; let mut defaults = vec![]; let mut try_default = |name: &ast::Parameter, default| { if let Some(default) = default { defaults.push(default); } else if !defaults.is_empty() { // Once we have started with defaults, all remaining arguments must // have defaults return Err(LexicalError { error: LexicalErrorType::DefaultArgumentError, location: name.location, }); } Ok(()) }; for (name, default) in params.0 { try_default(&name, default)?; names.push(name); } for (name, default) in params.1 { try_default(&name, default)?; names.push(name); } Ok((names, defaults)) } type FunctionArgument = (Option>, ast::Expression); pub fn parse_args(func_args: Vec) -> Result { let mut args = vec![]; let mut keywords = vec![]; let mut keyword_names = HashSet::with_capacity_and_hasher(func_args.len(), ahash::RandomState::default()); for (name, value) in func_args { match name { Some(n) => { if let Some(keyword_name) = n.clone() { if keyword_names.contains(&keyword_name) { return Err(LexicalError { error: LexicalErrorType::DuplicateKeywordArgumentError, location: value.location, }); } keyword_names.insert(keyword_name.clone()); } keywords.push(ast::Keyword { name: n, value }); } None => { // Allow starred args after keyword arguments. if !keywords.is_empty() && !is_starred(&value) { return Err(LexicalError { error: LexicalErrorType::PositionalArgumentError, location: value.location, }); } args.push(value); } } } Ok(ast::ArgumentList { args, keywords }) } fn is_starred(exp: &ast::Expression) -> bool { matches!(exp.node, ast::ExpressionType::Starred { .. }) }