@@ -39,6 +39,28 @@ impl ParserState {
3939 }
4040}
4141
42+ /// When parsing until a given token, sometimes the caller knows that parsing is going to restart
43+ /// at some earlier point, and consuming until we find a top level delimiter is just wasted work.
44+ ///
45+ /// In that case, callers can pass ParseUntilErrorBehavior::Stop to avoid doing all that wasted
46+ /// work.
47+ ///
48+ /// This is important for things like CSS nesting, where something like:
49+ ///
50+ /// foo:is(..) {
51+ /// ...
52+ /// }
53+ ///
54+ /// Would need to scan the whole {} block to find a semicolon, only for parsing getting restarted
55+ /// as a qualified rule later.
56+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
57+ pub enum ParseUntilErrorBehavior {
58+ /// Consume until we see the relevant delimiter or the end of the stream.
59+ Consume ,
60+ /// Eagerly error.
61+ Stop ,
62+ }
63+
4264/// Details about a `BasicParseError`
4365#[ derive( Clone , Debug , PartialEq ) ]
4466pub enum BasicParseErrorKind < ' i > {
@@ -766,7 +788,7 @@ impl<'i: 't, 't> Parser<'i, 't> {
766788 where
767789 F : for < ' tt > FnOnce ( & mut Parser < ' i , ' tt > ) -> Result < T , ParseError < ' i , E > > ,
768790 {
769- parse_until_before ( self , delimiters, parse)
791+ parse_until_before ( self , delimiters, ParseUntilErrorBehavior :: Consume , parse)
770792 }
771793
772794 /// Like `parse_until_before`, but also consume the delimiter token.
@@ -783,7 +805,7 @@ impl<'i: 't, 't> Parser<'i, 't> {
783805 where
784806 F : for < ' tt > FnOnce ( & mut Parser < ' i , ' tt > ) -> Result < T , ParseError < ' i , E > > ,
785807 {
786- parse_until_after ( self , delimiters, parse)
808+ parse_until_after ( self , delimiters, ParseUntilErrorBehavior :: Consume , parse)
787809 }
788810
789811 /// Parse a <whitespace-token> and return its value.
@@ -1013,6 +1035,7 @@ impl<'i: 't, 't> Parser<'i, 't> {
10131035pub fn parse_until_before < ' i : ' t , ' t , F , T , E > (
10141036 parser : & mut Parser < ' i , ' t > ,
10151037 delimiters : Delimiters ,
1038+ error_behavior : ParseUntilErrorBehavior ,
10161039 parse : F ,
10171040) -> Result < T , ParseError < ' i , E > >
10181041where
@@ -1028,6 +1051,9 @@ where
10281051 stop_before : delimiters,
10291052 } ;
10301053 result = delimited_parser. parse_entirely ( parse) ;
1054+ if error_behavior == ParseUntilErrorBehavior :: Stop && result. is_err ( ) {
1055+ return result;
1056+ }
10311057 if let Some ( block_type) = delimited_parser. at_start_of {
10321058 consume_until_end_of_block ( block_type, & mut delimited_parser. input . tokenizer ) ;
10331059 }
@@ -1051,12 +1077,16 @@ where
10511077pub fn parse_until_after < ' i : ' t , ' t , F , T , E > (
10521078 parser : & mut Parser < ' i , ' t > ,
10531079 delimiters : Delimiters ,
1080+ error_behavior : ParseUntilErrorBehavior ,
10541081 parse : F ,
10551082) -> Result < T , ParseError < ' i , E > >
10561083where
10571084 F : for < ' tt > FnOnce ( & mut Parser < ' i , ' tt > ) -> Result < T , ParseError < ' i , E > > ,
10581085{
1059- let result = parser. parse_until_before ( delimiters, parse) ;
1086+ let result = parse_until_before ( parser, delimiters, error_behavior, parse) ;
1087+ if error_behavior == ParseUntilErrorBehavior :: Stop && result. is_err ( ) {
1088+ return result;
1089+ }
10601090 let next_byte = parser. input . tokenizer . next_byte ( ) ;
10611091 if next_byte. is_some ( )
10621092 && !parser
0 commit comments