From cd199d9d06b1ca6bfa977cc236e26b6184e6276a Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 30 Mar 2022 16:44:13 +0100 Subject: [PATCH] LibWeb: Implement and use `parse_a_style_blocks_contents()` --- .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 109 +++++++++++++++++- Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 5 + 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index aa4d2deb50..5e2a33d63b 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1694,6 +1694,99 @@ RefPtr Parser::consume_a_qualified_rule(TokenStream& tokens) return rule; } +// 5.4.4. Consume a style block’s contents +// https://www.w3.org/TR/css-syntax-3/#consume-a-style-blocks-contents +template +Vector Parser::consume_a_style_blocks_contents(TokenStream& tokens) +{ + // To consume a style block’s contents: + // Create an initially empty list of declarations decls, and an initially empty list of rules rules. + Vector declarations; + Vector rules; + + // Repeatedly consume the next input token: + for (;;) { + auto& token = tokens.next_token(); + + // + // + if (token.is(Token::Type::Whitespace) || token.is(Token::Type::Semicolon)) { + // Do nothing. + continue; + } + + // + if (token.is(Token::Type::EndOfFile)) { + // Extend decls with rules, then return decls. + declarations.extend(move(rules)); + return declarations; + } + + // + if (token.is(Token::Type::AtKeyword)) { + // Reconsume the current input token. + tokens.reconsume_current_input_token(); + + // Consume an at-rule, and append the result to rules. + rules.empend(consume_an_at_rule(tokens)); + continue; + } + + // + if (token.is(Token::Type::Ident)) { + // Initialize a temporary list initially filled with the current input token. + Vector temporary_list; + temporary_list.append(token); + + // As long as the next input token is anything other than a or , + // consume a component value and append it to the temporary list. + for (;;) { + auto& next_input_token = tokens.peek_token(); + if (next_input_token.is(Token::Type::Semicolon) || next_input_token.is(Token::Type::EndOfFile)) + break; + temporary_list.append(consume_a_component_value(tokens)); + } + + // Consume a declaration from the temporary list. If anything was returned, append it to decls. + auto token_stream = TokenStream(temporary_list); + if (auto maybe_declaration = consume_a_declaration(token_stream); maybe_declaration.has_value()) + declarations.empend(maybe_declaration.release_value()); + + continue; + } + + // with a value of "&" (U+0026 AMPERSAND) + if (token.is(Token::Type::Delim) && token.token().delim() == '&') { + // Reconsume the current input token. + tokens.reconsume_current_input_token(); + + // Consume a qualified rule. If anything was returned, append it to rules. + if (auto qualified_rule = consume_a_qualified_rule(tokens)) + rules.empend(qualified_rule); + + continue; + } + + // anything else + { + // This is a parse error. + log_parse_error(); + + // Reconsume the current input token. + tokens.reconsume_current_input_token(); + + // As long as the next input token is anything other than a or , + // consume a component value and throw away the returned value. + for (;;) { + auto& peek = tokens.peek_token(); + if (peek.is(Token::Type::Semicolon) || peek.is(Token::Type::EndOfFile)) + break; + (void)consume_a_component_value(tokens); + } + } + } +} + template<> StyleComponentValueRule Parser::consume_a_component_value(TokenStream& tokens) { @@ -2099,6 +2192,20 @@ Optional Parser::parse_a_declaration(TokenStream& token return {}; } +// 5.3.7. Parse a style block’s contents +// https://www.w3.org/TR/css-syntax-3/#parse-style-blocks-contents +template +Vector Parser::parse_a_style_blocks_contents(TokenStream& tokens) +{ + // To parse a style block’s contents from input: + + // 1. Normalize input, and set input to the result. + // Note: This is done when initializing the Parser. + + // 2. Consume a style block’s contents from input, and return the result. + return consume_a_style_blocks_contents(tokens); +} + // 5.3.8. Parse a list of declarations // https://www.w3.org/TR/css-syntax-3/#parse-list-of-declarations template @@ -2363,7 +2470,7 @@ RefPtr Parser::convert_to_rule(NonnullRefPtr rule) return {}; auto stream = TokenStream(rule->block()->values()); - auto declarations_and_at_rules = parse_a_list_of_declarations(stream); + auto declarations_and_at_rules = parse_a_style_blocks_contents(stream); auto declaration = convert_to_style_declaration(declarations_and_at_rules); if (!declaration) { diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index c7b3ce853c..3c3922a607 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -141,6 +141,9 @@ private: template Optional parse_a_declaration(TokenStream&); + template + Vector parse_a_style_blocks_contents(TokenStream&); + // "Parse a list of declarations" is for the contents of a style attribute, which parses text into the contents of a single style rule. template Vector parse_a_list_of_declarations(TokenStream&); @@ -185,6 +188,8 @@ private: template [[nodiscard]] RefPtr consume_a_qualified_rule(TokenStream&); template + [[nodiscard]] Vector consume_a_style_blocks_contents(TokenStream&); + template [[nodiscard]] Vector consume_a_list_of_declarations(TokenStream&); template [[nodiscard]] Optional consume_a_declaration(TokenStream&);