use crate::parser::CssParser;
use crate::syntax::parse_error::expected_relative_selector;
use crate::syntax::selector::{is_nth_at_compound_selector, parse_selector};
use biome_css_syntax::CssSyntaxKind::*;
use biome_css_syntax::{CssSyntaxKind, T};
use biome_parser::parse_lists::ParseSeparatedList;
use biome_parser::parse_recovery::{ParseRecovery, RecoveryError, RecoveryResult};
use biome_parser::parsed_syntax::ParsedSyntax;
use biome_parser::parsed_syntax::ParsedSyntax::{Absent, Present};
use biome_parser::{token_set, Parser, TokenSet};
pub(crate) struct RelativeSelectorList {
end_kind: CssSyntaxKind,
is_recovery_disabled: bool,
}
impl RelativeSelectorList {
pub(crate) fn new(end_kind: CssSyntaxKind) -> Self {
RelativeSelectorList {
end_kind,
is_recovery_disabled: false,
}
}
pub(crate) fn disable_recovery(mut self) -> Self {
self.is_recovery_disabled = true;
self
}
}
pub(crate) struct RelativeSelectorListParseRecovery {
end_kind: CssSyntaxKind,
}
impl RelativeSelectorListParseRecovery {
pub(crate) fn new(end_kind: CssSyntaxKind) -> Self {
RelativeSelectorListParseRecovery { end_kind }
}
}
impl ParseRecovery for RelativeSelectorListParseRecovery {
type Kind = CssSyntaxKind;
type Parser<'source> = CssParser<'source>;
const RECOVERED_KIND: Self::Kind = CSS_BOGUS_SELECTOR;
fn is_at_recovered(&self, p: &mut Self::Parser<'_>) -> bool {
p.at(self.end_kind) || p.at(T![,]) || is_at_relative_selector(p)
}
}
impl ParseSeparatedList for RelativeSelectorList {
type Kind = CssSyntaxKind;
type Parser<'source> = CssParser<'source>;
const LIST_KIND: CssSyntaxKind = CSS_RELATIVE_SELECTOR_LIST;
fn parse_element(&mut self, p: &mut CssParser) -> ParsedSyntax {
parse_relative_selector(p)
}
fn is_at_list_end(&self, p: &mut CssParser) -> bool {
p.at(self.end_kind)
}
fn recover(&mut self, p: &mut CssParser, parsed_element: ParsedSyntax) -> RecoveryResult {
if parsed_element.is_absent() && self.is_recovery_disabled {
Err(RecoveryError::RecoveryDisabled)
} else {
parsed_element.or_recover(
p,
&RelativeSelectorListParseRecovery::new(self.end_kind),
expected_relative_selector,
)
}
}
fn separating_element_kind(&mut self) -> CssSyntaxKind {
T![,]
}
}
const RELATIVE_SELECTOR_COMBINATOR_SET: TokenSet<CssSyntaxKind> =
token_set![T![>], T![+], T![~], T![||]];
#[inline]
fn is_at_relative_selector_combinator(p: &mut CssParser) -> bool {
p.at_ts(RELATIVE_SELECTOR_COMBINATOR_SET)
}
#[inline]
pub(crate) fn is_at_relative_selector(p: &mut CssParser) -> bool {
is_at_relative_selector_combinator(p) || is_nth_at_compound_selector(p, 0)
}
#[inline]
fn parse_relative_selector(p: &mut CssParser) -> ParsedSyntax {
if !is_at_relative_selector(p) {
return Absent;
}
let m = p.start();
p.eat_ts(RELATIVE_SELECTOR_COMBINATOR_SET);
parse_selector(p).or_add_diagnostic(p, expected_relative_selector);
Present(m.complete(p, CSS_RELATIVE_SELECTOR))
}