@@ -997,6 +997,19 @@ export function isIdentifierText(name: string, languageVersion: ScriptTarget | u
997
997
return true ;
998
998
}
999
999
1000
+ const enum EscapeSequenceScanningFlags {
1001
+ String = 1 << 0 ,
1002
+ ReportErrors = 1 << 1 ,
1003
+
1004
+ RegularExpression = 1 << 2 ,
1005
+ AnnexB = 1 << 3 ,
1006
+ AnyUnicodeMode = 1 << 4 ,
1007
+ AtomEscape = 1 << 5 ,
1008
+
1009
+ ReportInvalidEscapeErrors = RegularExpression | ReportErrors ,
1010
+ ScanExtendedUnicodeEscape = String | AnyUnicodeMode ,
1011
+ }
1012
+
1000
1013
const enum ClassSetExpressionType {
1001
1014
Unknown ,
1002
1015
ClassUnion ,
@@ -1416,7 +1429,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
1416
1429
}
1417
1430
if ( ch === CharacterCodes . backslash && ! jsxAttributeString ) {
1418
1431
result += text . substring ( start , pos ) ;
1419
- result += scanEscapeSequence ( /*shouldEmitInvalidEscapeError*/ true , /*isRegularExpression*/ false ) ;
1432
+ result += scanEscapeSequence ( EscapeSequenceScanningFlags . String | EscapeSequenceScanningFlags . ReportErrors ) ;
1420
1433
start = pos ;
1421
1434
continue ;
1422
1435
}
@@ -1474,7 +1487,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
1474
1487
// Escape character
1475
1488
if ( currChar === CharacterCodes . backslash ) {
1476
1489
contents += text . substring ( start , pos ) ;
1477
- contents += scanEscapeSequence ( shouldEmitInvalidEscapeError , /*isRegularExpression*/ false ) ;
1490
+ contents += scanEscapeSequence ( EscapeSequenceScanningFlags . String | ( shouldEmitInvalidEscapeError ? EscapeSequenceScanningFlags . ReportErrors : 0 ) ) ;
1478
1491
start = pos ;
1479
1492
continue ;
1480
1493
}
@@ -1517,7 +1530,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
1517
1530
// | [0-3] [0-7] [0-7]?
1518
1531
// | [4-7] [0-7]
1519
1532
// NonOctalDecimalEscapeSequence ::= [89]
1520
- function scanEscapeSequence ( shouldEmitInvalidEscapeError : boolean , isRegularExpression : boolean | "annex-b" ) : string {
1533
+ function scanEscapeSequence ( flags : EscapeSequenceScanningFlags ) : string {
1521
1534
const start = pos ;
1522
1535
pos ++ ;
1523
1536
if ( pos >= end ) {
@@ -1554,18 +1567,28 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
1554
1567
}
1555
1568
// '\47'
1556
1569
tokenFlags |= TokenFlags . ContainsInvalidEscape ;
1557
- if ( isRegularExpression || shouldEmitInvalidEscapeError ) {
1570
+ if ( flags & EscapeSequenceScanningFlags . ReportInvalidEscapeErrors ) {
1558
1571
const code = parseInt ( text . substring ( start + 1 , pos ) , 8 ) ;
1559
- error ( Diagnostics . Octal_escape_sequences_are_not_allowed_Use_the_syntax_0 , start , pos - start , "\\x" + code . toString ( 16 ) . padStart ( 2 , "0" ) ) ;
1572
+ if ( flags & EscapeSequenceScanningFlags . RegularExpression && ! ( flags & EscapeSequenceScanningFlags . AtomEscape ) && ch !== CharacterCodes . _0 ) {
1573
+ error ( Diagnostics . Octal_escape_sequences_and_backreferences_are_not_allowed_in_a_character_class_If_this_was_intended_as_an_escape_sequence_use_the_syntax_0_instead , start , pos - start , "\\x" + code . toString ( 16 ) . padStart ( 2 , "0" ) ) ;
1574
+ }
1575
+ else {
1576
+ error ( Diagnostics . Octal_escape_sequences_are_not_allowed_Use_the_syntax_0 , start , pos - start , "\\x" + code . toString ( 16 ) . padStart ( 2 , "0" ) ) ;
1577
+ }
1560
1578
return String . fromCharCode ( code ) ;
1561
1579
}
1562
1580
return text . substring ( start , pos ) ;
1563
1581
case CharacterCodes . _8 :
1564
1582
case CharacterCodes . _9 :
1565
1583
// the invalid '\8' and '\9'
1566
1584
tokenFlags |= TokenFlags . ContainsInvalidEscape ;
1567
- if ( isRegularExpression || shouldEmitInvalidEscapeError ) {
1568
- error ( Diagnostics . Escape_sequence_0_is_not_allowed , start , pos - start , text . substring ( start , pos ) ) ;
1585
+ if ( flags & EscapeSequenceScanningFlags . ReportInvalidEscapeErrors ) {
1586
+ if ( flags & EscapeSequenceScanningFlags . RegularExpression && ! ( flags & EscapeSequenceScanningFlags . AtomEscape ) ) {
1587
+ error ( Diagnostics . Decimal_escape_sequences_and_backreferences_are_not_allowed_in_a_character_class , start , pos - start ) ;
1588
+ }
1589
+ else {
1590
+ error ( Diagnostics . Escape_sequence_0_is_not_allowed , start , pos - start , text . substring ( start , pos ) ) ;
1591
+ }
1569
1592
return String . fromCharCode ( ch ) ;
1570
1593
}
1571
1594
return text . substring ( start , pos ) ;
@@ -1587,18 +1610,18 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
1587
1610
return '"' ;
1588
1611
case CharacterCodes . u :
1589
1612
if (
1590
- ( ! isRegularExpression || shouldEmitInvalidEscapeError ) &&
1613
+ flags & EscapeSequenceScanningFlags . ScanExtendedUnicodeEscape &&
1591
1614
pos < end && charCodeUnchecked ( pos ) === CharacterCodes . openBrace
1592
1615
) {
1593
1616
// '\u{DDDDDD}'
1594
1617
pos -= 2 ;
1595
- return scanExtendedUnicodeEscape ( ! ! isRegularExpression || shouldEmitInvalidEscapeError ) ;
1618
+ return scanExtendedUnicodeEscape ( ! ! ( flags & EscapeSequenceScanningFlags . ReportInvalidEscapeErrors ) ) ;
1596
1619
}
1597
1620
// '\uDDDD'
1598
1621
for ( ; pos < start + 6 ; pos ++ ) {
1599
1622
if ( ! ( pos < end && isHexDigit ( charCodeUnchecked ( pos ) ) ) ) {
1600
1623
tokenFlags |= TokenFlags . ContainsInvalidEscape ;
1601
- if ( isRegularExpression || shouldEmitInvalidEscapeError ) {
1624
+ if ( flags & EscapeSequenceScanningFlags . ReportInvalidEscapeErrors ) {
1602
1625
error ( Diagnostics . Hexadecimal_digit_expected ) ;
1603
1626
}
1604
1627
return text . substring ( start , pos ) ;
@@ -1608,7 +1631,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
1608
1631
const escapedValue = parseInt ( text . substring ( start + 2 , pos ) , 16 ) ;
1609
1632
const escapedValueString = String . fromCharCode ( escapedValue ) ;
1610
1633
if (
1611
- isRegularExpression && shouldEmitInvalidEscapeError && escapedValue >= 0xD800 && escapedValue <= 0xDBFF &&
1634
+ flags & EscapeSequenceScanningFlags . AnyUnicodeMode && escapedValue >= 0xD800 && escapedValue <= 0xDBFF &&
1612
1635
pos + 6 < end && text . substring ( pos , pos + 2 ) === "\\u" && charCodeUnchecked ( pos + 2 ) !== CharacterCodes . openBrace
1613
1636
) {
1614
1637
// For regular expressions in any Unicode mode, \u HexLeadSurrogate \u HexTrailSurrogate is treated as a single character
@@ -1635,7 +1658,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
1635
1658
for ( ; pos < start + 4 ; pos ++ ) {
1636
1659
if ( ! ( pos < end && isHexDigit ( charCodeUnchecked ( pos ) ) ) ) {
1637
1660
tokenFlags |= TokenFlags . ContainsInvalidEscape ;
1638
- if ( isRegularExpression || shouldEmitInvalidEscapeError ) {
1661
+ if ( flags & EscapeSequenceScanningFlags . ReportInvalidEscapeErrors ) {
1639
1662
error ( Diagnostics . Hexadecimal_digit_expected ) ;
1640
1663
}
1641
1664
return text . substring ( start , pos ) ;
@@ -1656,7 +1679,12 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
1656
1679
case CharacterCodes . paragraphSeparator :
1657
1680
return "" ;
1658
1681
default :
1659
- if ( isRegularExpression === true && ( shouldEmitInvalidEscapeError || isIdentifierPart ( ch , languageVersion ) ) ) {
1682
+ if (
1683
+ flags & EscapeSequenceScanningFlags . AnyUnicodeMode
1684
+ || flags & EscapeSequenceScanningFlags . RegularExpression
1685
+ && ! ( flags & EscapeSequenceScanningFlags . AnnexB )
1686
+ && isIdentifierPart ( ch , languageVersion )
1687
+ ) {
1660
1688
error ( Diagnostics . This_character_cannot_be_escaped_in_a_regular_expression , pos - 2 , 2 ) ;
1661
1689
}
1662
1690
return String . fromCharCode ( ch ) ;
@@ -2934,7 +2962,12 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2934
2962
return String . fromCharCode ( ch ) ;
2935
2963
default :
2936
2964
pos -- ;
2937
- return scanEscapeSequence ( /*shouldEmitInvalidEscapeError*/ anyUnicodeMode , /*isRegularExpression*/ anyUnicodeModeOrNonAnnexB || "annex-b" ) ;
2965
+ return scanEscapeSequence (
2966
+ EscapeSequenceScanningFlags . RegularExpression
2967
+ | ( annexB ? EscapeSequenceScanningFlags . AnnexB : 0 )
2968
+ | ( anyUnicodeMode ? EscapeSequenceScanningFlags . AnyUnicodeMode : 0 )
2969
+ | ( atomEscape ? EscapeSequenceScanningFlags . AtomEscape : 0 ) ,
2970
+ ) ;
2938
2971
}
2939
2972
}
2940
2973
@@ -3540,7 +3573,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
3540
3573
error ( Diagnostics . This_backreference_refers_to_a_group_that_does_not_exist_There_are_only_0_capturing_groups_in_this_regular_expression , escape . pos , escape . end - escape . pos , numberOfCapturingGroups ) ;
3541
3574
}
3542
3575
else {
3543
- error ( Diagnostics . This_backreference_is_invalid_because_the_containing_regular_expression_contains_no_capturing_groups , escape . pos , escape . end - escape . pos ) ;
3576
+ error ( Diagnostics . This_backreference_refers_to_a_group_that_does_not_exist_There_are_no_capturing_groups_in_this_regular_expression , escape . pos , escape . end - escape . pos ) ;
3544
3577
}
3545
3578
}
3546
3579
} ) ;
0 commit comments