use crate::arena::ArenaVec; use crate::ast::{AstSpan, Parameter, ParameterModifier, ParameterModifierKind, ParameterRef}; use crate::lexer::{Keyword, Token}; use crate::parser::{ParseErrorKind, ResultRecoveryExt, SyncLevel}; impl<'src, 'arena> crate::parser::Parser<'src, 'arena> { // allowed to switch to result returning pub(crate) fn parse_parameter_list(&mut self) -> ArenaVec<'arena, ParameterRef<'src, 'arena>> { let mut params = self.arena.vec(); if matches!(self.peek_token(), Some(Token::RightParenthesis)) { return params; } loop { let start_pos = self.last_consumed_position_or_start(); let mut modifiers = self.arena.vec(); while let Some((next_keyword, next_position)) = self.peek_keyword_and_position() { match next_keyword { Keyword::Optional => { modifiers.push(ParameterModifier { kind: ParameterModifierKind::Optional, position: next_position, }); self.advance(); } Keyword::Out => { modifiers.push(ParameterModifier { kind: ParameterModifierKind::Out, position: next_position, }); self.advance(); } Keyword::Coerce => { modifiers.push(ParameterModifier { kind: ParameterModifierKind::Coerce, position: next_position, }); self.advance(); } Keyword::Skip => { modifiers.push(ParameterModifier { kind: ParameterModifierKind::Skip, position: next_position, }); self.advance(); } _ => break, } } let type_spec = match self.parse_type_specifier() { Ok(t) => t, Err(e) => { self.report_error(e); self.recover_until(SyncLevel::ListSeparator); if self.eat(Token::Comma) { continue; } break; } }; let name = self .parse_identifier(ParseErrorKind::ParamMissingIdentifier) .unwrap_or_fallback(self); let array_len = match self.parse_array_len_expr() { Ok(v) => v, Err(e) => { self.report_error(e); self.recover_until(SyncLevel::CloseBracket); let _ = self.eat(Token::RightBracket); None } }; let default_value = if self.eat(Token::Assign) { Some(self.parse_expression()) } else { None }; let span = AstSpan::range(start_pos, self.last_consumed_position_or_start()); params.push(self.arena.alloc_node( Parameter { modifiers, type_specifier: type_spec, name, array_size: array_len, default_value, }, span, )); if !self.eat(Token::Comma) || matches!(self.peek_token(), Some(Token::RightParenthesis)) { break; } self.ensure_forward_progress(start_pos); } params } }