rott/rottlib/src/parser/grammar/function/definition.rs

298 lines
11 KiB
Rust

//! 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<TypeSpecifierRef<'src, 'arena>>,
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<CallableModifier> {
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<u128> {
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<IdentifierToken> {
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
}
}