use ktrs_syntax::SyntaxKind::{self, *};
use super::{
CLASS_INTERFACE_SET, CLASS_NAME_RECOVERY_SET, COMMA_SEMICOLON_RBRACE_SET, LBRACE_RBRACE_SET,
LPAR_LBRACE_COLON_CONSTRUCTOR_KEYWORD_SET, NameParsingMode, SOFT_KEYWORDS_AT_MEMBER_START,
TYPE_PARAMETER_GT_RECOVERY_SET,
};
use crate::parsing::{OptionalMarker, Parser};
use crate::token_set::TokenSet;
enum ParseEnumEntryResult {
Failed,
NoDelimiter,
CommaDelimiter,
SemicolonDelimiter,
}
impl Parser {
fn parse_class_or_object(
&mut self,
object: bool,
name_parsing_mode: NameParsingMode,
optional_body: bool,
enum_class: bool,
expect_kind_keyword: bool,
) -> SyntaxKind {
if expect_kind_keyword {
if object {
debug_assert!(self._at(OBJECT_KEYWORD));
} else {
debug_assert!(self._at_set(CLASS_INTERFACE_SET));
}
self.advance(); } else {
debug_assert!(enum_class, "Currently classifiers without class/interface/object are only allowed for enums");
self.error("'class' keyword is expected after 'enum'");
}
if name_parsing_mode == NameParsingMode::Required {
self.expect_3(IDENTIFIER, "Name expected", Some(CLASS_NAME_RECOVERY_SET));
} else {
debug_assert!(object, "Must be an object to be nameless");
if self.at(IDENTIFIER) {
if name_parsing_mode == NameParsingMode::Prohibited {
self.error_and_advance("An object expression cannot bind a name");
} else {
debug_assert!(name_parsing_mode == NameParsingMode::Allowed);
self.advance();
}
}
}
let type_parameters_declared = self.parse_type_parameter_list(TYPE_PARAMETER_GT_RECOVERY_SET);
let before_constructor_modifiers = self.mark();
let primary_constructor_marker = self.mark();
let has_constructor_modifiers = self.parse_modifier_list(TokenSet::EMPTY);
if has_constructor_modifiers && !self.at_set(LPAR_LBRACE_COLON_CONSTRUCTOR_KEYWORD_SET) {
before_constructor_modifiers.rollback_to(self);
return if object { OBJECT_DECLARATION } else { CLASS };
}
before_constructor_modifiers.drop(self);
let has_constructor_keyword = self.at(CONSTRUCTOR_KEYWORD);
if has_constructor_keyword {
self.advance(); }
if self.at(LPAR) {
self.parse_value_parameter_list(false, true, LBRACE_RBRACE_SET);
primary_constructor_marker.done(self, PRIMARY_CONSTRUCTOR);
} else if has_constructor_modifiers || has_constructor_keyword {
primary_constructor_marker.done(self, PRIMARY_CONSTRUCTOR);
if has_constructor_keyword {
self.error("Expecting primary constructor parameter list");
} else {
self.error("Expecting 'constructor' keyword");
}
} else {
primary_constructor_marker.drop(self);
}
if self.at(COLON) {
self.advance(); self.parse_delegation_specifier_list();
}
let where_marker = OptionalMarker::new(self, object);
self.parse_type_constraints_guarded(type_parameters_declared);
where_marker.error(self, "Where clause is not allowed for objects");
if self.at(LBRACE) {
if enum_class {
self.parse_enum_class_body();
} else {
self.parse_class_body();
}
} else if !optional_body {
let fake_body = self.mark();
self.error("Expecting a class body");
fake_body.done(self, CLASS_BODY);
}
if object { OBJECT_DECLARATION } else { CLASS }
}
pub(super) fn parse_class(&mut self, enum_class: bool, expect_kind_keyword: bool) -> SyntaxKind {
self.parse_class_or_object(false, NameParsingMode::Required, true, enum_class, expect_kind_keyword)
}
pub(crate) fn parse_object(&mut self, name_parsing_mode: NameParsingMode, optional_body: bool) {
self.parse_class_or_object(true, name_parsing_mode, optional_body, false, true);
}
fn parse_enum_class_body(&mut self) {
if !self.at(LBRACE) {
return;
}
let body = self.mark();
self.my_builder.enable_newlines();
self.advance();
if !self.parse_enum_entries() && !self.at(RBRACE) {
self.error("Expecting ';' after the last enum entry or '}' to close enum class body");
}
self.parse_members();
self.expect_2(RBRACE, "Expecting '}' to close enum class body");
self.my_builder.restore_newlines_state();
body.done(self, CLASS_BODY);
}
fn parse_enum_entries(&mut self) -> bool {
while !self.eof() && !self.at(RBRACE) {
match self.parse_enum_entry() {
ParseEnumEntryResult::Failed => {
if self.at(SEMICOLON) {
self.advance();
return true;
} else {
return false;
}
}
ParseEnumEntryResult::NoDelimiter => return false,
ParseEnumEntryResult::CommaDelimiter => {}
ParseEnumEntryResult::SemicolonDelimiter => return true,
}
}
false
}
fn parse_enum_entry(&mut self) -> ParseEnumEntryResult {
let entry = self.mark();
self.parse_modifier_list(COMMA_SEMICOLON_RBRACE_SET);
if !self.at_set(SOFT_KEYWORDS_AT_MEMBER_START) && self.at(IDENTIFIER) {
self.advance();
if self.at(LPAR) {
let initializer_list = self.mark();
let delegator_super_call = self.mark();
let callee = self.mark();
let type_reference = self.mark();
let type_ = self.mark();
let reference_expr = self.mark();
reference_expr.done(self, ENUM_ENTRY_SUPERCLASS_REFERENCE_EXPRESSION);
type_.done(self, USER_TYPE);
type_reference.done(self, TYPE_REFERENCE);
callee.done(self, CONSTRUCTOR_CALLEE);
self.parse_value_argument_list();
delegator_super_call.done(self, SUPER_TYPE_CALL_ENTRY);
initializer_list.done(self, INITIALIZER_LIST);
}
if self.at(LBRACE) {
self.parse_class_body();
}
let comma_found = self.at(COMMA);
if comma_found {
self.advance();
}
let semicolon_found = self.at(SEMICOLON);
if semicolon_found {
self.advance();
}
self.close_declaration_with_comment_binders(entry, ENUM_ENTRY, true);
if semicolon_found {
ParseEnumEntryResult::SemicolonDelimiter
} else if comma_found {
ParseEnumEntryResult::CommaDelimiter
} else {
ParseEnumEntryResult::NoDelimiter
}
} else {
entry.rollback_to(self);
ParseEnumEntryResult::Failed
}
}
}