Skip to content

Commit 9cccf0e

Browse files
authored
Moved regular expressions used in hot paths to global constants so they don't need to be reconstructed each time. (#10506)
1 parent cc812ef commit 9cccf0e

11 files changed

Lines changed: 52 additions & 30 deletions

File tree

packages/pyright-internal/src/analyzer/docStringUtils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
* (https://www.python.org/dev/peps/pep-0257/).
1010
*/
1111

12+
const docStringCrRegEx = /\r/g;
13+
const docStringTabRegEx = /\t/g;
14+
1215
export function cleanAndSplitDocString(rawString: string): string[] {
1316
// Remove carriage returns and replace tabs.
14-
const unescaped = rawString.replace(/\r/g, '').replace(/\t/g, ' ');
17+
const unescaped = rawString.replace(docStringCrRegEx, '').replace(docStringTabRegEx, ' ');
1518

1619
// Split into lines.
1720
const lines = unescaped.split('\n');

packages/pyright-internal/src/analyzer/importStatementUtils.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ import { ImportResult, ImportType } from './importResult';
3838
import { getTokenAfter, getTokenAt } from './parseTreeUtils';
3939
import * as SymbolNameUtils from './symbolNameUtils';
4040

41+
const underscoreRegEx = /_/g;
42+
const indentTextRegEx = /^\s*$/;
43+
4144
export interface ImportStatement {
4245
node: ImportNode | ImportFromNode;
4346
subnode?: ImportAsNode;
@@ -238,8 +241,8 @@ function _compareImportNames(name1: string, name2: string) {
238241
// This can't be reproduced by a normal string compare in TypeScript, since '_' > 'A'.
239242
// Replace all '_' with '=' which guarantees '=' < 'A'.
240243
// Safe to do as '=' is an invalid char in Python names.
241-
const name1toCompare = name1.replace(/_/g, '=');
242-
const name2toCompare = name2.replace(/_/g, '=');
244+
const name1toCompare = name1.replace(underscoreRegEx, '=');
245+
const name2toCompare = name2.replace(underscoreRegEx, '=');
243246
return compareStringsCaseSensitive(name1toCompare, name2toCompare);
244247
}
245248

@@ -293,7 +296,7 @@ function _getTextEditsForAutoImportSymbolAddition(
293296
indentText = parseFileResults.text.substr(firstSymbolLineRange.start, firstSymbolPos.character);
294297

295298
// Is the indent text composed of whitespace only?
296-
if (/^\s*$/.test(indentText)) {
299+
if (indentTextRegEx.test(indentText)) {
297300
useOnePerLineFormatting = true;
298301
}
299302
}

packages/pyright-internal/src/analyzer/tracePrinter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import * as ParseTreeUtils from './parseTreeUtils';
1919
import { Symbol } from './symbol';
2020
import { OverloadedType, Type, TypeBase, TypeCategory } from './types';
2121

22+
const separatorRegExp = /[\\/]/g;
23+
2224
export type PrintableType = ParseNode | Declaration | Symbol | Type | undefined;
2325

2426
export interface TracePrinter {
@@ -36,7 +38,6 @@ export function createTracePrinter(roots: Uri[], includeRoots: boolean = false):
3638
// ex) d:/root/.env/lib/site-packages, d:/root/.env
3739
roots = roots.sort((a, b) => a.key.localeCompare(b.key)).reverse();
3840

39-
const separatorRegExp = /[\\/]/g;
4041
function printFileOrModuleName(fileUriOrModule: Uri | AbsoluteModuleDescriptor | undefined) {
4142
if (fileUriOrModule) {
4243
if (Uri.is(fileUriOrModule)) {

packages/pyright-internal/src/analyzer/typePrinterUtils.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
* Simple utility functions used by the type printer.
88
*/
99

10-
export function printStringLiteral(value: string, quotation = '"'): string {
11-
const singleTickRegEx = /'/g;
12-
const escapedDoubleQuoteRegEx = /\\"/g;
10+
const singleTickRegEx = /'/g;
11+
const escapedDoubleQuoteRegEx = /\\"/g;
1312

13+
export function printStringLiteral(value: string, quotation = '"'): string {
1414
// JSON.stringify will perform proper escaping for " case.
1515
// So, we only need to do our own escaping for ' case.
1616
let literalStr = JSON.stringify(value).toString();

packages/pyright-internal/src/common/pathUtils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface FileSpec {
3232
}
3333

3434
const _includeFileRegex = /\.pyi?$/;
35+
const _wildcardRootRegex = /[*?]/;
3536

3637
export namespace FileSpec {
3738
export function is(value: any): value is FileSpec {
@@ -166,10 +167,10 @@ export function getRelativePath(dirPath: string, relativeTo: string) {
166167
return relativePath;
167168
}
168169

170+
const separatorRegExp = /[\\/]/g;
169171
const getInvalidSeparator = (sep: string) => (sep === '/' ? '\\' : '/');
170172
export function normalizeSlashes(pathString: string, sep = path.sep): string {
171173
if (pathString.includes(getInvalidSeparator(sep))) {
172-
const separatorRegExp = /[\\/]/g;
173174
return pathString.replace(separatorRegExp, sep);
174175
}
175176

@@ -583,7 +584,7 @@ export function getWildcardRoot(rootPath: string, fileSpec: string): string {
583584
if (component === '**') {
584585
break;
585586
} else {
586-
if (component.match(/[*?]/)) {
587+
if (component.match(_wildcardRootRegex)) {
587588
break;
588589
}
589590

packages/pyright-internal/src/common/realFileSystem.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as fs from 'fs';
1010
import * as tmp from 'tmp';
1111
import { isMainThread } from 'worker_threads';
1212

13+
import { Disposable } from 'vscode-jsonrpc';
1314
import { CaseSensitivityDetector } from './caseSensitivityDetector';
1415
import { ConsoleInterface, NullConsole } from './console';
1516
import { randomBytesHex } from './crypto';
@@ -26,7 +27,6 @@ import { combinePaths, getRootLength } from './pathUtils';
2627
import { FileUri, FileUriSchema } from './uri/fileUri';
2728
import { Uri } from './uri/uri';
2829
import { getRootUri } from './uri/uriUtils';
29-
import { Disposable } from 'vscode-jsonrpc';
3030

3131
// Automatically remove files created by tmp at process exit.
3232
tmp.setGracefulCleanup();
@@ -49,6 +49,8 @@ const DOT_ZIP = `.zip`;
4949
const DOT_EGG = `.egg`;
5050
const DOT_JAR = `.jar`;
5151

52+
const zipPathRegEx = /[^\\/]\.(?:egg|zip|jar)[\\/]/;
53+
5254
// Exactly the same as ZipOpenFS's getArchivePart, but supporting .egg files.
5355
// https://github.com/yarnpkg/berry/blob/64a16b3603ef2ccb741d3c44f109c9cfc14ba8dd/packages/yarnpkg-fslib/sources/ZipOpenFS.ts#L23
5456
function getArchivePart(path: string) {
@@ -464,7 +466,7 @@ export class RealFileSystem implements FileSystem {
464466

465467
isInZip(uri: Uri): boolean {
466468
const path = uri.getFilePath();
467-
return /[^\\/]\.(?:egg|zip|jar)[\\/]/.test(path) && yarnFS.isZip(path);
469+
return zipPathRegEx.test(path) && yarnFS.isZip(path);
468470
}
469471
}
470472

packages/pyright-internal/src/common/uri/baseUri.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88

99
import { some } from '../collectionUtils';
1010
import { getRootLength, getShortenedFileName } from '../pathUtils';
11-
import { Uri } from './uri';
1211
import { cacheProperty } from './memoization';
12+
import { Uri } from './uri';
1313

1414
export type JsonObjType = any;
1515

16+
const backslashRegEx = /\\/g;
17+
1618
export abstract class BaseUri implements Uri {
1719
protected constructor(private readonly _key: string) {}
1820

@@ -245,7 +247,7 @@ export abstract class BaseUri implements Uri {
245247

246248
protected normalizeSlashes(path: string): string {
247249
if (path.includes('\\')) {
248-
return path.replace(/\\/g, '/');
250+
return path.replace(backslashRegEx, '/');
249251
}
250252
return path;
251253
}

packages/pyright-internal/src/common/uri/uri.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ export interface Uri {
120120
toJsonObj(): any;
121121
}
122122

123+
const _dosPathRegex = /^\/[a-zA-Z]:\//;
124+
const _win32NormalizationRegex = /\//g;
125+
123126
// Returns just the fsPath path portion of a vscode URI.
124127
function getFilePath(uri: URI): string {
125128
let filePath: string | undefined;
@@ -136,14 +139,14 @@ function getFilePath(uri: URI): string {
136139

137140
// If this is a DOS-style path with a drive letter, remove
138141
// the leading slash.
139-
if (filePath.match(/^\/[a-zA-Z]:\//)) {
142+
if (filePath.match(_dosPathRegex)) {
140143
filePath = filePath.slice(1);
141144
}
142145

143146
// vscode.URI normalizes the path to use the correct path separators.
144147
// We need to do the same.
145148
if (process?.platform === 'win32') {
146-
filePath = filePath.replace(/\//g, '\\');
149+
filePath = filePath.replace(_win32NormalizationRegex, '\\');
147150
}
148151

149152
return filePath;
@@ -164,16 +167,16 @@ function normalizeUri(uri: string | URI): { uri: URI; str: string } {
164167
return { uri: finalURI, str: finalString };
165168
}
166169

170+
const windowsUriRegEx = /^[a-zA-Z]:\\?/;
171+
const uriRegEx = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/?\/?/;
172+
167173
export namespace Uri {
168174
export interface IServiceProvider {
169175
get<T>(key: ServiceKey<T>): T;
170176
}
171177

172178
export function maybeUri(value: string) {
173-
const windows = /^[a-zA-Z]:\\?/;
174-
const uri = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/?\/?/;
175-
176-
return uri.test(value) && !windows.test(value);
179+
return uriRegEx.test(value) && !windowsUriRegEx.test(value);
177180
}
178181

179182
export function create(value: string, serviceProvider: IServiceProvider, checkRelative?: boolean): Uri;

packages/pyright-internal/src/common/uri/uriUtils.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88

99
import type { Dirent } from 'fs';
1010

11+
import { CaseSensitivityDetector } from '../caseSensitivityDetector';
1112
import { FileSystem, ReadOnlyFileSystem, Stats } from '../fileSystem';
1213
import {
1314
getRegexEscapedSeparator,
1415
isDirectoryWildcardPatternPresent,
1516
stripTrailingDirectorySeparator,
1617
} from '../pathUtils';
17-
import { Uri } from './uri';
1818
import { ServiceKeys } from '../serviceKeys';
19-
import { CaseSensitivityDetector } from '../caseSensitivityDetector';
2019
import { ServiceProvider } from '../serviceProvider';
20+
import { Uri } from './uri';
2121

2222
export interface FileSpec {
2323
// File specs can contain wildcard characters (**, *, ?). This
@@ -36,6 +36,7 @@ export interface FileSpec {
3636
}
3737

3838
const _includeFileRegex = /\.pyi?$/;
39+
const _wildcardRegex = /[*?]/;
3940

4041
export namespace FileSpec {
4142
export function is(value: any): value is FileSpec {
@@ -264,7 +265,7 @@ export function getWildcardRoot(root: Uri, fileSpec: string): Uri {
264265
if (component === '**') {
265266
break;
266267
} else {
267-
if (/[*?]/.test(component)) {
268+
if (_wildcardRegex.test(component)) {
268269
break;
269270
}
270271

packages/pyright-internal/src/parser/parser.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ interface SubscriptListResult {
160160
trailingComma: boolean;
161161
}
162162

163+
const commentRegEx = /^(\s*#\s*type:\s*)([^\r\n]*)/;
164+
const ignoreCommentRegEx = /^ignore(\s|\[|$)/;
165+
163166
export class ParseOptions {
164167
isStubFile: boolean;
165168
pythonVersion: PythonVersion;
@@ -4760,7 +4763,6 @@ export class Parser {
47604763
}
47614764

47624765
const interTokenContents = this._fileContents!.slice(curToken.start + curToken.length, nextToken.start);
4763-
const commentRegEx = /^(\s*#\s*type:\s*)([^\r\n]*)/;
47644766
const match = interTokenContents.match(commentRegEx);
47654767
if (!match) {
47664768
return undefined;
@@ -4773,7 +4775,7 @@ export class Parser {
47734775
// expression because mypy supports ignore comments of the
47744776
// form ignore[errorCode, ...]. We'll treat these as regular
47754777
// ignore statements (as though no errorCodes were included).
4776-
if (typeString.trim().match(/^ignore(\s|\[|$)/)) {
4778+
if (typeString.trim().match(ignoreCommentRegEx)) {
47774779
return undefined;
47784780
}
47794781

0 commit comments

Comments
 (0)