use ktrs_syntax::SyntaxKind::{self, *};
use super::{DECLARATION_FIRST, LAMBDA_VALUE_PARAMETER_FIRST, PARAMETER_NAME_RECOVERY_SET, VALUE_PARAMETER_FIRST};
use crate::parsing::{Consumer, Parser};
use crate::token_set::TokenSet;
pub(super) const NO_MODIFIER_BEFORE_FOR_VALUE_PARAMETER: TokenSet = TokenSet::create(&[COMMA, COLON, EQ, RPAR]);
pub(crate) const EXPRESSION_FIRST: TokenSet = TokenSet::create(&[
MINUS, PLUS, MINUSMINUS, PLUSPLUS,
EXCL, EXCLEXCL, COLONCOLON, LPAR, TRUE_KEYWORD, FALSE_KEYWORD,
INTERPOLATION_PREFIX, OPEN_QUOTE,
INTEGER_LITERAL, CHARACTER_LITERAL, FLOAT_LITERAL,
NULL_KEYWORD,
LBRACE, FUN_KEYWORD, THIS_KEYWORD, SUPER_KEYWORD, IF_KEYWORD, WHEN_KEYWORD, TRY_KEYWORD, OBJECT_KEYWORD, THROW_KEYWORD,
RETURN_KEYWORD,
CONTINUE_KEYWORD,
BREAK_KEYWORD,
FOR_KEYWORD,
WHILE_KEYWORD,
DO_KEYWORD,
IDENTIFIER, AT, LBRACKET, ]);
pub(crate) const EXPRESSION_FOLLOW: TokenSet = TokenSet::create(&[EOL_OR_SEMICOLON, ARROW, COMMA, RBRACE, RPAR, RBRACKET]);
pub(super) const USER_TYPE_NAME_RECOVERY_SET: TokenSet =
TokenSet::or_set(&[EXPRESSION_FIRST, EXPRESSION_FOLLOW, DECLARATION_FIRST]);
impl Parser {
pub(super) fn parse_value_parameter_list(
&mut self,
is_function_type_contents: bool,
type_required: bool,
recovery_set: TokenSet,
) {
debug_assert!(self._at(LPAR));
let parameters = self.mark();
self.my_builder.disable_newlines();
self.value_parameter_loop(is_function_type_contents, recovery_set, &mut |p: &mut Parser| {
if is_function_type_contents {
if !p.try_parse_value_parameter(type_required) {
let value_parameter = p.mark();
p.parse_function_type_value_parameter_modifier_list();
p.parse_type_ref();
p.close_declaration_with_comment_binders(value_parameter, VALUE_PARAMETER, false);
}
} else {
p.parse_value_parameter(type_required);
}
true
});
self.my_builder.restore_newlines_state();
parameters.done(self, VALUE_PARAMETER_LIST);
}
pub(super) fn value_parameter_loop(
&mut self,
in_function_type_context: bool,
recovery_set: TokenSet,
parse_parameter: &mut dyn FnMut(&mut Parser) -> bool,
) -> bool {
self.advance();
let mut no_error = true;
if !self.at(RPAR) && !self.at_set(recovery_set) {
loop {
let offset_before = self.my_builder.get_current_offset();
if self.at(RPAR) {
break;
}
no_error = parse_parameter(self) && no_error;
if self.at(COMMA) {
self.advance(); } else if self.at(COLON) {
continue;
} else {
if !self.at(RPAR) {
self.error("Expecting comma or ')'");
no_error = false;
}
if !self.at_set(if in_function_type_context { LAMBDA_VALUE_PARAMETER_FIRST } else { VALUE_PARAMETER_FIRST }) {
break;
}
if offset_before == self.my_builder.get_current_offset() {
break;
}
}
}
}
self.expect_3(RPAR, "Expecting ')'", Some(recovery_set)) && no_error
}
pub(super) fn try_parse_value_parameter(&mut self, type_required: bool) -> bool {
self.parse_value_parameter_2(true, type_required)
}
pub(crate) fn parse_value_parameter(&mut self, type_required: bool) {
self.parse_value_parameter_2(false, type_required);
}
fn parse_value_parameter_2(&mut self, rollback_on_failure: bool, type_required: bool) -> bool {
let parameter = self.mark();
self.parse_modifier_list(NO_MODIFIER_BEFORE_FOR_VALUE_PARAMETER);
if self.at(VAR_KEYWORD) || self.at(VAL_KEYWORD) {
self.advance(); }
if !self.parse_function_parameter_rest(type_required) && rollback_on_failure {
parameter.rollback_to(self);
return false;
}
self.close_declaration_with_comment_binders(parameter, VALUE_PARAMETER, false);
true
}
fn parse_function_parameter_rest(&mut self, type_required: bool) -> bool {
let mut no_errors = true;
if self.at(COMMA) || self.at(RPAR) {
self.error("Expecting a parameter declaration");
no_errors = false;
} else if self.at(IDENTIFIER) && self.lookahead(1) == Some(LT) {
self.error("Parameter name expected");
no_errors = false;
self.parse_type_ref();
} else if self.at(COLON) {
self.error("Parameter name expected");
self.advance(); self.parse_type_ref();
} else {
self.expect_3(IDENTIFIER, "Parameter name expected", Some(PARAMETER_NAME_RECOVERY_SET));
if self.at(COLON) {
self.advance();
if self.at(IDENTIFIER) && self.lookahead(1) == Some(COLON) {
self.error("Type reference expected");
return false;
}
self.parse_type_ref();
} else if type_required {
self.error_with_recovery("Parameters must have type annotation", Some(PARAMETER_NAME_RECOVERY_SET));
no_errors = false;
}
}
if self.at(EQ) {
self.advance(); self.parse_expression();
}
no_errors
}
}
#[derive(Default)]
pub(crate) struct ModifierDetector {
enum_detected: bool,
companion_detected: bool,
}
impl Consumer<SyntaxKind> for ModifierDetector {
fn consume(&mut self, item: SyntaxKind) {
if item == ENUM_KEYWORD {
self.enum_detected = true;
} else if item == COMPANION_KEYWORD {
self.companion_detected = true;
}
}
}
impl ModifierDetector {
pub(crate) fn is_enum_detected(&self) -> bool {
self.enum_detected
}
pub(crate) fn is_companion_detected(&self) -> bool {
self.companion_detected
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum AnnotationParsingMode {
Default,
FileAnnotationsBeforePackage,
FileAnnotationsWhenPackageOmitted,
TypeContext,
WithSignificantWhitespaceBeforeArguments,
WithSignificantWhitespaceBeforeArgumentsNoContext,
NoAnnotationsNoContext,
}
impl AnnotationParsingMode {
const fn flags(self) -> (bool, bool, bool, bool, bool) {
use AnnotationParsingMode::*;
match self {
Default => (false, true, true, false, false),
FileAnnotationsBeforePackage => (true, true, false, false, false),
FileAnnotationsWhenPackageOmitted => (true, true, false, false, false),
TypeContext => (false, true, false, true, false),
WithSignificantWhitespaceBeforeArguments => (false, true, true, true, true),
WithSignificantWhitespaceBeforeArgumentsNoContext => (false, true, false, true, true),
NoAnnotationsNoContext => (false, false, false, false, false),
}
}
pub(crate) fn is_file_annotation_parsing_mode(self) -> bool {
self.flags().0
}
pub(crate) fn allow_annotations(self) -> bool {
self.flags().1
}
pub(crate) fn allow_context_list(self) -> bool {
self.flags().2
}
pub(crate) fn type_context(self) -> bool {
self.flags().3
}
pub(crate) fn with_significant_whitespace_before_arguments(self) -> bool {
self.flags().4
}
}