@@ -21,7 +21,6 @@ import {
21
21
KeywordSyntaxKind ,
22
22
LanguageFeatureMinimumTarget ,
23
23
LanguageVariant ,
24
- lastOrUndefined ,
25
24
LineAndCharacter ,
26
25
MapLike ,
27
26
parsePseudoBigInt ,
@@ -2438,13 +2437,8 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2438
2437
while ( true ) {
2439
2438
// If we reach the end of a file, or hit a newline, then this is an unterminated
2440
2439
// regex. Report error and return what we have so far.
2441
- if ( pos >= end ) {
2442
- tokenFlags |= TokenFlags . Unterminated ;
2443
- break ;
2444
- }
2445
-
2446
- const ch = charCodeUnchecked ( pos ) ;
2447
- if ( isLineBreak ( ch ) ) {
2440
+ const ch = charCodeChecked ( pos ) ;
2441
+ if ( ch === CharacterCodes . EOF || isLineBreak ( ch ) ) {
2448
2442
tokenFlags |= TokenFlags . Unterminated ;
2449
2443
break ;
2450
2444
}
@@ -2477,7 +2471,8 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2477
2471
pos = startOfRegExpBody ;
2478
2472
inEscape = false ;
2479
2473
let characterClassDepth = 0 ;
2480
- const bracketStack : CharacterCodes [ ] = [ ] ;
2474
+ let inDecimalQuantifier = false ;
2475
+ let groupDepth = 0 ;
2481
2476
while ( pos < endOfRegExpBody ) {
2482
2477
const ch = charCodeUnchecked ( pos ) ;
2483
2478
if ( inEscape ) {
@@ -2493,18 +2488,23 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2493
2488
characterClassDepth -- ;
2494
2489
}
2495
2490
else if ( ! characterClassDepth ) {
2496
- if ( ch === CharacterCodes . openParen ) {
2497
- bracketStack . push ( CharacterCodes . closeParen ) ;
2491
+ if ( ch === CharacterCodes . openBrace ) {
2492
+ inDecimalQuantifier = true ;
2498
2493
}
2499
- else if ( ch === CharacterCodes . openBrace ) {
2500
- bracketStack . push ( CharacterCodes . closeBrace ) ;
2494
+ else if ( ch === CharacterCodes . closeBrace && inDecimalQuantifier ) {
2495
+ inDecimalQuantifier = false ;
2501
2496
}
2502
- else if ( ch === lastOrUndefined ( bracketStack ) ) {
2503
- bracketStack . pop ( ) ;
2504
- }
2505
- else if ( ch === CharacterCodes . closeParen || ch === CharacterCodes . closeBracket || ch === CharacterCodes . closeBrace ) {
2506
- // We encountered an unbalanced bracket outside a character class. Treat this position as the end of regex.
2507
- break ;
2497
+ else if ( ! inDecimalQuantifier ) {
2498
+ if ( ch === CharacterCodes . openParen ) {
2499
+ groupDepth ++ ;
2500
+ }
2501
+ else if ( ch === CharacterCodes . closeParen && groupDepth ) {
2502
+ groupDepth -- ;
2503
+ }
2504
+ else if ( ch === CharacterCodes . closeParen || ch === CharacterCodes . closeBracket || ch === CharacterCodes . closeBrace ) {
2505
+ // We encountered an unbalanced bracket outside a character class. Treat this position as the end of regex.
2506
+ break ;
2507
+ }
2508
2508
}
2509
2509
}
2510
2510
pos ++ ;
@@ -2517,9 +2517,9 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2517
2517
// Consume the slash character
2518
2518
pos ++ ;
2519
2519
let regExpFlags = RegularExpressionFlags . None ;
2520
- while ( pos < end ) {
2521
- const ch = codePointUnchecked ( pos ) ;
2522
- if ( ! isIdentifierPart ( ch , languageVersion ) ) {
2520
+ while ( true ) {
2521
+ const ch = codePointChecked ( pos ) ;
2522
+ if ( ch === CharacterCodes . EOF || ! isIdentifierPart ( ch , languageVersion ) ) {
2523
2523
break ;
2524
2524
}
2525
2525
if ( reportErrors ) {
@@ -2530,7 +2530,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2530
2530
else if ( regExpFlags & flag ) {
2531
2531
error ( Diagnostics . Duplicate_regular_expression_flag , pos , 1 ) ;
2532
2532
}
2533
- else if ( ( ( regExpFlags | flag ) & RegularExpressionFlags . UnicodeMode ) === RegularExpressionFlags . UnicodeMode ) {
2533
+ else if ( ( ( regExpFlags | flag ) & RegularExpressionFlags . AnyUnicodeMode ) === RegularExpressionFlags . AnyUnicodeMode ) {
2534
2534
error ( Diagnostics . The_Unicode_u_flag_and_the_Unicode_Sets_v_flag_cannot_be_set_simultaneously , pos , 1 ) ;
2535
2535
}
2536
2536
else {
@@ -2560,9 +2560,9 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2560
2560
/** Grammar parameter */
2561
2561
var unicodeSetsMode = ! ! ( regExpFlags & RegularExpressionFlags . UnicodeSets ) ;
2562
2562
/** Grammar parameter */
2563
- var unicodeMode = ! ! ( regExpFlags & RegularExpressionFlags . UnicodeMode ) ;
2563
+ var anyUnicodeMode = ! ! ( regExpFlags & RegularExpressionFlags . AnyUnicodeMode ) ;
2564
2564
2565
- if ( unicodeMode ) {
2565
+ if ( anyUnicodeMode ) {
2566
2566
// Annex B treats any unicode mode as the strict syntax.
2567
2567
annexB = false ;
2568
2568
}
@@ -2719,7 +2719,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2719
2719
error ( Diagnostics . Incomplete_quantifier_Digit_expected , digitsStart , 0 ) ;
2720
2720
}
2721
2721
else {
2722
- if ( unicodeMode ) {
2722
+ if ( anyUnicodeMode ) {
2723
2723
error ( Diagnostics . Unexpected_0_Did_you_mean_to_escape_it_with_backslash , start , 1 , String . fromCharCode ( ch ) ) ;
2724
2724
}
2725
2725
isPreviousTermQuantifiable = true ;
@@ -2731,7 +2731,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2731
2731
}
2732
2732
}
2733
2733
else if ( ! min ) {
2734
- if ( unicodeMode ) {
2734
+ if ( anyUnicodeMode ) {
2735
2735
error ( Diagnostics . Unexpected_0_Did_you_mean_to_escape_it_with_backslash , start , 1 , String . fromCharCode ( ch ) ) ;
2736
2736
}
2737
2737
isPreviousTermQuantifiable = true ;
@@ -2775,7 +2775,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2775
2775
// falls through
2776
2776
case CharacterCodes . closeBracket :
2777
2777
case CharacterCodes . closeBrace :
2778
- if ( unicodeMode || ch === CharacterCodes . closeParen ) {
2778
+ if ( anyUnicodeMode || ch === CharacterCodes . closeParen ) {
2779
2779
error ( Diagnostics . Unexpected_0_Did_you_mean_to_escape_it_with_backslash , pos , 1 , String . fromCharCode ( ch ) ) ;
2780
2780
}
2781
2781
pos ++ ;
@@ -2833,7 +2833,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2833
2833
scanGroupName ( /*isReference*/ true ) ;
2834
2834
scanExpectedChar ( CharacterCodes . greaterThan ) ;
2835
2835
}
2836
- else if ( unicodeMode ) {
2836
+ else if ( anyUnicodeMode ) {
2837
2837
error ( Diagnostics . k_must_be_followed_by_a_capturing_group_name_enclosed_in_angle_brackets , pos - 2 , 2 ) ;
2838
2838
}
2839
2839
break ;
@@ -2876,14 +2876,17 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2876
2876
Debug . assertEqual ( charCodeUnchecked ( pos - 1 ) , CharacterCodes . backslash ) ;
2877
2877
let ch = charCodeChecked ( pos ) ;
2878
2878
switch ( ch ) {
2879
+ case CharacterCodes . EOF :
2880
+ error ( Diagnostics . Undetermined_character_escape , pos - 1 , 1 ) ;
2881
+ return "\\" ;
2879
2882
case CharacterCodes . c :
2880
2883
pos ++ ;
2881
2884
ch = charCodeChecked ( pos ) ;
2882
2885
if ( isASCIILetter ( ch ) ) {
2883
2886
pos ++ ;
2884
2887
return String . fromCharCode ( ch & 0x1f ) ;
2885
2888
}
2886
- if ( unicodeMode ) {
2889
+ if ( anyUnicodeMode ) {
2887
2890
error ( Diagnostics . c_must_be_followed_by_an_ASCII_letter , pos - 2 , 2 ) ;
2888
2891
}
2889
2892
else if ( atomEscape && annexB ) {
@@ -2914,12 +2917,8 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
2914
2917
pos ++ ;
2915
2918
return String . fromCharCode ( ch ) ;
2916
2919
default :
2917
- if ( pos >= end ) {
2918
- error ( Diagnostics . Undetermined_character_escape , pos - 1 , 1 ) ;
2919
- return "\\" ;
2920
- }
2921
2920
pos -- ;
2922
- return scanEscapeSequence ( /*shouldEmitInvalidEscapeError*/ unicodeMode , /*isRegularExpression*/ annexB ? "annex-b" : true ) ;
2921
+ return scanEscapeSequence ( /*shouldEmitInvalidEscapeError*/ anyUnicodeMode , /*isRegularExpression*/ annexB ? "annex-b" : true ) ;
2923
2922
}
2924
2923
}
2925
2924
@@ -3465,11 +3464,11 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
3465
3464
}
3466
3465
}
3467
3466
scanExpectedChar ( CharacterCodes . closeBrace ) ;
3468
- if ( ! unicodeMode ) {
3467
+ if ( ! anyUnicodeMode ) {
3469
3468
error ( Diagnostics . Unicode_property_value_expressions_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set , start , pos - start ) ;
3470
3469
}
3471
3470
}
3472
- else if ( unicodeMode ) {
3471
+ else if ( anyUnicodeMode ) {
3473
3472
error ( Diagnostics . _0_must_be_followed_by_a_Unicode_property_value_expression_enclosed_in_braces , pos - 2 , 2 , String . fromCharCode ( ch ) ) ;
3474
3473
}
3475
3474
return true ;
@@ -3491,7 +3490,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
3491
3490
}
3492
3491
3493
3492
function scanSourceCharacter ( ) : string {
3494
- const size = unicodeMode ? charSize ( charCodeChecked ( pos ) ) : 1 ;
3493
+ const size = anyUnicodeMode ? charSize ( charCodeChecked ( pos ) ) : 1 ;
3495
3494
pos += size ;
3496
3495
return size > 0 ? text . substring ( pos - size , pos ) : "" ;
3497
3496
}
0 commit comments