//! Parsing of callable definitions for Fermented `UnrealScript` //! (functions, events, delegates, operators). use crate::arena::ArenaVec; use crate::ast::{ CallableDefinition, CallableDefinitionRef, CallableKind, CallableModifier, CallableModifierKind, CallableName, IdentifierToken, InfixOperator, InfixOperatorName, ParameterRef, PostfixOperator, PostfixOperatorName, PrefixOperator, PrefixOperatorName, TypeSpecifierRef, }; use crate::lexer::{Keyword, Token, TokenPosition, TokenSpan}; use crate::parser::{ ParseError, ParseErrorKind, ParseResult, Parser, ResultRecoveryExt, SyncLevel, recovery::RecoveryFallback, }; /// Temporary parsed representation of a callable header without its body. #[derive(Debug)] pub(super) struct ParsedCallableHeader<'src, 'arena> { pub start_position: TokenPosition, pub modifiers: crate::arena::ArenaVec<'arena, CallableModifier>, pub kind: CallableKind, pub return_type_specifier: Option>, pub name: CallableName, pub parameters: crate::arena::ArenaVec<'arena, ParameterRef<'src, 'arena>>, } impl<'src, 'arena> RecoveryFallback<'src, 'arena> for ParsedCallableHeader<'src, 'arena> { fn fallback_value(parser: &Parser<'src, 'arena>, error: &ParseError) -> Self { let fallback_position = error.covered_span.start; ParsedCallableHeader { start_position: fallback_position, modifiers: parser.arena.vec(), kind: CallableKind::Function, return_type_specifier: None, name: CallableName::Identifier(IdentifierToken(fallback_position)), parameters: parser.arena.vec(), } } } impl<'src, 'arena> Parser<'src, 'arena> { /// Parses a callable definition. /// /// Assumes [`Parser::is_callable_header_ahead`] has already confirmed that /// a callable declaration begins at the current position. This affects /// the diagnostics produced for malformed input. #[must_use] pub(crate) fn parse_callable_definition(&mut self) -> CallableDefinitionRef<'src, 'arena> { let header = self.parse_callable_header().unwrap_or_fallback(self); let body = if self.eat(Token::LeftBrace) { Some(self.parse_braced_block_statements_tail(self.last_consumed_position_or_start())) } else { self.expect( Token::Semicolon, ParseErrorKind::CallableMissingBodyOrSemicolon, ) .report_error(self); None }; let span = TokenSpan::range( header.start_position, self.last_consumed_position_or_start(), ); self.arena.alloc_node( CallableDefinition { name: header.name, kind: header.kind, return_type_specifier: header.return_type_specifier, modifiers: header.modifiers, parameters: header.parameters, body, }, span, ) } /// Parses a callable header without the body. fn parse_callable_header( &mut self, ) -> ParseResult<'src, 'arena, ParsedCallableHeader<'src, 'arena>> { let start_position = self.require_position(ParseErrorKind::CallableExpectedHeader)?; let mut modifiers = self.arena.vec(); self.collect_callable_modifiers(&mut modifiers); let kind = self.parse_callable_kind()?; self.collect_callable_modifiers(&mut modifiers); // `(` cannot appear inside a return type in this grammar, // so seeing it here means the callable has no return type specifier. let return_type_specifier = match self.peek_token_at(1) { Some(Token::LeftParenthesis) => None, _ => Some(self.parse_type_specifier()?), }; let name = self.parse_callable_name(kind)?; self.expect( Token::LeftParenthesis, ParseErrorKind::CallableParamsMissingOpeningParenthesis, ) .report_error(self); let parameters = self.parse_parameter_list(); self.expect( Token::RightParenthesis, ParseErrorKind::CallableParamsMissingClosingParenthesis, ) .sync_error_at(self, SyncLevel::CloseParenthesis) .report_error(self); Ok(ParsedCallableHeader { start_position, modifiers, kind, return_type_specifier, name, parameters, }) } fn parse_callable_kind(&mut self) -> ParseResult<'src, 'arena, CallableKind> { if let Some(keyword) = self.peek_keyword() { // Handle this separately because only infix operators can carry // an optional precedence and cannot, therefore, be handled by // a simple converter. if keyword == Keyword::Operator { self.advance(); let precedence = self.parse_optional_parenthesized_integer( ParseErrorKind::CallableOperatorInvalidPrecedence, ); return Ok(CallableKind::InfixOperator(precedence)); } if let Ok(kind) = CallableKind::try_from(keyword) { self.advance(); return Ok(kind); } } Err(self.make_error_at_last_consumed(ParseErrorKind::CallableExpectedKind)) } fn parse_callable_name( &mut self, kind: CallableKind, ) -> ParseResult<'src, 'arena, CallableName> { match kind { CallableKind::Function | CallableKind::Event | CallableKind::Delegate => self .parse_identifier(ParseErrorKind::CallableNameNotIdentifier) .map(CallableName::Identifier), CallableKind::PrefixOperator => { let (token, operator_position) = self.require_token_and_position( ParseErrorKind::CallablePrefixOperatorInvalidSymbol, )?; let operator = PrefixOperator::try_from(token).map_err(|()| { self.make_error_at_last_consumed(ParseErrorKind::CallablePrefixOperatorInvalidSymbol) })?; self.advance(); Ok(CallableName::PrefixOperator(PrefixOperatorName { kind: operator, position: operator_position, })) } CallableKind::InfixOperator(_) => { let (token, operator_position) = self.require_token_and_position( ParseErrorKind::CallableInfixOperatorInvalidSymbol, )?; let operator = InfixOperator::try_from(token).map_err(|()| { self.make_error_at_last_consumed(ParseErrorKind::CallableInfixOperatorInvalidSymbol) })?; self.advance(); Ok(CallableName::InfixOperator(InfixOperatorName { kind: operator, position: operator_position, })) } CallableKind::PostfixOperator => { let (token, operator_position) = self.require_token_and_position( ParseErrorKind::CallablePostfixOperatorInvalidSymbol, )?; let operator = PostfixOperator::try_from(token).map_err(|()| { self.make_error_at_last_consumed(ParseErrorKind::CallablePostfixOperatorInvalidSymbol) })?; self.advance(); Ok(CallableName::PostfixOperator(PostfixOperatorName { kind: operator, position: operator_position, })) } } } /// Parses an uninterrupted sequence of function modifiers into /// given vector. pub(crate) fn collect_callable_modifiers( &mut self, modifiers: &mut ArenaVec<'arena, CallableModifier>, ) { while let Some(next_mod) = self.parse_function_modifier() { modifiers.push(next_mod); } } fn parse_function_modifier(&mut self) -> Option { let (keyword, start) = self.peek_keyword_and_position()?; let kind = match keyword { Keyword::Native => { self.advance(); let native_id = self.parse_optional_parenthesized_integer( ParseErrorKind::NativeModifierIdNotIntegerLiteral, ); CallableModifierKind::Native(native_id) } Keyword::Config => { self.advance(); let ident = self .parse_required_parenthesized_identifier( ParseErrorKind::ParenthesisedIdentifierMissingClosingParenthesis, ParseErrorKind::ParenthesisedIdentifierMissingClosingParenthesis, ) .unwrap_or(IdentifierToken(start)); CallableModifierKind::Config(ident) } _ => { let simple = CallableModifierKind::try_from(keyword).ok()?; // Only advance after confirming it is the modifier self.advance(); simple } }; let span = TokenSpan::range(start, self.last_consumed_position_or_start()); Some(CallableModifier { kind, span }) } fn parse_optional_parenthesized_integer(&mut self, close_err: ParseErrorKind) -> Option { if !self.eat(Token::LeftParenthesis) { return None; } let value = match self.peek_token_and_lexeme() { Some((Token::IntegerLiteral, lex)) => { self.advance(); self.decode_integer_literal(lex).ok_or_report(self) } Some(_) => { self.report_error_here(ParseErrorKind::OperatorPrecedenceNotIntegerLiteral); self.advance(); None } None => { self.report_error_here(ParseErrorKind::OperatorPrecedenceNotIntegerLiteral); None } }; self.expect(Token::RightParenthesis, close_err) .sync_error_at(self, SyncLevel::CloseParenthesis) .report_error(self); value } fn parse_required_parenthesized_identifier( &mut self, close_err: ParseErrorKind, ident_err: ParseErrorKind, ) -> Option { if !self.eat(Token::LeftParenthesis) { self.report_error_here(ident_err); return None; } let ident = match self.peek_token_lexeme_and_position() { Some((tok, _, pos)) if tok.is_valid_identifier_name() => { self.advance(); Some(IdentifierToken(pos)) } Some(_) => { self.report_error_here(ident_err); self.advance(); None } None => { self.report_error_here(ident_err); None } }; self.expect(Token::RightParenthesis, close_err) .sync_error_at(self, SyncLevel::CloseParenthesis) .report_error(self); ident } }