Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/vs/platform/contextkey/common/contextkey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ const defaultConfig: ParserConfig = {
regexParsingWithErrorRecovery: true
};

class ParseError extends Error { }

export type ParsingError = {
message: string;
offset: number;
Expand Down Expand Up @@ -167,6 +165,8 @@ export class Parser {
// Note: this doesn't produce an exact syntax tree but a normalized one
// ContextKeyExpression's that we use as AST nodes do not expose constructors that do not normalize

private static _parseError = new Error();

// lifetime note: `_scanner` lives as long as the parser does, i.e., is not reset between calls to `parse`
private readonly _scanner = new Scanner();

Expand Down Expand Up @@ -211,11 +211,11 @@ export class Parser {
const peek = this._peek();
const additionalInfo = peek.type === TokenType.Str ? hintUnexpectedToken : undefined;
this._parsingErrors.push({ message: errorUnexpectedToken, offset: peek.offset, lexeme: Scanner.getLexeme(peek), additionalInfo });
throw new ParseError();
throw Parser._parseError;
}
return expr;
} catch (e) {
if (!(e instanceof ParseError)) {
if (!(e === Parser._parseError)) {
throw e;
}
return undefined;
Expand Down Expand Up @@ -311,7 +311,7 @@ export class Parser {
}
const regexLexeme = expr.lexeme;
const closingSlashIndex = regexLexeme.lastIndexOf('/');
const flags = closingSlashIndex === regexLexeme.length - 1 ? undefined : regexLexeme.substring(closingSlashIndex + 1);
const flags = closingSlashIndex === regexLexeme.length - 1 ? undefined : this._removeFlagsGY(regexLexeme.substring(closingSlashIndex + 1));
let regexp: RegExp | null;
try {
regexp = new RegExp(regexLexeme.substring(1, closingSlashIndex), flags);
Expand Down Expand Up @@ -365,7 +365,7 @@ export class Parser {

const regexLexeme = lexemeReconstruction.join('');
const closingSlashIndex = regexLexeme.lastIndexOf('/');
const flags = closingSlashIndex === regexLexeme.length - 1 ? undefined : regexLexeme.substring(closingSlashIndex + 1);
const flags = closingSlashIndex === regexLexeme.length - 1 ? undefined : this._removeFlagsGY(regexLexeme.substring(closingSlashIndex + 1));
let regexp: RegExp | null;
try {
regexp = new RegExp(regexLexeme.substring(1, closingSlashIndex), flags);
Expand Down Expand Up @@ -481,7 +481,7 @@ export class Parser {

case TokenType.EOF:
this._parsingErrors.push({ message: errorUnexpectedEOF, offset: peek.offset, lexeme: '', additionalInfo: hintUnexpectedEOF });
throw new ParseError();
throw Parser._parseError;

default:
throw this._errExpectedButGot(`true | false | KEY \n\t| KEY '=~' REGEX \n\t| KEY ('==' | '!=' | '<' | '<=' | '>' | '>=' | 'in' | 'not' 'in') value`, this._peek());
Expand Down Expand Up @@ -512,6 +512,11 @@ export class Parser {
}
}

private _flagsGYRe = /g|y/g;
private _removeFlagsGY(flags: string): string {
return flags.replaceAll(this._flagsGYRe, '');
}

// careful: this can throw if current token is the initial one (ie index = 0)
private _previous() {
return this._tokens[this._current - 1];
Expand Down Expand Up @@ -546,7 +551,7 @@ export class Parser {
const offset = got.offset;
const lexeme = Scanner.getLexeme(got);
this._parsingErrors.push({ message, offset, lexeme, additionalInfo });
return new ParseError();
return Parser._parseError;
}

private _check(type: TokenType) {
Expand Down Expand Up @@ -1558,7 +1563,7 @@ function eliminateConstantsInArray(arr: ContextKeyExpression[]): (ContextKeyExpr
return newArr;
}

class ContextKeyAndExpr implements IContextKeyExpression {
export class ContextKeyAndExpr implements IContextKeyExpression {

public static create(_expr: ReadonlyArray<ContextKeyExpression | null | undefined>, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {
return ContextKeyAndExpr._normalizeArr(_expr, negated, extraRedundantCheck);
Expand Down Expand Up @@ -1757,7 +1762,7 @@ class ContextKeyAndExpr implements IContextKeyExpression {
}
}

class ContextKeyOrExpr implements IContextKeyExpression {
export class ContextKeyOrExpr implements IContextKeyExpression {

public static create(_expr: ReadonlyArray<ContextKeyExpression | null | undefined>, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {
return ContextKeyOrExpr._normalizeArr(_expr, negated, extraRedundantCheck);
Expand Down
6 changes: 3 additions & 3 deletions src/vs/platform/contextkey/test/common/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ suite('Context Key Parser', () => {
assert.deepStrictEqual(parseToStr(input), "resource =~ /((\\/scratch\\/(?!update)(.*)\\/)|((\\/src\\/).*\\/)).*$/");
});

test(`resourcePath =~ /\.md(\.yml|\.txt)*$/gim`, () => {
const input = `resourcePath =~ /\.md(\.yml|\.txt)*$/gim`;
assert.deepStrictEqual(parseToStr(input), "resourcePath =~ /.md(.yml|.txt)*$/gim");
test(`resourcePath =~ /\.md(\.yml|\.txt)*$/giym`, () => {
const input = `resourcePath =~ /\.md(\.yml|\.txt)*$/giym`;
assert.deepStrictEqual(parseToStr(input), "resourcePath =~ /.md(.yml|.txt)*$/im");
});

});
Expand Down