mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 20:57:41 +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 {};
|
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() };
|
auto attribute_tokens = TokenStream { first_value.block().values() };
|
||||||
|
|
||||||
attribute_tokens.skip_whitespace();
|
attribute_tokens.skip_whitespace();
|
||||||
|
@ -461,8 +399,15 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
|
||||||
|
|
||||||
// FIXME: Handle case-sensitivity suffixes. https://www.w3.org/TR/selectors-4/#attribute-case
|
// FIXME: Handle case-sensitivity suffixes. https://www.w3.org/TR/selectors-4/#attribute-case
|
||||||
return simple_selector;
|
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())
|
if (peek_token_ends_selector())
|
||||||
return ParsingResult::SyntaxError;
|
return ParsingResult::SyntaxError;
|
||||||
|
|
||||||
|
@ -571,7 +516,6 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
|
||||||
return simple_selector;
|
return simple_selector;
|
||||||
}
|
}
|
||||||
if (pseudo_class_token.is_function()) {
|
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 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 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);
|
auto nth_child_pattern = parse_a_n_plus_b_pattern(function_values, allow_of ? AllowTrailingTokens::Yes : AllowTrailingTokens::No);
|
||||||
|
@ -649,7 +593,76 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
|
||||||
}
|
}
|
||||||
dbgln_if(CSS_PARSER_DEBUG, "Unexpected Block in pseudo-class name, expected a function or identifier. '{}'", pseudo_class_token.to_debug_string());
|
dbgln_if(CSS_PARSER_DEBUG, "Unexpected Block in pseudo-class name, expected a function or identifier. '{}'", pseudo_class_token.to_debug_string());
|
||||||
return ParsingResult::SyntaxError;
|
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!");
|
dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid simple selector!");
|
||||||
return ParsingResult::SyntaxError;
|
return ParsingResult::SyntaxError;
|
||||||
|
@ -4901,7 +4914,6 @@ TimePercentage Parser::Dimension::time_percentage() const
|
||||||
return percentage();
|
return percentage();
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Web {
|
namespace Web {
|
||||||
|
|
|
@ -315,6 +315,9 @@ private:
|
||||||
Result<NonnullRefPtr<Selector>, ParsingResult> parse_complex_selector(TokenStream<StyleComponentValueRule>&, SelectorType);
|
Result<NonnullRefPtr<Selector>, ParsingResult> parse_complex_selector(TokenStream<StyleComponentValueRule>&, SelectorType);
|
||||||
Result<Selector::CompoundSelector, ParsingResult> parse_compound_selector(TokenStream<StyleComponentValueRule>&);
|
Result<Selector::CompoundSelector, ParsingResult> parse_compound_selector(TokenStream<StyleComponentValueRule>&);
|
||||||
Optional<Selector::Combinator> parse_selector_combinator(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>&);
|
Result<Selector::SimpleSelector, ParsingResult> parse_simple_selector(TokenStream<StyleComponentValueRule>&);
|
||||||
|
|
||||||
NonnullRefPtr<MediaQuery> parse_media_query(TokenStream<StyleComponentValueRule>&);
|
NonnullRefPtr<MediaQuery> parse_media_query(TokenStream<StyleComponentValueRule>&);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue