mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 12:37:40 +00:00
LibWeb: Pull out larger parsing parts from Parser::parse_simple_selector
This lowers its cognitive complexity from 271 to under 100. The new `parse_pseudo_simple_selector` still has a complexity of 114.
This commit is contained in:
parent
397d8b4aca
commit
fff12847d5
2 changed files with 295 additions and 280 deletions
|
@ -307,70 +307,8 @@ Optional<Selector::Combinator> Parser::parse_selector_combinator(TokenStream<Sty
|
|||
return {};
|
||||
}
|
||||
|
||||
Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_selector(TokenStream<StyleComponentValueRule>& tokens)
|
||||
Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_attribute_simple_selector(StyleComponentValueRule const& first_value)
|
||||
{
|
||||
auto peek_token_ends_selector = [&]() -> bool {
|
||||
auto const& value = tokens.peek_token();
|
||||
return (value.is(Token::Type::EndOfFile) || value.is(Token::Type::Whitespace) || value.is(Token::Type::Comma));
|
||||
};
|
||||
|
||||
if (peek_token_ends_selector())
|
||||
return ParsingResult::Done;
|
||||
|
||||
auto const& first_value = tokens.next_token();
|
||||
|
||||
if (first_value.is(Token::Type::Delim)) {
|
||||
u32 delim = first_value.token().delim();
|
||||
switch (delim) {
|
||||
case '*':
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::Universal
|
||||
};
|
||||
case '.': {
|
||||
if (peek_token_ends_selector())
|
||||
return ParsingResult::SyntaxError;
|
||||
|
||||
auto const& class_name_value = tokens.next_token();
|
||||
if (!class_name_value.is(Token::Type::Ident)) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "Expected an ident after '.', got: {}", class_name_value.to_debug_string());
|
||||
return ParsingResult::SyntaxError;
|
||||
}
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::Class,
|
||||
.value = class_name_value.token().ident()
|
||||
};
|
||||
}
|
||||
case '>':
|
||||
case '+':
|
||||
case '~':
|
||||
case '|':
|
||||
// Whitespace is not required between the compound-selector and a combinator.
|
||||
// So, if we see a combinator, return that this compound-selector is done, instead of a syntax error.
|
||||
tokens.reconsume_current_input_token();
|
||||
return ParsingResult::Done;
|
||||
default:
|
||||
dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid simple selector!");
|
||||
return ParsingResult::SyntaxError;
|
||||
}
|
||||
}
|
||||
|
||||
if (first_value.is(Token::Type::Hash)) {
|
||||
if (first_value.token().hash_type() != Token::HashType::Id) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "Selector contains hash token that is not an id: {}", first_value.to_debug_string());
|
||||
return ParsingResult::SyntaxError;
|
||||
}
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::Id,
|
||||
.value = first_value.token().hash_value()
|
||||
};
|
||||
}
|
||||
if (first_value.is(Token::Type::Ident)) {
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::TagName,
|
||||
.value = first_value.token().ident()
|
||||
};
|
||||
}
|
||||
if (first_value.is_block() && first_value.block().is_square()) {
|
||||
auto attribute_tokens = TokenStream { first_value.block().values() };
|
||||
|
||||
attribute_tokens.skip_whitespace();
|
||||
|
@ -462,7 +400,14 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
|
|||
// FIXME: Handle case-sensitivity suffixes. https://www.w3.org/TR/selectors-4/#attribute-case
|
||||
return simple_selector;
|
||||
}
|
||||
if (first_value.is(Token::Type::Colon)) {
|
||||
|
||||
Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_pseudo_simple_selector(TokenStream<StyleComponentValueRule>& tokens)
|
||||
{
|
||||
auto peek_token_ends_selector = [&]() -> bool {
|
||||
auto const& value = tokens.peek_token();
|
||||
return (value.is(Token::Type::EndOfFile) || value.is(Token::Type::Whitespace) || value.is(Token::Type::Comma));
|
||||
};
|
||||
|
||||
if (peek_token_ends_selector())
|
||||
return ParsingResult::SyntaxError;
|
||||
|
||||
|
@ -571,7 +516,6 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
|
|||
return simple_selector;
|
||||
}
|
||||
if (pseudo_class_token.is_function()) {
|
||||
|
||||
auto parse_nth_child_pattern = [this](Selector::SimpleSelector& simple_selector, StyleFunctionRule const& pseudo_function, bool allow_of = false) -> bool {
|
||||
auto function_values = TokenStream<StyleComponentValueRule>(pseudo_function.values());
|
||||
auto nth_child_pattern = parse_a_n_plus_b_pattern(function_values, allow_of ? AllowTrailingTokens::Yes : AllowTrailingTokens::No);
|
||||
|
@ -651,6 +595,75 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
|
|||
return ParsingResult::SyntaxError;
|
||||
}
|
||||
|
||||
Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_selector(TokenStream<StyleComponentValueRule>& tokens)
|
||||
{
|
||||
auto peek_token_ends_selector = [&]() -> bool {
|
||||
auto const& value = tokens.peek_token();
|
||||
return (value.is(Token::Type::EndOfFile) || value.is(Token::Type::Whitespace) || value.is(Token::Type::Comma));
|
||||
};
|
||||
|
||||
if (peek_token_ends_selector())
|
||||
return ParsingResult::Done;
|
||||
|
||||
auto const& first_value = tokens.next_token();
|
||||
|
||||
if (first_value.is(Token::Type::Delim)) {
|
||||
u32 delim = first_value.token().delim();
|
||||
switch (delim) {
|
||||
case '*':
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::Universal
|
||||
};
|
||||
case '.': {
|
||||
if (peek_token_ends_selector())
|
||||
return ParsingResult::SyntaxError;
|
||||
|
||||
auto const& class_name_value = tokens.next_token();
|
||||
if (!class_name_value.is(Token::Type::Ident)) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "Expected an ident after '.', got: {}", class_name_value.to_debug_string());
|
||||
return ParsingResult::SyntaxError;
|
||||
}
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::Class,
|
||||
.value = class_name_value.token().ident()
|
||||
};
|
||||
}
|
||||
case '>':
|
||||
case '+':
|
||||
case '~':
|
||||
case '|':
|
||||
// Whitespace is not required between the compound-selector and a combinator.
|
||||
// So, if we see a combinator, return that this compound-selector is done, instead of a syntax error.
|
||||
tokens.reconsume_current_input_token();
|
||||
return ParsingResult::Done;
|
||||
default:
|
||||
dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid simple selector!");
|
||||
return ParsingResult::SyntaxError;
|
||||
}
|
||||
}
|
||||
|
||||
if (first_value.is(Token::Type::Hash)) {
|
||||
if (first_value.token().hash_type() != Token::HashType::Id) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "Selector contains hash token that is not an id: {}", first_value.to_debug_string());
|
||||
return ParsingResult::SyntaxError;
|
||||
}
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::Id,
|
||||
.value = first_value.token().hash_value()
|
||||
};
|
||||
}
|
||||
if (first_value.is(Token::Type::Ident)) {
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::TagName,
|
||||
.value = first_value.token().ident()
|
||||
};
|
||||
}
|
||||
if (first_value.is_block() && first_value.block().is_square())
|
||||
return parse_attribute_simple_selector(first_value);
|
||||
|
||||
if (first_value.is(Token::Type::Colon))
|
||||
return parse_pseudo_simple_selector(tokens);
|
||||
|
||||
dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid simple selector!");
|
||||
return ParsingResult::SyntaxError;
|
||||
}
|
||||
|
@ -4901,7 +4914,6 @@ TimePercentage Parser::Dimension::time_percentage() const
|
|||
return percentage();
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Web {
|
||||
|
|
|
@ -315,6 +315,9 @@ private:
|
|||
Result<NonnullRefPtr<Selector>, ParsingResult> parse_complex_selector(TokenStream<StyleComponentValueRule>&, SelectorType);
|
||||
Result<Selector::CompoundSelector, ParsingResult> parse_compound_selector(TokenStream<StyleComponentValueRule>&);
|
||||
Optional<Selector::Combinator> parse_selector_combinator(TokenStream<StyleComponentValueRule>&);
|
||||
|
||||
Result<Selector::SimpleSelector, ParsingResult> parse_attribute_simple_selector(StyleComponentValueRule const&);
|
||||
Result<Selector::SimpleSelector, ParsingResult> parse_pseudo_simple_selector(TokenStream<StyleComponentValueRule>&);
|
||||
Result<Selector::SimpleSelector, ParsingResult> parse_simple_selector(TokenStream<StyleComponentValueRule>&);
|
||||
|
||||
NonnullRefPtr<MediaQuery> parse_media_query(TokenStream<StyleComponentValueRule>&);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue