use ktrs_syntax::SyntaxKind::{self, *};
use super::parameters::{AnnotationParsingMode, ModifierDetector};
use super::properties::DeclarationParsingMode;
use super::{IMPORT_RECOVERY_SET, NameParsingMode, PACKAGE_NAME_RECOVERY_SET, SEMICOLON_SET};
use crate::builder::{EdgeBinder, Marker};
use crate::parsing::Parser;
use crate::token_set::TokenSet;
impl Parser {
pub(super) fn parse_preamble(&mut self) {
let first_entry = self.mark();
self.parse_file_annotation_list(AnnotationParsingMode::FileAnnotationsBeforePackage);
let mut package_directive = self.mark();
self.parse_modifier_list(TokenSet::EMPTY);
if self.at(PACKAGE_KEYWORD) {
self.advance();
self.parse_package_name();
first_entry.drop(self);
self.consume_if(SEMICOLON);
package_directive.done(self, PACKAGE_DIRECTIVE);
} else {
first_entry.rollback_to(self);
self.parse_file_annotation_list(AnnotationParsingMode::FileAnnotationsWhenPackageOmitted);
package_directive = self.mark();
package_directive.done(self, PACKAGE_DIRECTIVE);
package_directive.set_custom_edge_token_binders(self, Some(EdgeBinder::BindFirstShebangWithWhitespaceOnly), None);
}
self.parse_import_directives();
}
fn parse_package_name(&mut self) {
let mut qualified_expression = self.mark();
let mut simple_name = true;
loop {
if self.my_builder.newline_before_current_token() {
self.error_with_recovery(
"Package name must be a '.'-separated identifier list placed on a single line",
Some(PACKAGE_NAME_RECOVERY_SET),
);
break;
}
if self.at(DOT) {
self.advance(); qualified_expression.error(self, "Package name must be a '.'-separated identifier list");
qualified_expression = self.mark();
continue;
}
let ns_name = self.mark();
let simple_name_found = self.expect_3(
IDENTIFIER,
"Package name must be a '.'-separated identifier list",
Some(PACKAGE_NAME_RECOVERY_SET),
);
if simple_name_found {
ns_name.done(self, REFERENCE_EXPRESSION);
} else {
ns_name.drop(self);
}
if !simple_name {
let preceding_marker = qualified_expression.precede(self);
qualified_expression.done(self, DOT_QUALIFIED_EXPRESSION);
qualified_expression = preceding_marker;
}
if self.at(DOT) {
self.advance();
if simple_name && !simple_name_found {
qualified_expression.drop(self);
qualified_expression = self.mark();
} else {
simple_name = false;
}
} else {
break;
}
}
qualified_expression.drop(self);
}
fn parse_import_directive(&mut self) {
debug_assert!(self._at(IMPORT_KEYWORD));
let import_directive = self.mark();
self.advance();
if self.close_import_with_error_if_newline(import_directive, None, "Expecting qualified name") {
return;
}
if !self.at(IDENTIFIER) {
let error = self.mark();
self.skip_until(TokenSet::create(&[EOL_OR_SEMICOLON]));
error.error(self, "Expecting qualified name");
import_directive.done(self, IMPORT_DIRECTIVE);
self.consume_if(SEMICOLON);
return;
}
let mut qualified_name = self.mark();
let mut reference = self.mark();
self.advance(); reference.done(self, REFERENCE_EXPRESSION);
while self.at(DOT) && self.lookahead(1) != Some(MUL) {
self.advance();
if self.close_import_with_error_if_newline(import_directive, None, "Import must be placed on a single line") {
qualified_name.drop(self);
return;
}
reference = self.mark();
if self.expect_3(IDENTIFIER, "Qualified name must be a '.'-separated identifier list", Some(IMPORT_RECOVERY_SET)) {
reference.done(self, REFERENCE_EXPRESSION);
} else {
reference.drop(self);
}
let precede = qualified_name.precede(self);
qualified_name.done(self, DOT_QUALIFIED_EXPRESSION);
qualified_name = precede;
}
qualified_name.drop(self);
if self.at(DOT) {
self.advance(); debug_assert!(self._at(MUL));
self.advance(); if self.at(AS_KEYWORD) {
let as_ = self.mark();
self.advance(); if self.close_import_with_error_if_newline(import_directive, None, "Expecting identifier") {
as_.drop(self);
return;
}
self.consume_if(IDENTIFIER);
as_.done(self, IMPORT_ALIAS);
let error = as_.precede(self);
error.error(self, "Cannot rename all imported items to one identifier");
}
}
if self.at(AS_KEYWORD) {
let alias = self.mark();
self.advance(); if self.close_import_with_error_if_newline(import_directive, Some(alias), "Expecting identifier") {
return;
}
self.expect_3(IDENTIFIER, "Expecting identifier", Some(SEMICOLON_SET));
alias.done(self, IMPORT_ALIAS);
}
self.consume_if(SEMICOLON);
import_directive.done(self, IMPORT_DIRECTIVE);
import_directive.set_custom_edge_token_binders(self, None, Some(EdgeBinder::TrailingComments));
}
fn close_import_with_error_if_newline(
&mut self,
import_directive: Marker,
import_alias: Option<Marker>,
error_message: &str,
) -> bool {
if self.my_builder.newline_before_current_token() {
if let Some(import_alias) = import_alias {
import_alias.done(self, IMPORT_ALIAS);
}
self.error(error_message);
import_directive.done(self, IMPORT_DIRECTIVE);
return true;
}
false
}
fn parse_import_directives(&mut self) {
let import_list = self.mark();
if !self.at(IMPORT_KEYWORD) {
import_list.set_custom_edge_token_binders(self, Some(EdgeBinder::DoNotBindAnything), None);
}
while self.at(IMPORT_KEYWORD) {
self.parse_import_directive();
}
import_list.done(self, IMPORT_LIST);
}
pub(super) fn parse_top_level_declaration(&mut self) {
if self.at(SEMICOLON) {
self.advance(); return;
}
let decl = self.mark();
let mut detector = ModifierDetector::default();
self.parse_modifier_list_3(Some(&mut detector), TokenSet::EMPTY, false);
let mut decl_type =
self.parse_common_declaration(&detector, NameParsingMode::Required, DeclarationParsingMode::MemberOrToplevel);
if decl_type.is_none() && self.at(LBRACE) {
self.error("Expecting a top level declaration");
self.parse_block();
decl_type = Some(FUN);
}
if decl_type.is_none() && self.at(IMPORT_KEYWORD) {
self.error("imports are only allowed in the beginning of file");
self.parse_import_directives();
decl.drop(self);
} else if let Some(decl_type) = decl_type {
self.close_declaration_with_comment_binders(decl, decl_type, true);
} else {
self.error_and_advance("Expecting a top level declaration");
decl.drop(self);
}
}
pub(crate) fn parse_common_declaration(
&mut self,
detector: &ModifierDetector,
name_parsing_mode_for_object: NameParsingMode,
declaration_parsing_mode: DeclarationParsingMode,
) -> Option<SyntaxKind> {
match self.get_token_id() {
Some(CLASS_KEYWORD | INTERFACE_KEYWORD) => return Some(self.parse_class(detector.is_enum_detected(), true)),
Some(FUN_KEYWORD) => return Some(self.parse_function()),
Some(VAL_KEYWORD | VAR_KEYWORD) => return Some(self.parse_property(declaration_parsing_mode)),
Some(LPAR | LBRACKET) => {
let lookahead = self.lookahead(1);
return if lookahead == Some(VAL_KEYWORD) || lookahead == Some(VAR_KEYWORD) {
Some(self.parse_property(declaration_parsing_mode))
} else {
None
};
}
Some(TYPE_ALIAS_KEYWORD) => return Some(self.parse_type_alias()),
Some(OBJECT_KEYWORD) => {
self.parse_object(name_parsing_mode_for_object, true);
return Some(OBJECT_DECLARATION);
}
Some(IDENTIFIER) => {
if detector.is_enum_detected() && declaration_parsing_mode.can_be_enum_used_as_soft_keyword() {
return Some(self.parse_class(true, false));
}
}
_ => {}
}
None
}
}