mirror of
https://github.com/Microsoft/vscode
synced 2024-11-05 18:29:38 +00:00
context keys: scanner: support triple equal and triple not equal as double equal and double not equal respectively
This commit is contained in:
parent
aa8367e132
commit
1a25bd5f0f
2 changed files with 33 additions and 23 deletions
|
@ -35,8 +35,8 @@ export type Token =
|
|||
| { type: TokenType.LParen; offset: number }
|
||||
| { type: TokenType.RParen; offset: number }
|
||||
| { type: TokenType.Neg; offset: number }
|
||||
| { type: TokenType.Eq; offset: number }
|
||||
| { type: TokenType.NotEq; offset: number }
|
||||
| { type: TokenType.Eq; offset: number; isTripleEq: boolean }
|
||||
| { type: TokenType.NotEq; offset: number; isTripleEq: boolean }
|
||||
| { type: TokenType.Lt; offset: number }
|
||||
| { type: TokenType.LtEq; offset: number }
|
||||
| { type: TokenType.Gt; offset: number }
|
||||
|
@ -59,8 +59,6 @@ type TokenTypeWithoutLexeme =
|
|||
TokenType.LParen |
|
||||
TokenType.RParen |
|
||||
TokenType.Neg |
|
||||
TokenType.Eq |
|
||||
TokenType.NotEq |
|
||||
TokenType.Lt |
|
||||
TokenType.LtEq |
|
||||
TokenType.Gt |
|
||||
|
@ -98,7 +96,6 @@ function hintDidYouMean(...meant: string[]) {
|
|||
}
|
||||
}
|
||||
|
||||
const hintDontSupportTripleEq = localize('contextkey.scanner.hint.dontSupportTripleEq', "The '===' operator is not supported. Use '==' instead.");
|
||||
const hintDidYouForgetToOpenOrCloseQuote = localize('contextkey.scanner.hint.didYouForgetToOpenOrCloseQuote', "Did you forget to open or close the quote?");
|
||||
const hintDidYouForgetToEscapeSlash = localize('contextkey.scanner.hint.didYouForgetToEscapeSlash', "Did you forget to escape the '/' (slash) character? Put two backslashes before it to escape, e.g., '\\\\/\'.");
|
||||
|
||||
|
@ -128,9 +125,9 @@ export class Scanner {
|
|||
case TokenType.Neg:
|
||||
return '!';
|
||||
case TokenType.Eq:
|
||||
return '==';
|
||||
return token.isTripleEq ? '===' : '==';
|
||||
case TokenType.NotEq:
|
||||
return '!=';
|
||||
return token.isTripleEq ? '!==' : '!=';
|
||||
case TokenType.Lt:
|
||||
return '<';
|
||||
case TokenType.LtEq:
|
||||
|
@ -209,7 +206,12 @@ export class Scanner {
|
|||
case CharCode.CloseParen: this._addToken(TokenType.RParen); break;
|
||||
|
||||
case CharCode.ExclamationMark:
|
||||
this._addToken(this._match(CharCode.Equals) ? TokenType.NotEq : TokenType.Neg);
|
||||
if (this._match(CharCode.Equals)) {
|
||||
const isTripleEq = this._match(CharCode.Equals); // eat last `=` if `!==`
|
||||
this._tokens.push({ type: TokenType.NotEq, offset: this._start, isTripleEq });
|
||||
} else {
|
||||
this._addToken(TokenType.Neg);
|
||||
}
|
||||
break;
|
||||
|
||||
case CharCode.SingleQuote: this._quotedString(); break;
|
||||
|
@ -217,15 +219,12 @@ export class Scanner {
|
|||
|
||||
case CharCode.Equals:
|
||||
if (this._match(CharCode.Equals)) { // support `==`
|
||||
this._addToken(TokenType.Eq);
|
||||
const isTripleEq = this._match(CharCode.Equals); // eat last `=` if `===`
|
||||
this._tokens.push({ type: TokenType.Eq, offset: this._start, isTripleEq });
|
||||
} else if (this._match(CharCode.Tilde)) {
|
||||
this._addToken(TokenType.RegexOp);
|
||||
} else {
|
||||
if (this._tokens.length === 0 || this._tokens[this._tokens.length - 1].type !== TokenType.Eq) {
|
||||
this._error(hintDidYouMean('==', '=~'));
|
||||
} else {
|
||||
this._error(hintDontSupportTripleEq);
|
||||
}
|
||||
this._error(hintDidYouMean('==', '=~'));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -294,7 +293,7 @@ export class Scanner {
|
|||
private _error(additional?: string) {
|
||||
const offset = this._start;
|
||||
const lexeme = this._input.substring(this._start, this._current);
|
||||
const errToken = { type: TokenType.Error, offset: this._start, lexeme };
|
||||
const errToken: Token = { type: TokenType.Error, offset: this._start, lexeme };
|
||||
this._errors.push({ offset, lexeme, additionalInfo: additional });
|
||||
this._tokens.push(errToken);
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ suite('Context Key Scanner', () => {
|
|||
case TokenType.Neg:
|
||||
return '!';
|
||||
case TokenType.Eq:
|
||||
return '==';
|
||||
return token.isTripleEq ? '===' : '==';
|
||||
case TokenType.NotEq:
|
||||
return '!=';
|
||||
return token.isTripleEq ? '!==' : '!=';
|
||||
case TokenType.Lt:
|
||||
return '<';
|
||||
case TokenType.LtEq:
|
||||
|
@ -53,6 +53,7 @@ suite('Context Key Scanner', () => {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
function scan(input: string) {
|
||||
return (new Scanner()).reset(input).scan().map((token: Token) => {
|
||||
return 'lexeme' in token
|
||||
|
@ -79,6 +80,16 @@ suite('Context Key Scanner', () => {
|
|||
assert.deepStrictEqual(scan(input), ([{ type: "!", offset: 0 }, { type: "Str", lexeme: "foo", offset: 1 }, { type: "EOF", offset: 4 }]));
|
||||
});
|
||||
|
||||
test('foo === bar', () => {
|
||||
const input = 'foo === bar';
|
||||
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "Str", offset: 8, lexeme: "bar" }, { type: "EOF", offset: 11 }]));
|
||||
});
|
||||
|
||||
test('foo !== bar', () => {
|
||||
const input = 'foo !== bar';
|
||||
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "!==", offset: 5 }, { type: "Str", offset: 9, lexeme: "bar" }, { type: "EOF", offset: 12 }]));
|
||||
});
|
||||
|
||||
test('!(foo && bar)', () => {
|
||||
const input = '!(foo && bar)';
|
||||
assert.deepStrictEqual(scan(input), ([{ type: "!", offset: 0 }, { type: "(", offset: 1 }, { type: "Str", lexeme: "foo", offset: 2 }, { type: "&&", offset: 6 }, { type: "Str", lexeme: "bar", offset: 9 }, { type: ")", offset: 12 }, { type: "EOF", offset: 13 }]));
|
||||
|
@ -181,11 +192,16 @@ suite('Context Key Scanner', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test(`foo === bar'`, () => {
|
||||
const input = `foo === bar'`;
|
||||
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "Str", offset: 8, lexeme: "bar" }, { type: "ErrorToken", offset: 11, lexeme: "'" }, { type: "EOF", offset: 12 }]));
|
||||
});
|
||||
|
||||
suite('handling lexical errors', () => {
|
||||
|
||||
test(`foo === '`, () => {
|
||||
const input = `foo === '`;
|
||||
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "==", offset: 4 }, { type: "ErrorToken", offset: 6, lexeme: "=" }, { type: "ErrorToken", offset: 8, lexeme: "'" }, { type: "EOF", offset: 9 }]));
|
||||
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "ErrorToken", offset: 8, lexeme: "'" }, { type: "EOF", offset: 9 }]));
|
||||
});
|
||||
|
||||
test(`foo && 'bar - unterminated single quote`, () => {
|
||||
|
@ -193,11 +209,6 @@ suite('Context Key Scanner', () => {
|
|||
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo", offset: 0 }, { type: "&&", offset: 4 }, { type: "ErrorToken", offset: 7, lexeme: "'bar" }, { type: "EOF", offset: 11 }]));
|
||||
});
|
||||
|
||||
test(`foo === bar'`, () => {
|
||||
const input = `foo === bar'`;
|
||||
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "==", offset: 4 }, { type: "ErrorToken", offset: 6, lexeme: "=" }, { type: "Str", offset: 8, lexeme: "bar" }, { type: "ErrorToken", offset: 11, lexeme: "'" }, { type: "EOF", offset: 12 }]));
|
||||
});
|
||||
|
||||
test('vim<c-r> == 1 && vim<2 <= 3', () => {
|
||||
const input = 'vim<c-r> == 1 && vim<2 <= 3';
|
||||
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "vim<c-r>", offset: 0 }, { type: "==", offset: 9 }, { type: "Str", lexeme: "1", offset: 12 }, { type: "&&", offset: 14 }, { type: "Str", lexeme: "vim<2", offset: 17 }, { type: "<=", offset: 23 }, { type: "Str", lexeme: "3", offset: 26 }, { type: "EOF", offset: 27 }]));
|
||||
|
|
Loading…
Reference in a new issue