2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								/*
  
						 
					
						
							
								
									
										
										
										
											2024-10-04 13:19:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								 *  Copyright  ( c )  2018 - 2022 ,  Andreas  Kling  < andreas @ ladybird . org > 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								 *  Copyright  ( c )  2020 - 2021 ,  the  SerenityOS  developers . 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-15 12:00:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								 *  Copyright  ( c )  2021 - 2024 ,  Sam  Atkins  < sam @ ladybird . org > 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								 *  Copyright  ( c )  2021 ,  Tobias  Christiansen  < tobyase @ serenityos . org > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								 *  Copyright  ( c )  2022 ,  MacDue  < macdue @ dueutil . tech > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								 *  SPDX - License - Identifier :  BSD - 2 - Clause 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								# include  <AK/Debug.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								# include  <LibWeb/CSS/Parser/Parser.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-12-10 22:06:55 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								# include  <LibWeb/Infra/Strings.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								namespace  Web : : CSS : : Parser  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Optional < SelectorList >  Parser : : parse_as_selector ( SelectorParsingMode  parsing_mode )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  selector_list  =  parse_a_selector_list ( m_token_stream ,  SelectorType : : Standalone ,  parsing_mode ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! selector_list . is_error ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  selector_list . release_value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Optional < SelectorList >  Parser : : parse_as_relative_selector ( SelectorParsingMode  parsing_mode )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  selector_list  =  parse_a_selector_list ( m_token_stream ,  SelectorType : : Relative ,  parsing_mode ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! selector_list . is_error ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  selector_list . release_value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-03-20 16:56:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								Optional < Selector : : PseudoElementSelector >  Parser : : parse_as_pseudo_element_selector ( )  
						 
					
						
							
								
									
										
										
										
											2024-08-06 12:44:43 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // FIXME: This is quite janky. Selector parsing is not at all designed to allow parsing just a single part of a selector.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    //        So, this code parses a whole selector, then rejects it if it's not a single pseudo-element simple selector.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    //        Come back and fix this, future Sam!
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  maybe_selector_list  =  parse_a_selector_list ( m_token_stream ,  SelectorType : : Standalone ,  SelectorParsingMode : : Standard ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( maybe_selector_list . is_error ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto &  selector_list  =  maybe_selector_list . value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( selector_list . size ( )  ! =  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto &  selector  =  selector_list . first ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( selector - > compound_selectors ( ) . size ( )  ! =  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto &  first_compound_selector  =  selector - > compound_selectors ( ) . first ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_compound_selector . simple_selectors . size ( )  ! =  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto &  simple_selector  =  first_compound_selector . simple_selectors . first ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( simple_selector . type  ! =  Selector : : SimpleSelector : : Type : : PseudoElement ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  simple_selector . pseudo_element ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-13 15:49:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								static  NonnullRefPtr < Selector >  create_invalid_selector ( Selector : : Combinator  combinator ,  Vector < ComponentValue >  component_values )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // Trim leading and trailing whitespace
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    while  ( ! component_values . is_empty ( )  & &  component_values . first ( ) . is ( Token : : Type : : Whitespace ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        component_values . take_first ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    while  ( ! component_values . is_empty ( )  & &  component_values . last ( ) . is ( Token : : Type : : Whitespace ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        component_values . take_last ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    Selector : : SimpleSelector  simple  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        . type  =  Selector : : SimpleSelector : : Type : : Invalid , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        . value  =  Selector : : SimpleSelector : : Invalid  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            . component_values  =  move ( component_values ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    Selector : : CompoundSelector  compound  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        . combinator  =  combinator , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        . simple_selectors  =  {  move ( simple )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  Selector : : create ( {  move ( compound )  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								template < typename  T >  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Parser : : ParseErrorOr < SelectorList >  Parser : : parse_a_selector_list ( TokenStream < T > &  tokens ,  SelectorType  mode ,  SelectorParsingMode  parsing_mode )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-10-17 12:01:13 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    SelectorList  selectors ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-22 19:48:50 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    for  ( ; ; )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  selector_parts  =  consume_a_list_of_component_values ( tokens ,  Token : : Type : : Comma ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  stream  =  TokenStream ( selector_parts ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  selector  =  parse_complex_selector ( stream ,  mode ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( selector . is_error ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-13 15:49:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( parsing_mode  = =  SelectorParsingMode : : Forgiving )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                // Keep the invalid selector around for serialization and nesting
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                auto  combinator  =  mode  = =  SelectorType : : Standalone  ?  Selector : : Combinator : : None  :  Selector : : Combinator : : Descendant ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                selectors . append ( create_invalid_selector ( combinator ,  move ( selector_parts ) ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-22 19:48:50 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  selector . error ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-13 15:49:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-22 19:48:50 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            selectors . append ( selector . release_value ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-22 19:48:50 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( tokens . is_empty ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        tokens . discard_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( selectors . is_empty ( )  & &  parsing_mode  ! =  SelectorParsingMode : : Forgiving ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  selectors ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								template  Parser : : ParseErrorOr < SelectorList >  Parser : : parse_a_selector_list ( TokenStream < ComponentValue > & ,  SelectorType ,  SelectorParsingMode ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								template  Parser : : ParseErrorOr < SelectorList >  Parser : : parse_a_selector_list ( TokenStream < Token > & ,  SelectorType ,  SelectorParsingMode ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Parser : : ParseErrorOr < NonnullRefPtr < Selector > >  Parser : : parse_complex_selector ( TokenStream < ComponentValue > &  tokens ,  SelectorType  mode )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    Vector < Selector : : CompoundSelector >  compound_selectors ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  first_selector  =  TRY ( parse_compound_selector ( tokens ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! first_selector . has_value ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( mode  = =  SelectorType : : Standalone )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( first_selector - > combinator  ! =  Selector : : Combinator : : Descendant ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        first_selector - > combinator  =  Selector : : Combinator : : None ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    compound_selectors . append ( first_selector . release_value ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    while  ( tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  compound_selector  =  TRY ( parse_compound_selector ( tokens ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! compound_selector . has_value ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        compound_selectors . append ( compound_selector . release_value ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( compound_selectors . is_empty ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  Selector : : create ( move ( compound_selectors ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Parser : : ParseErrorOr < Optional < Selector : : CompoundSelector > >  Parser : : parse_compound_selector ( TokenStream < ComponentValue > &  tokens )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  combinator  =  parse_selector_combinator ( tokens ) . value_or ( Selector : : Combinator : : Descendant ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    Vector < Selector : : SimpleSelector >  simple_selectors ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    while  ( tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  component  =  TRY ( parse_simple_selector ( tokens ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! component . has_value ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            break ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-08 20:14:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( component - > type  = =  Selector : : SimpleSelector : : Type : : TagName  & &  ! simple_selectors . is_empty ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // Tag-name selectors can only go at the beginning of a compound selector.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        simple_selectors . append ( component . release_value ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-21 16:58:18 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( simple_selectors . is_empty ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( tokens . has_next_token ( )  | |  combinator  ! =  Selector : : Combinator : : Descendant ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Optional < Selector : : CompoundSelector >  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-21 16:58:18 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  Selector : : CompoundSelector  {  combinator ,  move ( simple_selectors )  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Optional < Selector : : Combinator >  Parser : : parse_selector_combinator ( TokenStream < ComponentValue > &  tokens )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  current_value  =  tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( current_value . is ( Token : : Type : : Delim ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        switch  ( current_value . token ( ) . delim ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' > ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : Combinator : : ImmediateChild ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' + ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : Combinator : : NextSibling ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' ~ ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : Combinator : : SubsequentSibling ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' | ' :  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  next  =  tokens . next_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( next . is ( Token : : Type : : EndOfFile ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( next . is_delim ( ' | ' ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                tokens . discard_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  Selector : : Combinator : : Column ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    tokens . reconsume_current_input_token ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Optional < Selector : : SimpleSelector : : QualifiedName >  Parser : : parse_selector_qualified_name ( TokenStream < ComponentValue > &  tokens ,  AllowWildcardName  allow_wildcard_name )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_name  =  [ ] ( ComponentValue  const &  token )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  token . is_delim ( ' * ' )  | |  token . is ( Token : : Type : : Ident ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  get_name  =  [ ] ( ComponentValue  const &  token )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( token . is_delim ( ' * ' ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 16:18:26 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            return  " * " _fly_string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  token . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // There are 3 possibilities here:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // (Where <name> and <namespace> are either an <ident> or a `*` delim)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // 1) `|<name>`
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // 2) `<namespace>|<name>`
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // 3) `<name>`
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // Whitespace is forbidden between any of these parts. https://www.w3.org/TR/selectors-4/#white-space
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  transaction  =  tokens . begin_transaction ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-31 21:43:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  first_token  =  tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_token . is_delim ( ' | ' ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // Case 1: `|<name>`
 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( is_name ( tokens . next_token ( ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-31 21:43:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  name_token  =  tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( allow_wildcard_name  = =  AllowWildcardName : : No  & &  name_token . is_delim ( ' * ' ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : QualifiedName  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . namespace_type  =  Selector : : SimpleSelector : : QualifiedName : : NamespaceType : : None , 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 16:18:26 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                . name  =  get_name ( name_token ) , 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! is_name ( first_token ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( tokens . next_token ( ) . is_delim ( ' | ' )  & &  is_name ( tokens . peek_token ( 1 ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // Case 2: `<namespace>|<name>`
 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        tokens . discard_a_token ( ) ;  // `|`
 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 16:18:26 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  namespace_  =  get_name ( first_token ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  name  =  get_name ( tokens . consume_a_token ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( allow_wildcard_name  = =  AllowWildcardName : : No  & &  name  = =  " * " sv ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  namespace_type  =  namespace_  = =  " * " sv 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            ?  Selector : : SimpleSelector : : QualifiedName : : NamespaceType : : Any 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            :  Selector : : SimpleSelector : : QualifiedName : : NamespaceType : : Named ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-06-23 22:40:37 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        // https://www.w3.org/TR/selectors-4/#invalid
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // a simple selector containing an undeclared namespace prefix is invalid
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( namespace_type  = =  Selector : : SimpleSelector : : QualifiedName : : NamespaceType : : Named  & &  ! m_declared_namespaces . contains ( namespace_ ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-06-09 22:33:36 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Selector : : SimpleSelector : : QualifiedName  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            . namespace_type  =  namespace_type , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            . namespace_  =  namespace_ , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            . name  =  name , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // Case 3: `<name>`
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto &  name_token  =  first_token ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( allow_wildcard_name  = =  AllowWildcardName : : No  & &  name_token . is_delim ( ' * ' ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  Selector : : SimpleSelector : : QualifiedName  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        . namespace_type  =  Selector : : SimpleSelector : : QualifiedName : : NamespaceType : : Default , 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 16:18:26 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        . name  =  get_name ( name_token ) , 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Parser : : ParseErrorOr < Selector : : SimpleSelector >  Parser : : parse_attribute_simple_selector ( ComponentValue  const &  first_value )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  attribute_tokens  =  TokenStream  {  first_value . block ( ) . value  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    attribute_tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! attribute_tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        dbgln_if ( CSS_PARSER_DEBUG ,  " CSS attribute selector is empty! " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  maybe_qualified_name  =  parse_selector_qualified_name ( attribute_tokens ,  AllowWildcardName : : No ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! maybe_qualified_name . has_value ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        dbgln_if ( CSS_PARSER_DEBUG ,  " Expected qualified-name for attribute name, got: '{}' " ,  attribute_tokens . next_token ( ) . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-22 13:33:48 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  qualified_name  =  maybe_qualified_name . release_value ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    Selector : : SimpleSelector  simple_selector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        . type  =  Selector : : SimpleSelector : : Type : : Attribute , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        . value  =  Selector : : SimpleSelector : : Attribute  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            . match_type  =  Selector : : SimpleSelector : : Attribute : : MatchType : : HasAttribute , 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-22 13:33:48 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            . qualified_name  =  qualified_name , 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-18 21:17:08 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            . case_type  =  Selector : : SimpleSelector : : Attribute : : CaseType : : DefaultMatch , 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    attribute_tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! attribute_tokens . has_next_token ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  simple_selector ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  delim_part  =  attribute_tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! delim_part . is ( Token : : Type : : Delim ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        dbgln_if ( CSS_PARSER_DEBUG ,  " Expected a delim for attribute comparison, got: '{}' " ,  delim_part . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( delim_part . token ( ) . delim ( )  = =  ' = ' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        simple_selector . attribute ( ) . match_type  =  Selector : : SimpleSelector : : Attribute : : MatchType : : ExactValueMatch ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! attribute_tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Attribute selector ended part way through a match type. " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  delim_second_part  =  attribute_tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! delim_second_part . is_delim ( ' = ' ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Expected a double delim for attribute comparison, got: '{}{}' " ,  delim_part . to_debug_string ( ) ,  delim_second_part . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        switch  ( delim_part . token ( ) . delim ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' ~ ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            simple_selector . attribute ( ) . match_type  =  Selector : : SimpleSelector : : Attribute : : MatchType : : ContainsWord ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' * ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            simple_selector . attribute ( ) . match_type  =  Selector : : SimpleSelector : : Attribute : : MatchType : : ContainsString ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' | ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            simple_selector . attribute ( ) . match_type  =  Selector : : SimpleSelector : : Attribute : : MatchType : : StartsWithSegment ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' ^ ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            simple_selector . attribute ( ) . match_type  =  Selector : : SimpleSelector : : Attribute : : MatchType : : StartsWithString ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' $ ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            simple_selector . attribute ( ) . match_type  =  Selector : : SimpleSelector : : Attribute : : MatchType : : EndsWithString ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            attribute_tokens . reconsume_current_input_token ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    attribute_tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! attribute_tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        dbgln_if ( CSS_PARSER_DEBUG ,  " Attribute selector ended without a value to match. " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  value_part  =  attribute_tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! value_part . is ( Token : : Type : : Ident )  & &  ! value_part . is ( Token : : Type : : String ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        dbgln_if ( CSS_PARSER_DEBUG ,  " Expected a string or ident for the value to match attribute against, got: '{}' " ,  value_part . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-09 09:24:41 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  value_string  =  value_part . token ( ) . is ( Token : : Type : : Ident )  ?  value_part . token ( ) . ident ( )  :  value_part . token ( ) . string ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    simple_selector . attribute ( ) . value  =  value_string . to_string ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    attribute_tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // Handle case-sensitivity suffixes. https://www.w3.org/TR/selectors-4/#attribute-case
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( attribute_tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  case_sensitivity_part  =  attribute_tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( case_sensitivity_part . is ( Token : : Type : : Ident ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  case_sensitivity  =  case_sensitivity_part . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( case_sensitivity . equals_ignoring_ascii_case ( " i " sv ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                simple_selector . attribute ( ) . case_type  =  Selector : : SimpleSelector : : Attribute : : CaseType : : CaseInsensitiveMatch ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            }  else  if  ( case_sensitivity . equals_ignoring_ascii_case ( " s " sv ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                simple_selector . attribute ( ) . case_type  =  Selector : : SimpleSelector : : Attribute : : CaseType : : CaseSensitiveMatch ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                dbgln_if ( CSS_PARSER_DEBUG ,  " Expected a  \" i \"  or  \" s \"  attribute selector case sensitivity identifier, got: '{}' " ,  case_sensitivity_part . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Expected an attribute selector case sensitivity identifier, got: '{}' " ,  case_sensitivity_part . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-05-15 17:24:30 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    attribute_tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( attribute_tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        dbgln_if ( CSS_PARSER_DEBUG ,  " Was not expecting anything else inside attribute selector. " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  simple_selector ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Parser : : ParseErrorOr < Selector : : SimpleSelector >  Parser : : parse_pseudo_simple_selector ( TokenStream < ComponentValue > &  tokens )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  peek_token_ends_selector  =  [ & ] ( )  - >  bool  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  value  =  tokens . next_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ( value . is ( Token : : Type : : EndOfFile )  | |  value . is ( Token : : Type : : Whitespace )  | |  value . is ( Token : : Type : : Comma ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( peek_token_ends_selector ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    // Note that we already consumed one colon before we entered this function.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // FIXME: Don't do that.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    bool  is_pseudo_element  =  false ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( tokens . next_token ( ) . is ( Token : : Type : : Colon ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        is_pseudo_element  =  true ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        tokens . discard_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( peek_token_ends_selector ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( is_pseudo_element )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  name_token  =  tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        bool  is_function  =  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        FlyString  pseudo_name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( name_token . is ( Token : : Type : : Ident ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            pseudo_name  =  name_token . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        }  else  if  ( name_token . is_function ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            pseudo_name  =  name_token . function ( ) . name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            is_function  =  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Expected an ident or function token for pseudo-element, got: '{}' " ,  name_token . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        bool  is_aliased_pseudo  =  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  pseudo_element  =  pseudo_element_from_string ( pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! pseudo_element . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            pseudo_element  =  aliased_pseudo_element_from_string ( pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            is_aliased_pseudo  =  pseudo_element . has_value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( pseudo_element . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  metadata  =  pseudo_element_metadata ( * pseudo_element ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 12:18:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            // :has() is fussy about pseudo-elements inside it
 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-19 14:58:22 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( m_pseudo_class_context . contains_slow ( PseudoClass : : Has )  & &  ! is_has_allowed_pseudo_element ( * pseudo_element ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 12:18:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            Selector : : PseudoElementSelector : : Value  value  =  Empty  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( is_function )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                if  ( ! metadata . is_valid_as_function )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    dbgln_if ( CSS_PARSER_DEBUG ,  " Pseudo-element '::{}()' is not valid as a function. " ,  pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                // Parse arguments
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                TokenStream  function_tokens  {  name_token . function ( ) . value  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                function_tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                switch  ( metadata . parameter_type )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                case  PseudoElementMetadata : : ParameterType : : None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    if  ( function_tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        dbgln_if ( CSS_PARSER_DEBUG ,  " Pseudo-element '::{}()' invalid: Should have no arguments. " ,  pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-12 16:15:06 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                case  PseudoElementMetadata : : ParameterType : : CompoundSelector :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    auto  compound_selector_or_error  =  parse_compound_selector ( function_tokens ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    if  ( compound_selector_or_error . is_error ( )  | |  ! compound_selector_or_error . value ( ) . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        dbgln_if ( CSS_PARSER_DEBUG ,  " Failed to parse ::{}() parameter as a compound selector " ,  pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    auto  compound_selector  =  compound_selector_or_error . release_value ( ) . release_value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    compound_selector . combinator  =  Selector : : Combinator : : None ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    Vector  compound_selectors  {  move ( compound_selector )  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    value  =  Selector : : create ( move ( compound_selectors ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                case  PseudoElementMetadata : : ParameterType : : PTNameSelector :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    // <pt-name-selector> = '*' | <custom-ident>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    // https://drafts.csswg.org/css-view-transitions-1/#typedef-pt-name-selector
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    if  ( function_tokens . next_token ( ) . is_delim ( ' * ' ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        function_tokens . discard_a_token ( ) ;  // *
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        value  =  Selector : : PseudoElementSelector : : PTNameSelector  {  . is_universal  =  true  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    }  else  if  ( auto  custom_ident  =  parse_custom_ident ( function_tokens ,  { } ) ;  custom_ident . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        value  =  Selector : : PseudoElementSelector : : PTNameSelector  {  . value  =  custom_ident . release_value ( )  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    }  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-14 23:14:02 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                        dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid <pt-name-selector> in ::{}() - expected `*` or `<custom-ident>`, got `{}` " ,  pseudo_name ,  function_tokens . next_token ( ) . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    function_tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    if  ( function_tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-14 23:14:02 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                        dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid <pt-name-selector> in ::{}() - trailing tokens " ,  pseudo_name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                if  ( ! metadata . is_valid_as_identifier )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    dbgln_if ( CSS_PARSER_DEBUG ,  " Pseudo-element '::{}' is not valid as an identifier. " ,  pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // Aliased pseudo-elements behave like their target pseudo-element, but serialize as themselves. So store their
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // name like we do for unknown -webkit pseudos below.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( is_aliased_pseudo )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  Selector : : SimpleSelector : : Type : : PseudoElement , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . value  =  Selector : : PseudoElementSelector  {  pseudo_element . release_value ( ) ,  pseudo_name . to_string ( ) . to_ascii_lowercase ( ) ,  move ( value )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-19 16:36:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoElement , 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : PseudoElementSelector  {  pseudo_element . release_value ( ) ,  move ( value )  } 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-19 16:36:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 22:06:55 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        // https://www.w3.org/TR/selectors-4/#compat
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // All other pseudo-elements whose names begin with the string “-webkit-” (matched ASCII case-insensitively)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // and that are not functional notations must be treated as valid at parse time. (That is, ::-webkit-asdf is
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
										 
							
							
								        // valid at parse time, but ::-webkit-jkl() is not.) If they’  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // must be treated as matching nothing, and are unknown -webkit- pseudo-elements.
 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-24 13:56:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! is_function  & &  pseudo_name . starts_with_bytes ( " -webkit- " sv ,  CaseSensitivity : : CaseInsensitive ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 12:18:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            // :has() only allows a limited set of pseudo-elements inside it, which doesn't include unknown ones.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( m_pseudo_class_context . contains_slow ( PseudoClass : : Has ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 22:06:55 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoElement , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                // Unknown -webkit- pseudo-elements must be serialized in ASCII lowercase.
 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-20 16:56:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : PseudoElementSelector  {  PseudoElement : : UnknownWebKit ,  pseudo_name . to_string ( ) . to_ascii_lowercase ( )  } , 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 22:06:55 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 17:07:32 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( has_ignored_vendor_prefix ( pseudo_name ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : IncludesIgnoredVendorPrefix ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        dbgln_if ( CSS_PARSER_DEBUG ,  " Unrecognized pseudo-element: '::{}' " ,  pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( peek_token_ends_selector ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  pseudo_class_token  =  tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( pseudo_class_token . is ( Token : : Type : : Ident ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  pseudo_name  =  pseudo_class_token . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( has_ignored_vendor_prefix ( pseudo_name ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : IncludesIgnoredVendorPrefix ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  make_pseudo_class_selector  =  [ ] ( auto  pseudo_class )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoClass , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : SimpleSelector : : PseudoClassSelector  {  . type  =  pseudo_class  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( auto  pseudo_class  =  pseudo_class_from_string ( pseudo_name ) ;  pseudo_class . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! pseudo_class_metadata ( pseudo_class . value ( ) ) . is_valid_as_identifier )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                dbgln_if ( CSS_PARSER_DEBUG ,  " Pseudo-class ':{}' is only valid as a function " ,  pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  make_pseudo_class_selector ( pseudo_class . value ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // Single-colon syntax allowed for ::after, ::before, ::first-letter and ::first-line for compatibility.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // https://www.w3.org/TR/selectors/#pseudo-element-syntax
 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-19 14:58:22 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( auto  pseudo_element  =  pseudo_element_from_string ( pseudo_name ) ;  pseudo_element . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            switch  ( pseudo_element . value ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-20 16:56:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            case  PseudoElement : : After : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            case  PseudoElement : : Before : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            case  PseudoElement : : FirstLetter : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            case  PseudoElement : : FirstLine : 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 12:18:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                // :has() is fussy about pseudo-elements inside it
 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-19 14:58:22 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                if  ( m_pseudo_class_context . contains_slow ( PseudoClass : : Has )  & &  ! is_has_allowed_pseudo_element ( pseudo_element . value ( ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 12:18:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                    return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  Selector : : SimpleSelector : : Type : : PseudoElement , 
							 
						 
					
						
							
								
									
										
										
										
											2025-03-19 14:58:22 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                    . value  =  Selector : : PseudoElementSelector  {  pseudo_element . value ( )  } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        dbgln_if ( CSS_PARSER_DEBUG ,  " Unrecognized pseudo-class: ':{}' " ,  pseudo_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( pseudo_class_token . is_function ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  parse_nth_child_selector  =  [ this ] ( auto  pseudo_class ,  Vector < ComponentValue >  const &  function_values ,  bool  allow_of  =  false )  - >  ParseErrorOr < Selector : : SimpleSelector >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  tokens  =  TokenStream < ComponentValue > ( function_values ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  nth_child_pattern  =  parse_a_n_plus_b_pattern ( tokens ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! nth_child_pattern . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                dbgln_if ( CSS_PARSER_DEBUG ,  " !!! Invalid An+B format for {} " ,  pseudo_class_name ( pseudo_class ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  Selector : : SimpleSelector : : Type : : PseudoClass , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . value  =  Selector : : SimpleSelector : : PseudoClassSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        . type  =  pseudo_class , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        . nth_child_pattern  =  nth_child_pattern . release_value ( )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! allow_of ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // Parse the `of <selector-list>` syntax
 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  maybe_of  =  tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 12:08:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! maybe_of . is_ident ( " of " sv ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  selector_list  =  TRY ( parse_a_selector_list ( tokens ,  SelectorType : : Standalone ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( tokens . has_next_token ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoClass , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : SimpleSelector : : PseudoClassSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  pseudo_class , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . nth_child_pattern  =  nth_child_pattern . release_value ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . argument_selector_list  =  move ( selector_list )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  pseudo_function  =  pseudo_class_token . function ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  maybe_pseudo_class  =  pseudo_class_from_string ( pseudo_function . name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! maybe_pseudo_class . has_value ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Unrecognized pseudo-class function: ':{}'() " ,  pseudo_function . name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  pseudo_class  =  maybe_pseudo_class . value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  metadata  =  pseudo_class_metadata ( pseudo_class ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! metadata . is_valid_as_function )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Pseudo-class ':{}' is not valid as a function " ,  pseudo_function . name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( pseudo_function . value . is_empty ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Empty :{}() selector " ,  pseudo_function . name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 12:18:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        // "The :has() pseudo-class cannot be nested; :has() is not valid within :has()."
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // https://drafts.csswg.org/selectors/#relational
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( pseudo_class  = =  PseudoClass : : Has  & &  m_pseudo_class_context . contains_slow ( PseudoClass : : Has ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " :has() is not allowed inside :has() " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        m_pseudo_class_context . append ( pseudo_class ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        ScopeGuard  guard  =  [ & ]  {  m_pseudo_class_context . take_last ( ) ;  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        switch  ( metadata . parameter_type )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : ANPlusB : 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            return  parse_nth_child_selector ( pseudo_class ,  pseudo_function . value ,  false ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : ANPlusBOf : 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            return  parse_nth_child_selector ( pseudo_class ,  pseudo_function . value ,  true ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : CompoundSelector :  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  function_token_stream  =  TokenStream ( pseudo_function . value ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  compound_selector_or_error  =  parse_compound_selector ( function_token_stream ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( compound_selector_or_error . is_error ( )  | |  ! compound_selector_or_error . value ( ) . has_value ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                dbgln_if ( CSS_PARSER_DEBUG ,  " Failed to parse :{}() parameter as a compound selector " ,  pseudo_function . name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-23 15:03:27 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  compound_selector  =  compound_selector_or_error . release_value ( ) . release_value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            compound_selector . combinator  =  Selector : : Combinator : : None ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            Vector  compound_selectors  {  move ( compound_selector )  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  selector  =  Selector : : create ( move ( compound_selectors ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoClass , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : SimpleSelector : : PseudoClassSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  pseudo_class , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . argument_selector_list  =  {  move ( selector )  }  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-13 09:19:30 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : ForgivingRelativeSelectorList : 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : ForgivingSelectorList :  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  function_token_stream  =  TokenStream ( pseudo_function . value ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-13 09:19:30 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  selector_type  =  metadata . parameter_type  = =  PseudoClassMetadata : : ParameterType : : ForgivingSelectorList 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                ?  SelectorType : : Standalone 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                :  SelectorType : : Relative ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // NOTE: Because it's forgiving, even complete garbage will parse OK as an empty selector-list.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-13 09:19:30 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  argument_selector_list  =  MUST ( parse_a_selector_list ( function_token_stream ,  selector_type ,  SelectorParsingMode : : Forgiving ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoClass , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : SimpleSelector : : PseudoClassSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  pseudo_class , 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 12:48:14 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                    . is_forgiving  =  true , 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . argument_selector_list  =  move ( argument_selector_list )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-12 18:11:50 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : Ident :  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  function_token_stream  =  TokenStream ( pseudo_function . value ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            function_token_stream . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-05-16 14:57:18 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  maybe_ident_token  =  function_token_stream . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            function_token_stream . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-05-16 14:57:18 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! maybe_ident_token . is ( Token : : Type : : Ident )  | |  function_token_stream . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                dbgln_if ( CSS_PARSER_DEBUG ,  " Failed to parse :{}() parameter: not an ident " ,  pseudo_function . name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-12 18:11:50 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-05-16 14:57:18 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto &  ident  =  maybe_ident_token . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-12 18:11:50 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoClass , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : SimpleSelector : : PseudoClassSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  pseudo_class , 
							 
						 
					
						
							
								
									
										
										
										
											2025-05-16 14:57:18 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                    . ident  =  Selector : : SimpleSelector : : PseudoClassSelector : : Ident  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        . keyword  =  keyword_from_string ( ident ) . value_or ( Keyword : : Invalid ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                        . string_value  =  ident , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-12 18:11:50 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : LanguageRanges :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            Vector < FlyString >  languages ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  function_token_stream  =  TokenStream ( pseudo_function . value ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  language_token_lists  =  parse_a_comma_separated_list_of_component_values ( function_token_stream ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-31 21:43:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            for  ( auto  const &  language_token_list  :  language_token_lists )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                auto  language_token_stream  =  TokenStream ( language_token_list ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                language_token_stream . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-31 21:43:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                auto  const &  language_token  =  language_token_stream . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                if  ( ! ( language_token . is ( Token : : Type : : Ident )  | |  language_token . is ( Token : : Type : : String ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                    dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid language range in :{}() - not a string/ident " ,  pseudo_function . name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                auto  language_string  =  language_token . is ( Token : : Type : : String )  ?  language_token . token ( ) . string ( )  :  language_token . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 16:18:26 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                languages . append ( language_string ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                language_token_stream . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                if  ( language_token_stream . has_next_token ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                    dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid language range in :{}() - trailing tokens " ,  pseudo_function . name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoClass , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : SimpleSelector : : PseudoClassSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  pseudo_class , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . languages  =  move ( languages )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 11:22:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : RelativeSelectorList : 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : SelectorList :  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-11 11:17:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  function_token_stream  =  TokenStream ( pseudo_function . value ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-14 11:22:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  selector_type  =  metadata . parameter_type  = =  PseudoClassMetadata : : ParameterType : : SelectorList 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                ?  SelectorType : : Standalone 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                :  SelectorType : : Relative ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  not_selector  =  TRY ( parse_a_selector_list ( function_token_stream ,  selector_type ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : PseudoClass , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : SimpleSelector : : PseudoClassSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . type  =  pseudo_class , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                    . argument_selector_list  =  move ( not_selector )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  PseudoClassMetadata : : ParameterType : : None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // `None` means this is not a function-type pseudo-class, so this state should be impossible.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            VERIFY_NOT_REACHED ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    dbgln_if ( CSS_PARSER_DEBUG ,  " Unexpected Block in pseudo-class name, expected a function or identifier. '{}' " ,  pseudo_class_token . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Parser : : ParseErrorOr < Optional < Selector : : SimpleSelector > >  Parser : : parse_simple_selector ( TokenStream < ComponentValue > &  tokens )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  peek_token_ends_selector  =  [ & ] ( )  - >  bool  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  value  =  tokens . next_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  ( value . is ( Token : : Type : : EndOfFile )  | |  value . is ( Token : : Type : : Whitespace )  | |  value . is ( Token : : Type : : Comma ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( peek_token_ends_selector ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Optional < Selector : : SimpleSelector >  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // Handle universal and tag-name types together, since both can be namespaced
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( auto  qualified_name  =  parse_selector_qualified_name ( tokens ,  AllowWildcardName : : Yes ) ;  qualified_name . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( qualified_name - > name . name  = =  " * " sv )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : Universal , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  qualified_name . release_value ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            . type  =  Selector : : SimpleSelector : : Type : : TagName , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            . value  =  qualified_name . release_value ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  first_value  =  tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_value . is ( Token : : Type : : Delim ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        u32  delim  =  first_value . token ( ) . delim ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        switch  ( delim )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' * ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // Handled already
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            VERIFY_NOT_REACHED ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-15 12:00:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' & ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : Nesting , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        case  ' . ' :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( peek_token_ends_selector ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  class_name_value  =  tokens . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            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  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                . type  =  Selector : : SimpleSelector : : Type : : Class , 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 16:18:26 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								                . value  =  Selector : : SimpleSelector : : Name  {  class_name_value . token ( ) . ident ( )  } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        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  Optional < Selector : : SimpleSelector >  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        default : 
							 
						 
					
						
							
								
									
										
										
										
											2025-05-16 16:06:35 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Unrecognized delimiter in selector: '{}' " ,  first_value . token ( ) . to_string ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : 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  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Selector : : SimpleSelector  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            . type  =  Selector : : SimpleSelector : : Type : : Id , 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 16:18:26 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            . value  =  Selector : : SimpleSelector : : Name  {  first_value . token ( ) . hash_value ( )  } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_value . is_block ( )  & &  first_value . block ( ) . is_square ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  TRY ( parse_attribute_simple_selector ( first_value ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_value . is ( Token : : Type : : Colon ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  TRY ( parse_pseudo_simple_selector ( tokens ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-05-16 16:06:35 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid simple selector: {} " ,  first_value . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Optional < Selector : : SimpleSelector : : ANPlusBPattern >  Parser : : parse_a_n_plus_b_pattern ( TokenStream < ComponentValue > &  values )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  transaction  =  values . begin_transaction ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  syntax_error  =  [ & ] ( )  - >  Optional < Selector : : SimpleSelector : : ANPlusBPattern >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  constexpr  ( CSS_PARSER_DEBUG )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid An+B value: " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            values . dump_all_tokens ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_sign  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  value . is ( Token : : Type : : Delim )  & &  ( value . token ( ) . delim ( )  = =  ' + '  | |  value . token ( ) . delim ( )  = =  ' - ' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_n_dimension  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . is ( Token : : Type : : Dimension ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . token ( ) . number ( ) . is_integer ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . token ( ) . dimension_unit ( ) . equals_ignoring_ascii_case ( " n " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_ndash_dimension  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . is ( Token : : Type : : Dimension ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . token ( ) . number ( ) . is_integer ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . token ( ) . dimension_unit ( ) . equals_ignoring_ascii_case ( " n- " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_ndashdigit_dimension  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . is ( Token : : Type : : Dimension ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . token ( ) . number ( ) . is_integer ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  dimension_unit  =  value . token ( ) . dimension_unit ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-26 10:40:08 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! dimension_unit . starts_with_bytes ( " n- " sv ,  CaseSensitivity : : CaseInsensitive ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-26 10:40:08 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        for  ( size_t  i  =  2 ;  i  <  dimension_unit . bytes_as_string_view ( ) . length ( ) ;  + + i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! is_ascii_digit ( dimension_unit . bytes_as_string_view ( ) [ i ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_ndashdigit_ident  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . is ( Token : : Type : : Ident ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  ident  =  value . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-07 00:22:33 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! ident . starts_with_bytes ( " n- " sv ,  CaseSensitivity : : CaseInsensitive ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-07 00:22:33 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        for  ( size_t  i  =  2 ;  i  <  ident . bytes_as_string_view ( ) . length ( ) ;  + + i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! is_ascii_digit ( ident . bytes_as_string_view ( ) [ i ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_dashndashdigit_ident  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! value . is ( Token : : Type : : Ident ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  ident  =  value . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-07 00:22:33 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! ident . starts_with_bytes ( " -n- " sv ,  CaseSensitivity : : CaseInsensitive ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-07 00:22:33 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ident . bytes_as_string_view ( ) . length ( )  = =  3 ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  false ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-07 00:22:33 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        for  ( size_t  i  =  3 ;  i  <  ident . bytes_as_string_view ( ) . length ( ) ;  + + i )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! is_ascii_digit ( ident . bytes_as_string_view ( ) [ i ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_integer  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  value . is ( Token : : Type : : Number )  & &  value . token ( ) . number ( ) . is_integer ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_signed_integer  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  value . is ( Token : : Type : : Number )  & &  value . token ( ) . number ( ) . is_integer_with_explicit_sign ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  is_signless_integer  =  [ ] ( ComponentValue  const &  value )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  value . is ( Token : : Type : : Number )  & &  ! value . token ( ) . number ( ) . is_integer_with_explicit_sign ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // https://www.w3.org/TR/css-syntax-3/#the-anb-type
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // Unfortunately these can't be in the same order as in the spec.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  first_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // odd | even
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_value . is ( Token : : Type : : Ident ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  ident  =  first_value . token ( ) . ident ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ident . equals_ignoring_ascii_case ( " odd " sv ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  2 ,  1  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ident . equals_ignoring_ascii_case ( " even " sv ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  2 ,  0  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( is_integer ( first_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        int  b  =  first_value . token ( ) . to_integer ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Selector : : SimpleSelector : : ANPlusBPattern  {  0 ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <n-dimension>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <n-dimension> <signed-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <n-dimension> ['+' | '-'] <signless-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( is_n_dimension ( first_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        int  a  =  first_value . token ( ) . dimension_value_int ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // <n-dimension> <signed-integer>
 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( is_signed_integer ( values . next_token ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            int  b  =  values . consume_a_token ( ) . token ( ) . to_integer ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  a ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // <n-dimension> ['+' | '-'] <signless-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  child_transaction  =  transaction . create_child ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  second_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  third_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( is_sign ( second_value )  & &  is_signless_integer ( third_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                int  b  =  third_value . token ( ) . to_integer ( )  *  ( second_value . is_delim ( ' + ' )  ?  1  :  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                child_transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  Selector : : SimpleSelector : : ANPlusBPattern  {  a ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // <n-dimension>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Selector : : SimpleSelector : : ANPlusBPattern  {  a ,  0  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <ndash-dimension> <signless-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( is_ndash_dimension ( first_value ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  second_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( is_signless_integer ( second_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            int  a  =  first_value . token ( ) . dimension_value_int ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            int  b  =  - second_value . token ( ) . to_integer ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  a ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  syntax_error ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <ndashdigit-dimension>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( is_ndashdigit_dimension ( first_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  dimension  =  first_value . token ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        int  a  =  dimension . dimension_value_int ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-23 15:59:14 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  maybe_b  =  dimension . dimension_unit ( ) . bytes_as_string_view ( ) . substring_view ( 1 ) . to_number < int > ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( maybe_b . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  a ,  maybe_b . value ( )  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  syntax_error ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <dashndashdigit-ident>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( is_dashndashdigit_ident ( first_value ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-23 15:59:14 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  maybe_b  =  first_value . token ( ) . ident ( ) . bytes_as_string_view ( ) . substring_view ( 2 ) . to_number < int > ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( maybe_b . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  - 1 ,  maybe_b . value ( )  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  syntax_error ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // -n
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // -n <signed-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // -n ['+' | '-'] <signless-integer>
 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 12:08:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_value . is_ident ( " -n " sv ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // -n <signed-integer>
 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( is_signed_integer ( values . next_token ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            int  b  =  values . consume_a_token ( ) . token ( ) . to_integer ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  - 1 ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // -n ['+' | '-'] <signless-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  child_transaction  =  transaction . create_child ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  second_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  third_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( is_sign ( second_value )  & &  is_signless_integer ( third_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                int  b  =  third_value . token ( ) . to_integer ( )  *  ( second_value . is_delim ( ' + ' )  ?  1  :  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                child_transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  Selector : : SimpleSelector : : ANPlusBPattern  {  - 1 ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // -n
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Selector : : SimpleSelector : : ANPlusBPattern  {  - 1 ,  0  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // -n- <signless-integer>
 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 12:08:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_value . is_ident ( " -n- " sv ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  second_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( is_signless_integer ( second_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            int  b  =  - second_value . token ( ) . to_integer ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  - 1 ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  syntax_error ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // All that's left now are these:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† n
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† n <signed-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† n ['+' | '-'] <signless-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† n- <signless-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† <ndashdigit-ident>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // In all of these cases, the + is optional, and has no effect.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // So, we just skip the +, and carry on.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! first_value . is_delim ( ' + ' ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        values . reconsume_current_input_token ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // We do *not* skip whitespace here.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    auto  const &  first_after_plus  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† n
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† n <signed-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† n ['+' | '-'] <signless-integer>
 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 12:08:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_after_plus . is_ident ( " n " sv ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // '+'?† n <signed-integer>
 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( is_signed_integer ( values . next_token ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            int  b  =  values . consume_a_token ( ) . token ( ) . to_integer ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  1 ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // '+'?† n ['+' | '-'] <signless-integer>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  child_transaction  =  transaction . create_child ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  second_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  const &  third_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( is_sign ( second_value )  & &  is_signless_integer ( third_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                int  b  =  third_value . token ( ) . to_integer ( )  *  ( second_value . is_delim ( ' + ' )  ?  1  :  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                child_transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  Selector : : SimpleSelector : : ANPlusBPattern  {  1 ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // '+'?† n
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  Selector : : SimpleSelector : : ANPlusBPattern  {  1 ,  0  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† n- <signless-integer>
 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 12:08:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( first_after_plus . is_ident ( " n- " sv ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-09 12:29:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        values . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        auto  const &  second_value  =  values . consume_a_token ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( is_signless_integer ( second_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            int  b  =  - second_value . token ( ) . to_integer ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  1 ,  b  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  syntax_error ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // '+'?† <ndashdigit-ident>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( is_ndashdigit_ident ( first_after_plus ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-23 15:59:14 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								        auto  maybe_b  =  first_after_plus . token ( ) . ident ( ) . bytes_as_string_view ( ) . substring_view ( 1 ) . to_number < int > ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( maybe_b . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            transaction . commit ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  Selector : : SimpleSelector : : ANPlusBPattern  {  1 ,  maybe_b . value ( )  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  syntax_error ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  syntax_error ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-05-16 11:37:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
								
									
								 
							
							
								Optional < PageSelectorList >  Parser : : parse_as_page_selector_list ( )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    auto  selector_list  =  parse_a_page_selector_list ( m_token_stream ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    if  ( ! selector_list . is_error ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        return  selector_list . release_value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								template < typename  T >  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								Parser : : ParseErrorOr < PageSelectorList >  Parser : : parse_a_page_selector_list ( TokenStream < T > &  tokens )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // https://drafts.csswg.org/css-page-3/#syntax-page-selector
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <page-selector-list> = <page-selector>#
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <page-selector> = [ <ident-token>? <pseudo-page>* ]!
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    // <pseudo-page> = : [ left | right | first | blank ]
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    PageSelectorList  selector_list ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    while  ( tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // First optional ident
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        Optional < FlyString >  maybe_ident ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( tokens . next_token ( ) . is ( Token : : Type : : Ident ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            maybe_ident  =  static_cast < Token > ( tokens . consume_a_token ( ) ) . ident ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        // Then an optional series of pseudo-classes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        Vector < PagePseudoClass >  pseudo_classes ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        while  ( tokens . next_token ( ) . is ( Token : : Type : : Colon ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            tokens . discard_a_token ( ) ;  // :
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! tokens . next_token ( ) . is ( Token : : Type : : Ident ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid @page selector: pseudo-class is not an ident: `{}` " ,  tokens . next_token ( ) . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            auto  pseudo_class_name  =  static_cast < Token > ( tokens . consume_a_token ( ) ) . ident ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( auto  pseudo_class  =  page_pseudo_class_from_string ( pseudo_class_name ) ;  pseudo_class . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                pseudo_classes . append ( * pseudo_class ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid @page selector: unrecognized pseudo-class `:{}` " ,  pseudo_class_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( ! maybe_ident . has_value ( )  & &  pseudo_classes . is_empty ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            // Nothing parsed
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid @page selector: is empty " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        selector_list . empend ( move ( maybe_ident ) ,  move ( pseudo_classes ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        if  ( tokens . next_token ( ) . is ( Token : : Type : : Comma ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            tokens . discard_a_token ( ) ;  // ,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            tokens . discard_whitespace ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            if  ( ! tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid @page selector: trailing comma " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								                return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        }  else  if  ( tokens . has_next_token ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            dbgln_if ( CSS_PARSER_DEBUG ,  " Invalid @page selector: trailing token `{}` " ,  tokens . next_token ( ) . to_debug_string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								            return  ParseError : : SyntaxError ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								    return  selector_list ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								template  Parser : : ParseErrorOr < PageSelectorList >  Parser : : parse_a_page_selector_list ( TokenStream < ComponentValue > & ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								template  Parser : : ParseErrorOr < PageSelectorList >  Parser : : parse_a_page_selector_list ( TokenStream < Token > & ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-17 15:18:41 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
								
									
								 
							
							
								}