@@ -589,6 +589,26 @@ extension Source {
589
589
return AST . Quote ( str. value, str. location)
590
590
}
591
591
592
+ /// Try to consume an interpolation sequence.
593
+ ///
594
+ /// Interpolation -> '<{' String '}>'
595
+ ///
596
+ mutating func lexInterpolation( ) throws -> AST . Interpolation ? {
597
+ let contents = try recordLoc { src -> String ? in
598
+ try src. tryEating { src in
599
+ guard src. tryEat ( sequence: " <{ " ) else { return nil }
600
+ _ = src. lexUntil { $0. isEmpty || $0. starts ( with: " }> " ) }
601
+ guard src. tryEat ( sequence: " }> " ) else { return nil }
602
+
603
+ // Not currently supported. We error here instead of during Sema to
604
+ // get a better error for something like `(<{)}>`.
605
+ throw ParseError . unsupported ( " interpolation " )
606
+ }
607
+ }
608
+ guard let contents = contents else { return nil }
609
+ return . init( contents. value, contents. location)
610
+ }
611
+
592
612
/// Try to consume a comment
593
613
///
594
614
/// Comment -> '(?#' [^')']* ')'
@@ -1674,9 +1694,10 @@ extension Source {
1674
1694
break
1675
1695
}
1676
1696
1677
- // We only allow unknown escape sequences for non-letter ASCII, and
1678
- // non-ASCII whitespace.
1679
- guard ( char. isASCII && !char. isLetter) ||
1697
+ // We only allow unknown escape sequences for non-letter non-number ASCII,
1698
+ // and non-ASCII whitespace.
1699
+ // TODO: Once we have fix-its, suggest a `0` prefix for octal `[\7]`.
1700
+ guard ( char. isASCII && !char. isLetter && !char. isNumber) ||
1680
1701
( !char. isASCII && char. isWhitespace)
1681
1702
else {
1682
1703
throw ParseError . invalidEscape ( char)
@@ -1981,10 +2002,21 @@ extension Source {
1981
2002
1982
2003
case " ] " :
1983
2004
assert ( !customCC, " parser should have prevented this " )
1984
- fallthrough
2005
+ break
1985
2006
1986
- default : return . char( char)
2007
+ default :
2008
+ // Reject non-letter non-number non-`\r\n` ASCII characters that have
2009
+ // multiple scalars. These may be confusable for metacharacters, e.g
2010
+ // `[\u{301}]` wouldn't be interpreted as a custom character class due
2011
+ // to the combining accent (assuming it is literal, not `\u{...}`).
2012
+ let scalars = char. unicodeScalars
2013
+ if scalars. count > 1 && scalars. first!. isASCII && char != " \r \n " &&
2014
+ !char. isLetter && !char. isNumber {
2015
+ throw ParseError . confusableCharacter ( char)
2016
+ }
2017
+ break
1987
2018
}
2019
+ return . char( char)
1988
2020
}
1989
2021
guard let kind = kind else { return nil }
1990
2022
return AST . Atom ( kind. value, kind. location)
0 commit comments