@@ -1182,7 +1182,7 @@ impl Parser {
11821182 self . parse_class_set_expression ( ) ?
11831183 } ;
11841184 self . in_negated_class = saved_negated;
1185- if negated && ! Self :: class_set_expression_strings ( & expr) . is_empty ( ) {
1185+ if negated && Self :: class_set_expression_may_contain_strings ( & expr) {
11861186 return Err ( Error :: InvalidCharacterClass ) ;
11871187 }
11881188 self . expect ( ']' ) ?;
@@ -1413,6 +1413,9 @@ impl Parser {
14131413 self . in_negated_class = false ;
14141414 while self . peek_pair ( ) == Some ( ( '&' , '&' ) ) {
14151415 self . pos += 2 ; // consume '&&'
1416+ if self . peek ( ) == Some ( '&' ) {
1417+ return Err ( Error :: InvalidCharacterClass ) ;
1418+ }
14161419 operands. push ( self . parse_class_set_operand ( ) ?) ;
14171420 }
14181421 self . in_negated_class = saved_negated;
@@ -1454,93 +1457,38 @@ impl Parser {
14541457 Ok ( ( ) )
14551458 }
14561459
1457- fn get_string_property_strings ( name : & str ) -> std:: collections:: BTreeSet < Vec < u32 > > {
1458- let buf = libunicode_rust:: character_types:: get_string_property_data ( name) ;
1459- if buf. is_empty ( ) {
1460- return std:: collections:: BTreeSet :: new ( ) ;
1461- }
1462-
1463- let count = buf[ 0 ] as usize ;
1464- let mut strings = std:: collections:: BTreeSet :: new ( ) ;
1465- let mut offset = 1 ;
1466- for _ in 0 ..count {
1467- if offset >= buf. len ( ) {
1468- break ;
1469- }
1470- let len = buf[ offset] as usize ;
1471- offset += 1 ;
1472- if offset + len > buf. len ( ) {
1473- break ;
1474- }
1475- if len > 1 {
1476- strings. insert ( buf[ offset..offset + len] . to_vec ( ) ) ;
1477- }
1478- offset += len;
1479- }
1480- strings
1481- }
1482-
1483- fn class_set_expression_strings ( expr : & ClassSetExpression ) -> std:: collections:: BTreeSet < Vec < u32 > > {
1460+ /// - Union: may contain strings if ANY operand may contain strings
1461+ /// - Intersection: may contain strings if ALL operands may contain strings
1462+ /// (i.e., no operand is "purely characters")
1463+ /// - Subtraction: may contain strings if the leftmost operand may contain strings
1464+ fn class_set_expression_may_contain_strings ( expr : & ClassSetExpression ) -> bool {
14841465 match expr {
1485- ClassSetExpression :: Union ( operands) => {
1486- operands
1487- . iter ( )
1488- . fold ( std:: collections:: BTreeSet :: new ( ) , |mut strings, operand| {
1489- strings. extend ( Self :: class_set_operand_strings ( operand) ) ;
1490- strings
1491- } )
1492- }
1466+ ClassSetExpression :: Union ( operands) => operands. iter ( ) . any ( Self :: class_set_operand_may_contain_strings) ,
14931467 ClassSetExpression :: Intersection ( operands) => {
1494- let Some ( ( first, rest) ) = operands. split_first ( ) else {
1495- return std:: collections:: BTreeSet :: new ( ) ;
1496- } ;
1497- let mut strings = Self :: class_set_operand_strings ( first) ;
1498- for operand in rest {
1499- let operand_strings = Self :: class_set_operand_strings ( operand) ;
1500- strings. retain ( |string| operand_strings. contains ( string) ) ;
1501- }
1502- strings
1503- }
1504- ClassSetExpression :: Subtraction ( operands) => {
1505- let Some ( ( first, rest) ) = operands. split_first ( ) else {
1506- return std:: collections:: BTreeSet :: new ( ) ;
1507- } ;
1508- let mut strings = Self :: class_set_operand_strings ( first) ;
1509- for operand in rest {
1510- let operand_strings = Self :: class_set_operand_strings ( operand) ;
1511- strings. retain ( |string| !operand_strings. contains ( string) ) ;
1512- }
1513- strings
1468+ operands. iter ( ) . all ( Self :: class_set_operand_may_contain_strings)
15141469 }
1470+ ClassSetExpression :: Subtraction ( operands) => operands
1471+ . first ( )
1472+ . is_some_and ( Self :: class_set_operand_may_contain_strings) ,
15151473 }
15161474 }
15171475
1518- fn class_set_operand_strings ( operand : & ClassSetOperand ) -> std :: collections :: BTreeSet < Vec < u32 > > {
1476+ fn class_set_operand_may_contain_strings ( operand : & ClassSetOperand ) -> bool {
15191477 match operand {
15201478 ClassSetOperand :: NestedClass ( class) => {
15211479 if class. negated {
1522- return std :: collections :: BTreeSet :: new ( ) ;
1480+ return false ;
15231481 }
15241482 match & class. body {
1525- CharacterClassBody :: Ranges ( _) => std :: collections :: BTreeSet :: new ( ) ,
1526- CharacterClassBody :: UnicodeSet ( expr) => Self :: class_set_expression_strings ( expr) ,
1483+ CharacterClassBody :: Ranges ( _) => false ,
1484+ CharacterClassBody :: UnicodeSet ( expr) => Self :: class_set_expression_may_contain_strings ( expr) ,
15271485 }
15281486 }
15291487 ClassSetOperand :: UnicodeProperty ( property) => {
1530- if !property. negated && property. value . is_none ( ) && Self :: is_string_property ( & property. name ) {
1531- return Self :: get_string_property_strings ( & property. name ) ;
1532- }
1533- std:: collections:: BTreeSet :: new ( )
1534- }
1535- ClassSetOperand :: StringLiteral ( chars) => {
1536- if chars. len ( ) > 1 {
1537- return [ chars. iter ( ) . map ( |ch| * ch as u32 ) . collect ( ) ] . into_iter ( ) . collect ( ) ;
1538- }
1539- std:: collections:: BTreeSet :: new ( )
1540- }
1541- ClassSetOperand :: Char ( _) | ClassSetOperand :: Range ( _, _) | ClassSetOperand :: BuiltinClass ( _) => {
1542- std:: collections:: BTreeSet :: new ( )
1488+ !property. negated && property. value . is_none ( ) && Self :: is_string_property ( & property. name )
15431489 }
1490+ ClassSetOperand :: StringLiteral ( chars) => chars. len ( ) != 1 ,
1491+ ClassSetOperand :: Char ( _) | ClassSetOperand :: Range ( _, _) | ClassSetOperand :: BuiltinClass ( _) => false ,
15441492 }
15451493 }
15461494
0 commit comments