use super::parse_error::expected_expression;
use super::url::{is_at_url_function, parse_url_function};
use crate::parser::CssParser;
use crate::syntax::parse_error::expected_declaration_item;
use crate::syntax::{
is_at_any_value, is_nth_at_identifier, parse_regular_identifier, CssComponentValueList,
};
use biome_css_syntax::CssSyntaxKind::*;
use biome_css_syntax::{CssSyntaxKind, T};
use biome_parser::parse_lists::{ParseNodeList, ParseSeparatedList};
use biome_parser::parse_recovery::{ParseRecovery, RecoveryResult};
use biome_parser::parsed_syntax::ParsedSyntax;
use biome_parser::parsed_syntax::ParsedSyntax::{Absent, Present};
use biome_parser::{token_set, Parser, TokenSet};
#[inline]
pub(crate) fn is_at_any_function(p: &mut CssParser) -> bool {
is_at_url_function(p) || is_at_function(p)
}
#[inline]
pub(crate) fn parse_any_function(p: &mut CssParser) -> ParsedSyntax {
if !is_at_any_function(p) {
return Absent;
}
if is_at_url_function(p) {
parse_url_function(p)
} else {
parse_function(p)
}
}
#[inline]
pub(crate) fn is_at_function(p: &mut CssParser) -> bool {
is_nth_at_function(p, 0) && !is_at_url_function(p)
}
#[inline]
pub(crate) fn is_nth_at_function(p: &mut CssParser, n: usize) -> bool {
is_nth_at_identifier(p, n) && p.nth_at(n + 1, T!['('])
}
#[inline]
pub(crate) fn parse_function(p: &mut CssParser) -> ParsedSyntax {
if !is_at_function(p) {
return Absent;
}
let m = p.start();
parse_regular_identifier(p).ok();
p.bump(T!['(']);
ParameterList.parse_list(p);
p.expect(T![')']);
Present(m.complete(p, CSS_FUNCTION))
}
struct ParameterListParseRecovery;
impl ParseRecovery for ParameterListParseRecovery {
type Kind = CssSyntaxKind;
type Parser<'source> = CssParser<'source>;
const RECOVERED_KIND: Self::Kind = CSS_BOGUS_PARAMETER;
fn is_at_recovered(&self, p: &mut Self::Parser<'_>) -> bool {
p.at_ts(token_set!(T![,], T![')'], T![;])) || is_at_parameter(p)
}
}
pub(crate) struct ParameterList;
impl ParseSeparatedList for ParameterList {
type Kind = CssSyntaxKind;
type Parser<'source> = CssParser<'source>;
const LIST_KIND: Self::Kind = CSS_PARAMETER_LIST;
fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax {
parse_parameter(p)
}
fn is_at_list_end(&self, p: &mut Self::Parser<'_>) -> bool {
p.at(T![')'])
}
fn recover(
&mut self,
p: &mut Self::Parser<'_>,
parsed_element: ParsedSyntax,
) -> RecoveryResult {
parsed_element.or_recover(p, &ParameterListParseRecovery, expected_declaration_item)
}
fn separating_element_kind(&mut self) -> Self::Kind {
T![,]
}
fn allow_trailing_separating_element(&self) -> bool {
true
}
}
#[inline]
pub(crate) fn is_at_parameter(p: &mut CssParser) -> bool {
is_at_any_expression(p)
}
#[inline]
pub(crate) fn parse_parameter(p: &mut CssParser) -> ParsedSyntax {
if !is_at_parameter(p) {
return Absent;
}
let param = p.start();
parse_any_expression(p).ok();
Present(param.complete(p, CSS_PARAMETER))
}
#[inline]
pub(crate) fn is_at_any_expression(p: &mut CssParser) -> bool {
is_at_parenthesized(p) || is_at_any_value(p)
}
#[inline]
pub(crate) fn parse_any_expression(p: &mut CssParser) -> ParsedSyntax {
if !is_at_any_expression(p) {
return Absent;
}
let param = if is_at_parenthesized(p) {
parse_parenthesized_expression(p)
} else {
parse_list_of_component_values_expression(p)
};
if is_at_binary_operator(p) {
let binary_expression = param.precede(p);
p.bump_ts(BINARY_OPERATION_TOKEN);
parse_any_expression(p).or_add_diagnostic(p, expected_expression);
Present(binary_expression.complete(p, CSS_BINARY_EXPRESSION))
} else {
param
}
}
pub(crate) const BINARY_OPERATION_TOKEN: TokenSet<CssSyntaxKind> =
token_set![T![+], T![-], T![*], T![/]];
#[inline]
pub(crate) fn is_at_binary_operator(p: &mut CssParser) -> bool {
p.at_ts(BINARY_OPERATION_TOKEN)
}
#[inline]
pub(crate) fn is_at_parenthesized(p: &mut CssParser) -> bool {
p.at(T!['('])
}
#[inline]
pub(crate) fn parse_parenthesized_expression(p: &mut CssParser) -> ParsedSyntax {
if !is_at_parenthesized(p) {
return Absent;
}
let m = p.start();
p.expect(T!['(']);
parse_any_expression(p).ok();
p.expect(T![')']);
Present(m.complete(p, CSS_PARENTHESIZED_EXPRESSION))
}
#[inline]
pub(crate) fn parse_list_of_component_values_expression(p: &mut CssParser) -> ParsedSyntax {
if !is_at_any_value(p) {
return Absent;
}
let m = p.start();
CssComponentValueList.parse_list(p);
Present(m.complete(p, CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION))
}