Added code to better handle the obsolete "<>" operator from Python 2 - including a better error message and better parse recovery.

This commit is contained in:
Eric Traut 2020-06-26 19:38:22 -07:00
parent 317e853539
commit 2cf7f61fc6
9 changed files with 27 additions and 2 deletions

View File

@ -404,6 +404,7 @@ export function printOperator(operator: OperatorType): string {
[OperatorType.GreaterThanOrEqual]: '>=',
[OperatorType.LeftShift]: '<<',
[OperatorType.LeftShiftEqual]: '<<=',
[OperatorType.LessOrGreaterThan]: '<>',
[OperatorType.LessThan]: '<',
[OperatorType.LessThanOrEqual]: '<=',
[OperatorType.MatrixMultiply]: '@',

View File

@ -398,6 +398,7 @@ export namespace Localizer {
new ParameterizedString<{ name: string }>(getRawString('Diagnostic.obscuredParameterDeclaration'));
export const obscuredVariableDeclaration = () =>
new ParameterizedString<{ name: string }>(getRawString('Diagnostic.obscuredVariableDeclaration'));
export const operatorLessOrGreaterDeprecated = () => getRawString('Diagnostic.operatorLessOrGreaterDeprecated');
export const optionalExtraArgs = () => getRawString('Diagnostic.optionalExtraArgs');
export const paramAfterKwargsParam = () => getRawString('Diagnostic.paramAfterKwargsParam');
export const paramAlreadyAssigned = () =>

View File

@ -182,6 +182,7 @@
"obscuredFunctionDeclaration": "Function declaration \"{name}\" is obscured by a declaration of the same name",
"obscuredParameterDeclaration": "Parameter declaration \"{name}\" is obscured by a declaration of the same name",
"obscuredVariableDeclaration": "Declaration \"{name}\" is obscured by a declaration of the same name",
"operatorLessOrGreaterDeprecated": "Operator \"<>\" is not supported in Python 3; use \"!=\" instead",
"optionalExtraArgs": "Expected one type argument after \"Optional\"",
"paramAfterKwargsParam": "Parameter cannot follow \"**\" parameter",
"paramAlreadyAssigned": "Parameter \"{name}\" is already assigned",

View File

@ -1805,6 +1805,10 @@ export class Parser {
if (Tokenizer.isOperatorComparison(this._peekOperatorType())) {
comparisonOperator = this._peekOperatorType();
if (comparisonOperator === OperatorType.LessOrGreaterThan) {
this._addError(Localizer.Diagnostic.operatorLessOrGreaterDeprecated(), peekToken);
comparisonOperator = OperatorType.NotEquals;
}
this._getNextToken();
} else if (this._consumeTokenIfKeyword(KeywordType.In)) {
comparisonOperator = OperatorType.In;

View File

@ -94,6 +94,7 @@ const _operatorInfo: { [key: number]: OperatorFlags } = {
[OperatorType.GreaterThanOrEqual]: OperatorFlags.Binary | OperatorFlags.Comparison,
[OperatorType.LeftShift]: OperatorFlags.Binary,
[OperatorType.LeftShiftEqual]: OperatorFlags.Assignment,
[OperatorType.LessOrGreaterThan]: OperatorFlags.Binary | OperatorFlags.Comparison | OperatorFlags.Deprecated,
[OperatorType.LessThan]: OperatorFlags.Binary | OperatorFlags.Comparison,
[OperatorType.LessThanOrEqual]: OperatorFlags.Binary | OperatorFlags.Comparison,
[OperatorType.MatrixMultiply]: OperatorFlags.Binary,
@ -869,6 +870,9 @@ export class Tokenizer {
if (nextChar === Char.Less) {
length = this._cs.lookAhead(2) === Char.Equal ? 3 : 2;
operatorType = length === 3 ? OperatorType.LeftShiftEqual : OperatorType.LeftShift;
} else if (nextChar === Char.Greater) {
length = 2;
operatorType = OperatorType.LessOrGreaterThan;
} else {
length = nextChar === Char.Equal ? 2 : 1;
operatorType = length === 2 ? OperatorType.LessThanOrEqual : OperatorType.LessThan;

View File

@ -68,6 +68,7 @@ export const enum OperatorType {
GreaterThanOrEqual,
LeftShift,
LeftShiftEqual,
LessOrGreaterThan,
LessThan,
LessThanOrEqual,
MatrixMultiply,
@ -101,6 +102,7 @@ export const enum OperatorFlags {
Binary = 1 << 1,
Assignment = 1 << 2,
Comparison = 1 << 3,
Deprecated = 1 << 4,
}
export const enum KeywordType {

View File

@ -536,6 +536,12 @@ test('Operators4', () => {
validateResults(analysisResults, 0);
});
test('Operators5', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['operators5.py']);
validateResults(analysisResults, 1);
});
test('Optional1', () => {
const configOptions = new ConfigOptions('.');

View File

@ -0,0 +1,5 @@
# This sample tests the parsing of the deprecated <> operator.
# This should generate a single error, not a cascade of errors.
if 3 <> 5:
print("OK")

View File

@ -1259,9 +1259,9 @@ test('Operators', () => {
'* ** / // /= //=' +
'*= += -= %= **= ' +
'& &= | |= ^ ^= ' +
':=';
':= <>';
const results = new Tokenizer().tokenize(text);
const lengths = [1, 2, 3, 2, 2, 1, 2, 3, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 3, 2, 2, 2, 2, 3, 1, 2, 1, 2, 1, 2, 2];
const lengths = [1, 2, 3, 2, 2, 1, 2, 3, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 3, 2, 2, 2, 2, 3, 1, 2, 1, 2, 1, 2, 2, 2];
const operatorTypes = [
OperatorType.LessThan,
OperatorType.LeftShift,
@ -1295,6 +1295,7 @@ test('Operators', () => {
OperatorType.BitwiseXor,
OperatorType.BitwiseXorEqual,
OperatorType.Walrus,
OperatorType.LessOrGreaterThan,
];
assert.equal(results.tokens.count - _implicitTokenCount, lengths.length);
assert.equal(results.tokens.count - _implicitTokenCount, operatorTypes.length);