mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-13 04:57:55 -06:00
Gracefully handle 'catch' and 'finally' blocks without a preceding 'try' block.
Fixes #216. As a note of this fix, when a 'catch' block is followed by a 'finally' block, only the 'catch' keyword gets an error reported on it.
This commit is contained in:
parent
e4256d827d
commit
efb6db8757
@ -160,6 +160,8 @@ module ts {
|
||||
Constructor_implementation_expected: { code: 2240, category: DiagnosticCategory.Error, key: "Constructor implementation expected." },
|
||||
An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements: { code: 2245, category: DiagnosticCategory.Error, key: "An export assignment cannot be used in a module with other exported elements." },
|
||||
A_parameter_property_is_only_allowed_in_a_constructor_implementation: { code: 2246, category: DiagnosticCategory.Error, key: "A parameter property is only allowed in a constructor implementation." },
|
||||
A_catch_clause_must_be_preceded_by_a_try_statement: { code: 2249, category: DiagnosticCategory.Error, key: "A 'catch' clause must be preceded by a 'try' statement." },
|
||||
A_finally_block_must_be_preceded_by_a_try_statement: { code: 2250, category: DiagnosticCategory.Error, key: "A 'finally' block must be preceded by a 'try' statement." },
|
||||
Circular_definition_of_import_alias_0: { code: 3000, category: DiagnosticCategory.Error, key: "Circular definition of import alias '{0}'." },
|
||||
Cannot_find_name_0: { code: 3001, category: DiagnosticCategory.Error, key: "Cannot find name '{0}'." },
|
||||
Module_0_has_no_exported_member_1: { code: 3002, category: DiagnosticCategory.Error, key: "Module '{0}' has no exported member '{1}'." },
|
||||
|
||||
@ -632,6 +632,15 @@
|
||||
"category": "Error",
|
||||
"code": 2246
|
||||
},
|
||||
"A 'catch' clause must be preceded by a 'try' statement.": {
|
||||
"category": "Error",
|
||||
"code": 2249
|
||||
},
|
||||
"A 'finally' block must be preceded by a 'try' statement.": {
|
||||
"category": "Error",
|
||||
"code": 2250
|
||||
},
|
||||
|
||||
"Circular definition of import alias '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 3000
|
||||
|
||||
@ -2542,6 +2542,35 @@ module ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
// This function is used for parsing 'catch'/'finally' blocks
|
||||
// in spite of them missing a 'try' statement.
|
||||
function parseCatchOrFinallyBlocksMissingTryStatement(): TryStatement {
|
||||
|
||||
Debug.assert(token === SyntaxKind.CatchKeyword || token === SyntaxKind.FinallyKeyword,
|
||||
"'parseCatchOrFinallyBlocksMissingTryStatement' should only be called when the current token is a 'catch' or 'finally' keyword.");
|
||||
|
||||
// We're just going to return a bogus TryStatement.
|
||||
var node = <TryStatement>createNode(SyntaxKind.TryStatement);
|
||||
node.tryBlock = <Block>createNode(SyntaxKind.Block);
|
||||
node.tryBlock.statements = createMissingList<Statement>();
|
||||
|
||||
if (token === SyntaxKind.CatchKeyword) {
|
||||
error(Diagnostics.A_catch_clause_must_be_preceded_by_a_try_statement);
|
||||
node.catchBlock = parseCatchBlock();
|
||||
}
|
||||
|
||||
if (token === SyntaxKind.FinallyKeyword) {
|
||||
// Only report an error on the 'finally' block if we haven't on the 'catch' block.
|
||||
if (node.catchBlock === undefined) {
|
||||
error(Diagnostics.A_finally_block_must_be_preceded_by_a_try_statement);
|
||||
}
|
||||
|
||||
node.finallyBlock = parseTokenAndBlock(SyntaxKind.FinallyKeyword, SyntaxKind.FinallyBlock);
|
||||
}
|
||||
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseTokenAndBlock(token: SyntaxKind, kind: SyntaxKind): Block {
|
||||
var pos = getNodePos();
|
||||
parseExpected(token);
|
||||
@ -2646,6 +2675,10 @@ module ts {
|
||||
case SyntaxKind.ThrowKeyword:
|
||||
case SyntaxKind.TryKeyword:
|
||||
case SyntaxKind.DebuggerKeyword:
|
||||
// 'catch' and 'finally' do not actually indicate that the code is part of a statement,
|
||||
// however, we say they are here so that we may gracefully parse them and error later.
|
||||
case SyntaxKind.CatchKeyword:
|
||||
case SyntaxKind.FinallyKeyword:
|
||||
return true;
|
||||
case SyntaxKind.InterfaceKeyword:
|
||||
case SyntaxKind.ClassKeyword:
|
||||
@ -2653,13 +2686,17 @@ module ts {
|
||||
case SyntaxKind.EnumKeyword:
|
||||
// When followed by an identifier, these do not start a statement but might
|
||||
// instead be following declarations
|
||||
if (isDeclaration()) return false;
|
||||
if (isDeclaration()) {
|
||||
return false;
|
||||
}
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.StaticKeyword:
|
||||
// When followed by an identifier or keyword, these do not start a statement but
|
||||
// might instead be following type members
|
||||
if (lookAhead(() => nextToken() >= SyntaxKind.Identifier)) return false;
|
||||
if (lookAhead(() => nextToken() >= SyntaxKind.Identifier)) {
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return isExpression();
|
||||
}
|
||||
@ -2697,6 +2734,9 @@ module ts {
|
||||
return parseThrowStatement();
|
||||
case SyntaxKind.TryKeyword:
|
||||
return parseTryStatement();
|
||||
case SyntaxKind.CatchKeyword:
|
||||
case SyntaxKind.FinallyKeyword:
|
||||
return parseCatchOrFinallyBlocksMissingTryStatement();
|
||||
case SyntaxKind.DebuggerKeyword:
|
||||
return parseDebuggerStatement();
|
||||
default:
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
==== tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts (4 errors) ====
|
||||
==== tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts (2 errors) ====
|
||||
function fn() {
|
||||
try {
|
||||
} catch { // syntax error, missing '(x)'
|
||||
@ -8,11 +8,7 @@
|
||||
|
||||
catch(x) { } // error missing try
|
||||
~~~~~
|
||||
!!! Statement expected.
|
||||
~
|
||||
!!! '=>' expected.
|
||||
!!! A 'catch' clause must be preceded by a 'try' statement.
|
||||
|
||||
finally{ } // error missing try
|
||||
~~~~~~~
|
||||
!!! Statement expected.
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
==== tests/cases/conformance/parser/ecmascript5/MissingTokens/parserMissingToken1.ts (2 errors) ====
|
||||
==== tests/cases/conformance/parser/ecmascript5/MissingTokens/parserMissingToken1.ts (3 errors) ====
|
||||
a / finally
|
||||
~~~~~~~
|
||||
!!! Expression expected.
|
||||
|
||||
!!! '{' expected.
|
||||
~
|
||||
!!! Cannot find name 'a'.
|
||||
Loading…
x
Reference in New Issue
Block a user