Better error recovery when encountering an errant comma in a semicolon delimited list.

This commit is contained in:
Cyrus Najmabadi 2014-12-08 15:35:09 -08:00
parent 9351fc1920
commit 5db51fead8
2 changed files with 29 additions and 32 deletions

View file

@ -1338,15 +1338,17 @@ module ts {
return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak();
}
function parseSemicolon(diagnosticMessage?: DiagnosticMessage): void {
function parseSemicolon(diagnosticMessage?: DiagnosticMessage): boolean {
if (canParseSemicolon()) {
if (token === SyntaxKind.SemicolonToken) {
// consume the semicolon if it was explicitly provided.
nextToken();
}
return true;
}
else {
parseExpected(SyntaxKind.SemicolonToken, diagnosticMessage);
return parseExpected(SyntaxKind.SemicolonToken, diagnosticMessage);
}
}
@ -2052,13 +2054,27 @@ module ts {
return requireCompleteParameterList ? undefined : createMissingList<ParameterDeclaration>();
}
function parseTypeMemberSemicolon() {
// Try to parse out an explicit or implicit (ASI) semicolon for a type member. If we
// don't have one, then an appropriate error will be reported.
if (parseSemicolon()) {
return;
}
// If we don't have a semicolon, then the user may have written a comma instead
// accidently (pretty easy to do since commas are so prevalent as list separators). So
// just consume the comma and keep going. Note: we'll have already reported the error
// about the missing semicolon above.
parseOptional(SyntaxKind.CommaToken);
}
function parseSignatureMember(kind: SyntaxKind): SignatureDeclaration {
var node = <SignatureDeclaration>createNode(kind);
if (kind === SyntaxKind.ConstructSignature) {
parseExpected(SyntaxKind.NewKeyword);
}
fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, node);
parseSemicolon();
parseTypeMemberSemicolon();
return finishNode(node);
}
@ -2130,11 +2146,11 @@ module ts {
setModifiers(node, modifiers);
node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
node.type = parseTypeAnnotation();
parseSemicolon();
parseTypeMemberSemicolon();
return finishNode(node)
}
function parsePropertyOrMethod(): Declaration {
function parsePropertyOrMethodSignature(): Declaration {
var fullStart = scanner.getStartPos();
var name = parsePropertyName();
var questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
@ -2147,8 +2163,7 @@ module ts {
// Method signatues don't exist in expression contexts. So they have neither
// [Yield] nor [GeneratorParameter]
fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, method);
parseSemicolon();
parseTypeMemberSemicolon();
return finishNode(method);
}
else {
@ -2156,7 +2171,7 @@ module ts {
property.name = name;
property.questionToken = questionToken;
property.type = parseTypeAnnotation();
parseSemicolon();
parseTypeMemberSemicolon();
return finishNode(property);
}
}
@ -2188,7 +2203,7 @@ module ts {
return parseSignatureMember(SyntaxKind.CallSignature);
case SyntaxKind.OpenBracketToken:
// Indexer or computed property
return isIndexSignature() ? parseIndexSignatureDeclaration(scanner.getStartPos(), /*modifiers:*/ undefined) : parsePropertyOrMethod();
return isIndexSignature() ? parseIndexSignatureDeclaration(scanner.getStartPos(), /*modifiers:*/ undefined) : parsePropertyOrMethodSignature();
case SyntaxKind.NewKeyword:
if (lookAhead(isStartOfConstructSignature)) {
return parseSignatureMember(SyntaxKind.ConstructSignature);
@ -2196,10 +2211,10 @@ module ts {
// fall through.
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
return parsePropertyOrMethod();
return parsePropertyOrMethodSignature();
default:
if (isIdentifierOrKeyword()) {
return parsePropertyOrMethod();
return parsePropertyOrMethodSignature();
}
}
}

View file

@ -1,29 +1,11 @@
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,38): error TS1134: Variable declaration expected.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,60): error TS1005: ';' expected.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,70): error TS1128: Declaration or statement expected.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,53): error TS1005: ';' expected.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,9): error TS2304: Cannot find name '$'.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,31): error TS2304: Cannot find name 'any'.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,50): error TS2304: Cannot find name 'any'.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,55): error TS2304: Cannot find name 'width'.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts(1,62): error TS2304: Cannot find name 'string'.
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts (8 errors) ====
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts (2 errors) ====
var s = $.extend< { workItem: any }, { workItem: any, width: string }>({ workItem: this._workItem }, {});
~
!!! error TS1134: Variable declaration expected.
~
~
!!! error TS1005: ';' expected.
~
!!! error TS1128: Declaration or statement expected.
~
!!! error TS2304: Cannot find name '$'.
~~~
!!! error TS2304: Cannot find name 'any'.
~~~
!!! error TS2304: Cannot find name 'any'.
~~~~~
!!! error TS2304: Cannot find name 'width'.
~~~~~~
!!! error TS2304: Cannot find name 'string'.