mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Better error recover when there is an unterminated expression before a declaration.
This commit is contained in:
parent
db2bf0a309
commit
ebe8711a21
@ -1589,12 +1589,47 @@ module ts {
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
var node = <QualifiedName>createNode(SyntaxKind.QualifiedName, entity.pos);
|
||||
node.left = entity;
|
||||
node.right = allowReservedWords ? parseIdentifierName() : parseIdentifier();
|
||||
node.right = parseRightSideOfDot(allowReservedWords);
|
||||
entity = finishNode(node);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
function parseRightSideOfDot(allowIdentifierNames: boolean): Identifier {
|
||||
// Technically a keyword is valid here as all keywords are identifier names.
|
||||
// However, often we'll encounter this in error situations when the keyword
|
||||
// is actually starting another valid construct.
|
||||
//
|
||||
// So, we check for the following specific case:
|
||||
//
|
||||
// name.
|
||||
// keyword identifierNameOrKeyword
|
||||
//
|
||||
// Note: the newlines are important here. For example, if that above code
|
||||
// were rewritten into:
|
||||
//
|
||||
// name.keyword
|
||||
// identifierNameOrKeyword
|
||||
//
|
||||
// Then we would consider it valid. That's because ASI would take effect and
|
||||
// the code would be implicitly: "name.keyword; identifierNameOrKeyword".
|
||||
// In the first case though, ASI will not take effect because there is not a
|
||||
// line terminator after the keyword.
|
||||
if (scanner.hasPrecedingLineBreak() && scanner.isReservedWord()) {
|
||||
var matchesPattern = lookAhead(() => {
|
||||
nextToken();
|
||||
return !scanner.hasPrecedingLineBreak() && (scanner.isIdentifier() || scanner.isReservedWord());
|
||||
});
|
||||
|
||||
if (matchesPattern) {
|
||||
errorAtPos(scanner.getTokenPos(), 0, Diagnostics.Identifier_expected);
|
||||
return <Identifier>createMissingNode();
|
||||
}
|
||||
}
|
||||
|
||||
return allowIdentifierNames ? parseIdentifierName() : parseIdentifier();
|
||||
}
|
||||
|
||||
function parseTokenNode(): PrimaryExpression {
|
||||
var node = <PrimaryExpression>createNode(token);
|
||||
nextToken();
|
||||
@ -2847,7 +2882,7 @@ module ts {
|
||||
var node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
node.expression = expression;
|
||||
parseExpected(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
|
||||
node.name = parseIdentifierName();
|
||||
node.name = parseRightSideOfDot(/*allowIdentifierNames:*/ true);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@ -2865,40 +2900,8 @@ module ts {
|
||||
var dotOrBracketStart = scanner.getTokenPos();
|
||||
if (parseOptional(SyntaxKind.DotToken)) {
|
||||
var propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
// Technically a keyword is valid here as all keywords are identifier names.
|
||||
// However, often we'll encounter this in error situations when the keyword
|
||||
// is actually starting another valid construct.
|
||||
//
|
||||
// So, we check for the following specific case:
|
||||
//
|
||||
// name.
|
||||
// keyword identifierNameOrKeyword
|
||||
//
|
||||
// Note: the newlines are important here. For example, if that above code
|
||||
// were rewritten into:
|
||||
//
|
||||
// name.keyword
|
||||
// identifierNameOrKeyword
|
||||
//
|
||||
// Then we would consider it valid. That's because ASI would take effect and
|
||||
// the code would be implicitly: "name.keyword; identifierNameOrKeyword".
|
||||
// In the first case though, ASI will not take effect because there is not a
|
||||
// line terminator after the keyword.
|
||||
var id: Identifier;
|
||||
if (scanner.hasPrecedingLineBreak() && scanner.isReservedWord()) {
|
||||
var matchesPattern = lookAhead(() => {
|
||||
nextToken();
|
||||
return !scanner.hasPrecedingLineBreak() && (scanner.isIdentifier() || scanner.isReservedWord);
|
||||
});
|
||||
|
||||
if (matchesPattern) {
|
||||
errorAtPos(dotOrBracketStart + 1, 0, Diagnostics.Identifier_expected);
|
||||
id = <Identifier>createMissingNode();
|
||||
}
|
||||
}
|
||||
|
||||
propertyAccess.expression = expression;
|
||||
propertyAccess.name = id || parseIdentifierName();
|
||||
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames:*/ true);
|
||||
expression = finishNode(propertyAccess);
|
||||
continue;
|
||||
}
|
||||
@ -3226,9 +3229,7 @@ module ts {
|
||||
function parseDoStatement(): DoStatement {
|
||||
var node = <DoStatement>createNode(SyntaxKind.DoStatement);
|
||||
parseExpected(SyntaxKind.DoKeyword);
|
||||
|
||||
node.statement = parseStatement();
|
||||
|
||||
parseExpected(SyntaxKind.WhileKeyword);
|
||||
parseExpected(SyntaxKind.OpenParenToken);
|
||||
node.expression = allowInAnd(parseExpression);
|
||||
@ -3248,9 +3249,7 @@ module ts {
|
||||
parseExpected(SyntaxKind.OpenParenToken);
|
||||
node.expression = allowInAnd(parseExpression);
|
||||
parseExpected(SyntaxKind.CloseParenToken);
|
||||
|
||||
node.statement = parseStatement();
|
||||
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
tests/cases/compiler/enumConflictsWithGlobalIdentifier.ts(4,29): error TS1003: Identifier expected.
|
||||
tests/cases/compiler/enumConflictsWithGlobalIdentifier.ts(5,1): error TS1003: Identifier expected.
|
||||
tests/cases/compiler/enumConflictsWithGlobalIdentifier.ts(4,9): error TS2304: Cannot find name 'IgnoreRulesSpecific'.
|
||||
|
||||
|
||||
@ -7,9 +7,9 @@ tests/cases/compiler/enumConflictsWithGlobalIdentifier.ts(4,9): error TS2304: Ca
|
||||
IgnoreRulesSpecific = 0,
|
||||
}
|
||||
var x = IgnoreRulesSpecific.
|
||||
|
||||
!!! error TS1003: Identifier expected.
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2304: Cannot find name 'IgnoreRulesSpecific'.
|
||||
var y = Position.IgnoreRulesSpecific;
|
||||
|
||||
!!! error TS1003: Identifier expected.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
tests/cases/compiler/enumMemberResolution.ts(4,29): error TS1003: Identifier expected.
|
||||
tests/cases/compiler/enumMemberResolution.ts(5,1): error TS1003: Identifier expected.
|
||||
tests/cases/compiler/enumMemberResolution.ts(4,9): error TS2304: Cannot find name 'IgnoreRulesSpecific'.
|
||||
|
||||
|
||||
@ -7,10 +7,10 @@ tests/cases/compiler/enumMemberResolution.ts(4,9): error TS2304: Cannot find nam
|
||||
IgnoreRulesSpecific = 0
|
||||
}
|
||||
var x = IgnoreRulesSpecific. // error
|
||||
|
||||
!!! error TS1003: Identifier expected.
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2304: Cannot find name 'IgnoreRulesSpecific'.
|
||||
var y = 1;
|
||||
|
||||
!!! error TS1003: Identifier expected.
|
||||
var z = Position2.IgnoreRulesSpecific; // no error
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user