Skip to content

Commit

Permalink
Correct flags scanning for non-BMP characters
Browse files Browse the repository at this point in the history
  • Loading branch information
graphemecluster committed Apr 27, 2024
1 parent 76acd92 commit e67692a
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 15 deletions.
32 changes: 17 additions & 15 deletions src/compiler/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2485,27 +2485,28 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
pos++;
let regExpFlags = RegularExpressionFlags.None;
while (pos < end) {
const ch = text.charCodeAt(pos);
const ch = codePointAt(text, pos);
if (!isIdentifierPart(ch, languageVersion)) {
break;
}
const size = charSize(ch);
if (reportErrors) {
const flag = characterToRegularExpressionFlag(String.fromCharCode(ch));
const flag = characterToRegularExpressionFlag(utf16EncodeAsString(ch));
if (flag === undefined) {
error(Diagnostics.Unknown_regular_expression_flag, pos, 1);
error(Diagnostics.Unknown_regular_expression_flag, pos, size);
}
else if (regExpFlags & flag) {
error(Diagnostics.Duplicate_regular_expression_flag, pos, 1);
error(Diagnostics.Duplicate_regular_expression_flag, pos, size);
}
else if (((regExpFlags | flag) & RegularExpressionFlags.UnicodeMode) === RegularExpressionFlags.UnicodeMode) {
error(Diagnostics.The_Unicode_u_flag_and_the_Unicode_Sets_v_flag_cannot_be_set_simultaneously, pos, 1);
error(Diagnostics.The_Unicode_u_flag_and_the_Unicode_Sets_v_flag_cannot_be_set_simultaneously, pos, size);
}
else {
regExpFlags |= flag;
checkRegularExpressionFlagAvailable(flag);
checkRegularExpressionFlagAvailability(flag);
}
}
pos++;
pos += size;
}
if (reportErrors) {
scanRange(startOfRegExpBody, endOfRegExpBody - startOfRegExpBody, () => {
Expand Down Expand Up @@ -2752,25 +2753,26 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean

function scanPatternModifiers(currFlags: RegularExpressionFlags): RegularExpressionFlags {
while (pos < end) {
const ch = text.charCodeAt(pos);
const ch = codePointAt(text, pos);
if (!isIdentifierPart(ch, languageVersion)) {
break;
}
const flag = characterToRegularExpressionFlag(String.fromCharCode(ch));
const size = charSize(ch);
const flag = characterToRegularExpressionFlag(utf16EncodeAsString(ch));
if (flag === undefined) {
error(Diagnostics.Unknown_regular_expression_flag, pos, 1);
error(Diagnostics.Unknown_regular_expression_flag, pos, size);
}
else if (currFlags & flag) {
error(Diagnostics.Duplicate_regular_expression_flag, pos, 1);
error(Diagnostics.Duplicate_regular_expression_flag, pos, size);
}
else if (!(flag & RegularExpressionFlags.Modifiers)) {
error(Diagnostics.This_regular_expression_flag_cannot_be_toggled_within_a_subpattern, pos, 1);
error(Diagnostics.This_regular_expression_flag_cannot_be_toggled_within_a_subpattern, pos, size);
}
else {
currFlags |= flag;
checkRegularExpressionFlagAvailable(flag);
checkRegularExpressionFlagAvailability(flag);
}
pos++;
pos += size;
}
return currFlags;
}
Expand Down Expand Up @@ -3470,7 +3472,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
});
}

function checkRegularExpressionFlagAvailable(flag: RegularExpressionFlags) {
function checkRegularExpressionFlagAvailability(flag: RegularExpressionFlags) {
const availableFrom = regExpFlagToFirstAvailableLanguageVersion.get(flag) as ScriptTarget | undefined;
if (availableFrom && languageVersion < availableFrom) {
error(Diagnostics.This_regular_expression_flag_is_only_available_when_targeting_0_or_later, pos, 1, getNameOfScriptTarget(availableFrom));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
regularExpressionWithNonBMPFlags.ts(1,23): error TS1499: Unknown regular expression flag.
regularExpressionWithNonBMPFlags.ts(1,25): error TS1499: Unknown regular expression flag.
regularExpressionWithNonBMPFlags.ts(1,28): error TS1499: Unknown regular expression flag.
regularExpressionWithNonBMPFlags.ts(1,41): error TS1499: Unknown regular expression flag.
regularExpressionWithNonBMPFlags.ts(1,43): error TS1499: Unknown regular expression flag.
regularExpressionWithNonBMPFlags.ts(1,45): error TS1499: Unknown regular expression flag.


==== regularExpressionWithNonBMPFlags.ts (6 errors) ====
const 𝘳𝘦𝘨𝘦𝘹 = /(?𝘴𝘪-𝘮:^𝘧𝘰𝘰.)/𝘨𝘮𝘶;
~~
!!! error TS1499: Unknown regular expression flag.
~~
!!! error TS1499: Unknown regular expression flag.
~~
!!! error TS1499: Unknown regular expression flag.
~~
!!! error TS1499: Unknown regular expression flag.
~~
!!! error TS1499: Unknown regular expression flag.
~~
!!! error TS1499: Unknown regular expression flag.

8 changes: 8 additions & 0 deletions tests/baselines/reference/regularExpressionWithNonBMPFlags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//// [tests/cases/compiler/regularExpressionWithNonBMPFlags.ts] ////

//// [regularExpressionWithNonBMPFlags.ts]
const 𝘳𝘦𝘨𝘦𝘹 = /(?𝘴𝘪-𝘮:^𝘧𝘰𝘰.)/𝘨𝘮𝘶;


//// [regularExpressionWithNonBMPFlags.js]
const 𝘳𝘦𝘨𝘦𝘹 = /(?𝘴𝘪-𝘮:^𝘧𝘰𝘰.)/𝘨𝘮𝘶;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//// [tests/cases/compiler/regularExpressionWithNonBMPFlags.ts] ////

=== regularExpressionWithNonBMPFlags.ts ===
const 𝘳𝘦𝘨𝘦𝘹 = /(?𝘴𝘪-𝘮:^𝘧𝘰𝘰.)/𝘨𝘮𝘶;
>𝘳𝘦𝘨𝘦𝘹 : Symbol(𝘳𝘦𝘨𝘦𝘹, Decl(regularExpressionWithNonBMPFlags.ts, 0, 5))

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//// [tests/cases/compiler/regularExpressionWithNonBMPFlags.ts] ////

=== regularExpressionWithNonBMPFlags.ts ===
const 𝘳𝘦𝘨𝘦𝘹 = /(?𝘴𝘪-𝘮:^𝘧𝘰𝘰.)/𝘨𝘮𝘶;
>𝘳𝘦𝘨𝘦𝘹 : RegExp
> : ^^^^^^
>/(?𝘴𝘪-𝘮:^𝘧𝘰𝘰.)/𝘨𝘮𝘶 : RegExp
> : ^^^^^^

3 changes: 3 additions & 0 deletions tests/cases/compiler/regularExpressionWithNonBMPFlags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @target: esnext

const 𝘳𝘦𝘨𝘦𝘹 = /(?𝘴𝘪-𝘮:^𝘧𝘰𝘰.)/𝘨𝘮𝘶;

0 comments on commit e67692a

Please sign in to comment.