mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 14:37:43 +00:00
LibWeb: Fix whitespace handling in CSS selectors
Whitespace marks the end of a compound-selector, no matter where it occurs. `check_for_eof_or_whitespace()` reconsumes the whitespace token for convenience.
This commit is contained in:
parent
57f6d86996
commit
7e4f75c78c
1 changed files with 31 additions and 21 deletions
|
@ -218,9 +218,21 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
|
|
||||||
Vector<Selector::ComplexSelector> selectors;
|
Vector<Selector::ComplexSelector> selectors;
|
||||||
|
|
||||||
|
auto check_for_eof_or_whitespace = [&](T& current_value) -> bool {
|
||||||
|
if (current_value.is(Token::Type::EndOfFile))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (current_value.is(Token::Type::Whitespace)) {
|
||||||
|
tokens.reconsume_current_input_token();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
auto parse_simple_selector = [&]() -> Optional<Selector::SimpleSelector> {
|
auto parse_simple_selector = [&]() -> Optional<Selector::SimpleSelector> {
|
||||||
auto current_value = tokens.next_token();
|
auto current_value = tokens.next_token();
|
||||||
if (current_value.is(Token::Type::EndOfFile))
|
dbgln("parse_simple_selector, start token: {}", current_value.to_string());
|
||||||
|
if (check_for_eof_or_whitespace(current_value))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
Selector::SimpleSelector::Type type;
|
Selector::SimpleSelector::Type type;
|
||||||
|
@ -245,7 +257,7 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
value = ((Token)current_value).m_value.to_string();
|
value = ((Token)current_value).m_value.to_string();
|
||||||
} else if (current_value.is(Token::Type::Delim) && ((Token)current_value).delim() == ".") {
|
} else if (current_value.is(Token::Type::Delim) && ((Token)current_value).delim() == ".") {
|
||||||
current_value = tokens.next_token();
|
current_value = tokens.next_token();
|
||||||
if (current_value.is(Token::Type::EndOfFile))
|
if (check_for_eof_or_whitespace(current_value))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!current_value.is(Token::Type::Ident)) {
|
if (!current_value.is(Token::Type::Ident)) {
|
||||||
|
@ -267,7 +279,7 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
simple_selector.value = value;
|
simple_selector.value = value;
|
||||||
|
|
||||||
current_value = tokens.next_token();
|
current_value = tokens.next_token();
|
||||||
if (current_value.is(Token::Type::EndOfFile))
|
if (check_for_eof_or_whitespace(current_value))
|
||||||
return simple_selector;
|
return simple_selector;
|
||||||
|
|
||||||
// FIXME: Attribute selectors want to be their own Selector::SimpleSelector::Type according to the spec.
|
// FIXME: Attribute selectors want to be their own Selector::SimpleSelector::Type according to the spec.
|
||||||
|
@ -337,14 +349,6 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (attribute_parts.at(attribute_index).is(Token::Type::Whitespace)) {
|
|
||||||
attribute_index++;
|
|
||||||
if (attribute_index >= attribute_parts.size()) {
|
|
||||||
dbgln("Attribute selector ended without a value to match.");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attribute_index >= attribute_parts.size()) {
|
if (attribute_index >= attribute_parts.size()) {
|
||||||
dbgln("Attribute selector ended without a value to match.");
|
dbgln("Attribute selector ended without a value to match.");
|
||||||
return {};
|
return {};
|
||||||
|
@ -366,13 +370,13 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
bool is_pseudo = false;
|
bool is_pseudo = false;
|
||||||
|
|
||||||
current_value = tokens.next_token();
|
current_value = tokens.next_token();
|
||||||
if (current_value.is(Token::Type::EndOfFile))
|
if (check_for_eof_or_whitespace(current_value))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (current_value.is(Token::Type::Colon)) {
|
if (current_value.is(Token::Type::Colon)) {
|
||||||
is_pseudo = true;
|
is_pseudo = true;
|
||||||
current_value = tokens.next_token();
|
current_value = tokens.next_token();
|
||||||
if (current_value.is(Token::Type::EndOfFile))
|
if (check_for_eof_or_whitespace(current_value))
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +386,7 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
current_value = tokens.next_token();
|
current_value = tokens.next_token();
|
||||||
if (current_value.is(Token::Type::EndOfFile))
|
if (check_for_eof_or_whitespace(current_value))
|
||||||
return simple_selector;
|
return simple_selector;
|
||||||
|
|
||||||
if (current_value.is(Token::Type::Ident)) {
|
if (current_value.is(Token::Type::Ident)) {
|
||||||
|
@ -452,6 +456,8 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
auto parse_complex_selector = [&]() -> Optional<Selector::ComplexSelector> {
|
auto parse_complex_selector = [&]() -> Optional<Selector::ComplexSelector> {
|
||||||
auto relation = Selector::ComplexSelector::Relation::Descendant;
|
auto relation = Selector::ComplexSelector::Relation::Descendant;
|
||||||
|
|
||||||
|
tokens.skip_whitespace();
|
||||||
|
|
||||||
auto current_value = tokens.peek_token();
|
auto current_value = tokens.peek_token();
|
||||||
if (current_value.is(Token::Type::Delim)) {
|
if (current_value.is(Token::Type::Delim)) {
|
||||||
auto delim = ((Token)current_value).delim();
|
auto delim = ((Token)current_value).delim();
|
||||||
|
@ -475,12 +481,20 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
relation = Selector::ComplexSelector::Relation::Column;
|
relation = Selector::ComplexSelector::Relation::Column;
|
||||||
tokens.next_token();
|
tokens.next_token();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
dbgln("Unrecognized relation delimiter: '{}'", delim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokens.skip_whitespace();
|
||||||
|
|
||||||
Vector<Selector::SimpleSelector> simple_selectors;
|
Vector<Selector::SimpleSelector> simple_selectors;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
auto current_value = tokens.peek_token();
|
||||||
|
if (current_value.is(Token::Type::EndOfFile) || current_value.is(Token::Type::Whitespace))
|
||||||
|
break;
|
||||||
|
|
||||||
auto component = parse_simple_selector();
|
auto component = parse_simple_selector();
|
||||||
if (!component.has_value())
|
if (!component.has_value())
|
||||||
break;
|
break;
|
||||||
|
@ -495,17 +509,13 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
};
|
};
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto complex = parse_complex_selector();
|
|
||||||
if (complex.has_value())
|
|
||||||
selectors.append(complex.value());
|
|
||||||
|
|
||||||
auto current_value = tokens.peek_token();
|
auto current_value = tokens.peek_token();
|
||||||
if (current_value.is(Token::Type::EndOfFile))
|
if (current_value.is(Token::Type::EndOfFile))
|
||||||
break;
|
break;
|
||||||
if (current_value.is(Token::Type::Comma))
|
|
||||||
break;
|
|
||||||
|
|
||||||
tokens.next_token();
|
auto complex = parse_complex_selector();
|
||||||
|
if (complex.has_value())
|
||||||
|
selectors.append(complex.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectors.is_empty())
|
if (selectors.is_empty())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue