@@ -495,43 +495,72 @@ extension Parser {
495495 return CustomCC ( start, members, loc ( start. location. start) )
496496 }
497497
498+ mutating func parseCCCMember( ) throws -> CustomCC . Member ? {
499+ guard !source. isEmpty && source. peek ( ) != " ] " && source. peekCCBinOp ( ) == nil
500+ else { return nil }
501+
502+ // Nested custom character class.
503+ if let cccStart = source. lexCustomCCStart ( ) {
504+ return . custom( try parseCustomCharacterClass ( cccStart) )
505+ }
506+
507+ // Quoted sequence.
508+ if let quote = try source. lexQuote ( context: context) {
509+ return . quote( quote)
510+ }
511+
512+ // Lex triva if we're allowed.
513+ if let trivia = try source. lexTrivia ( context: context) {
514+ return . trivia( trivia)
515+ }
516+
517+ if let atom = try source. lexAtom ( context: context) {
518+ return . atom( atom)
519+ }
520+ return nil
521+ }
522+
498523 mutating func parseCCCMembers(
499524 into members: inout Array < CustomCC . Member >
500525 ) throws {
501526 // Parse members until we see the end of the custom char class or an
502527 // operator.
503- while !source. isEmpty && source. peek ( ) != " ] " &&
504- source. peekCCBinOp ( ) == nil {
505-
506- // Nested custom character class.
507- if let cccStart = source. lexCustomCCStart ( ) {
508- members. append ( . custom( try parseCustomCharacterClass ( cccStart) ) )
509- continue
510- }
511-
512- // Quoted sequence.
513- if let quote = try source. lexQuote ( context: context) {
514- members. append ( . quote( quote) )
515- continue
516- }
517-
518- // Lex trivia if we're allowed.
519- if let trivia = try source. lexTrivia ( context: context) {
520- members. append ( . trivia( trivia) )
521- continue
522- }
528+ while let member = try parseCCCMember ( ) {
529+ members. append ( member)
530+
531+ // If we have an atom, we can try to parse a character class range. Each
532+ // time we parse a component of the range, we append to `members` in case
533+ // it ends up not being a range, and we bail. If we succeed in parsing, we
534+ // remove the intermediate members.
535+ if case . atom( let lhs) = member {
536+ let membersBeforeRange = members. count - 1
537+
538+ while let t = try source. lexTrivia ( context: context) {
539+ members. append ( . trivia( t) )
540+ }
523541
524- guard let atom = try source. lexAtom ( context: context) else { break }
542+ guard let dash = source. lexCustomCharacterClassRangeOperator ( ) else {
543+ continue
544+ }
545+ // If we can't parse a range, '-' becomes literal, e.g `[6-]`.
546+ members. append ( . atom( . init( . char( " - " ) , dash) ) )
525547
526- // Range between atoms.
527- if let ( dashLoc, rhs) =
528- try source. lexCustomCharClassRangeEnd ( context: context) {
529- members. append ( . range( . init( atom, dashLoc, rhs) ) )
530- continue
548+ while let t = try source. lexTrivia ( context: context) {
549+ members. append ( . trivia( t) )
550+ }
551+ guard let rhs = try parseCCCMember ( ) else { continue }
552+ members. append ( rhs)
553+
554+ guard case let . atom( rhs) = rhs else { continue }
555+
556+ // We've successfully parsed an atom LHS and RHS, so form a range,
557+ // collecting the trivia we've parsed, and replacing the members that
558+ // would have otherwise been added to the custom character class.
559+ let rangeMemberCount = members. count - membersBeforeRange
560+ let trivia = members. suffix ( rangeMemberCount) . compactMap ( \. asTrivia)
561+ members. removeLast ( rangeMemberCount)
562+ members. append ( . range( . init( lhs, dash, rhs, trivia: trivia) ) )
531563 }
532-
533- members. append ( . atom( atom) )
534- continue
535564 }
536565 }
537566}
0 commit comments