@@ -39,6 +39,28 @@ impl ParserState {
39
39
}
40
40
}
41
41
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
+
42
64
/// Details about a `BasicParseError`
43
65
#[ derive( Clone , Debug , PartialEq ) ]
44
66
pub enum BasicParseErrorKind < ' i > {
@@ -766,7 +788,7 @@ impl<'i: 't, 't> Parser<'i, 't> {
766
788
where
767
789
F : for < ' tt > FnOnce ( & mut Parser < ' i , ' tt > ) -> Result < T , ParseError < ' i , E > > ,
768
790
{
769
- parse_until_before ( self , delimiters, parse)
791
+ parse_until_before ( self , delimiters, ParseUntilErrorBehavior :: Consume , parse)
770
792
}
771
793
772
794
/// Like `parse_until_before`, but also consume the delimiter token.
@@ -783,7 +805,7 @@ impl<'i: 't, 't> Parser<'i, 't> {
783
805
where
784
806
F : for < ' tt > FnOnce ( & mut Parser < ' i , ' tt > ) -> Result < T , ParseError < ' i , E > > ,
785
807
{
786
- parse_until_after ( self , delimiters, parse)
808
+ parse_until_after ( self , delimiters, ParseUntilErrorBehavior :: Consume , parse)
787
809
}
788
810
789
811
/// Parse a <whitespace-token> and return its value.
@@ -1013,6 +1035,7 @@ impl<'i: 't, 't> Parser<'i, 't> {
1013
1035
pub fn parse_until_before < ' i : ' t , ' t , F , T , E > (
1014
1036
parser : & mut Parser < ' i , ' t > ,
1015
1037
delimiters : Delimiters ,
1038
+ error_behavior : ParseUntilErrorBehavior ,
1016
1039
parse : F ,
1017
1040
) -> Result < T , ParseError < ' i , E > >
1018
1041
where
@@ -1028,6 +1051,9 @@ where
1028
1051
stop_before : delimiters,
1029
1052
} ;
1030
1053
result = delimited_parser. parse_entirely ( parse) ;
1054
+ if error_behavior == ParseUntilErrorBehavior :: Stop && result. is_err ( ) {
1055
+ return result;
1056
+ }
1031
1057
if let Some ( block_type) = delimited_parser. at_start_of {
1032
1058
consume_until_end_of_block ( block_type, & mut delimited_parser. input . tokenizer ) ;
1033
1059
}
@@ -1051,12 +1077,16 @@ where
1051
1077
pub fn parse_until_after < ' i : ' t , ' t , F , T , E > (
1052
1078
parser : & mut Parser < ' i , ' t > ,
1053
1079
delimiters : Delimiters ,
1080
+ error_behavior : ParseUntilErrorBehavior ,
1054
1081
parse : F ,
1055
1082
) -> Result < T , ParseError < ' i , E > >
1056
1083
where
1057
1084
F : for < ' tt > FnOnce ( & mut Parser < ' i , ' tt > ) -> Result < T , ParseError < ' i , E > > ,
1058
1085
{
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
+ }
1060
1090
let next_byte = parser. input . tokenizer . next_byte ( ) ;
1061
1091
if next_byte. is_some ( )
1062
1092
&& !parser
0 commit comments