mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Understand and handle modifiers on function declarations and variable statements within blocks.
This ensures reusability for functions/variables that may have been outside a block, but end up
inside one afterwards. It also ensure the same tree is produced when incremental parsing.
i.e. if you have:
declare function F() { }
And you add a { above it, then we current have an incremental parsing bug. Namely we would see
a FunctionDeclaration node and say 'yes, we can reuse that node while parsing the block'. This
is currently broken because the normal parse would not have normally accepted such a node (because
of the modifiers).
This was an example of contextual parsing of the same kind of node. Something which we do not
want to do if we want incremental parsing to work properly.
This commit is contained in:
@@ -144,6 +144,7 @@ module ts {
|
||||
Array_element_destructuring_pattern_expected: { code: 1181, category: DiagnosticCategory.Error, key: "Array element destructuring pattern expected." },
|
||||
A_destructuring_declaration_must_have_an_initializer: { code: 1182, category: DiagnosticCategory.Error, key: "A destructuring declaration must have an initializer." },
|
||||
Destructuring_declarations_are_not_allowed_in_ambient_contexts: { code: 1183, category: DiagnosticCategory.Error, key: "Destructuring declarations are not allowed in ambient contexts." },
|
||||
Modifiers_cannot_appear_here: { code: 1184, category: DiagnosticCategory.Error, key: "Modifiers cannot appear here." },
|
||||
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
|
||||
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
|
||||
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
|
||||
|
||||
@@ -568,6 +568,10 @@
|
||||
"category": "Error",
|
||||
"code": 1183
|
||||
},
|
||||
"Modifiers cannot appear here.": {
|
||||
"category": "Error",
|
||||
"code": 1184
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -3866,12 +3866,45 @@ module ts {
|
||||
}
|
||||
// Else parse it like identifier - fall through
|
||||
default:
|
||||
if (isModifier(token)) {
|
||||
var result = tryParse(parseVariableStatementOrFunctionDeclarationWithModifiers);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return isLabel()
|
||||
? parseLabeledStatement()
|
||||
: parseExpressionStatement();
|
||||
}
|
||||
}
|
||||
|
||||
function parseVariableStatementOrFunctionDeclarationWithModifiers(): FunctionDeclaration | VariableStatement {
|
||||
var start = scanner.getStartPos();
|
||||
var modifiers = parseModifiers();
|
||||
switch (token) {
|
||||
case SyntaxKind.ConstKeyword:
|
||||
var nextTokenIsEnum = lookAhead(nextTokenIsEnumKeyword)
|
||||
if (nextTokenIsEnum) {
|
||||
return undefined;
|
||||
}
|
||||
return parseVariableStatement(start, modifiers);
|
||||
|
||||
case SyntaxKind.LetKeyword:
|
||||
if (!isLetDeclaration()) {
|
||||
return undefined;
|
||||
}
|
||||
return parseVariableStatement(start, modifiers);
|
||||
|
||||
case SyntaxKind.VarKeyword:
|
||||
return parseVariableStatement(start, modifiers);
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
return parseFunctionDeclaration(start, modifiers);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseFunctionBlockOrSemicolon(isGenerator: boolean): Block {
|
||||
if (token === SyntaxKind.OpenBraceToken) {
|
||||
return parseFunctionBlock(isGenerator, /*ignoreMissingOpenBrace:*/ false);
|
||||
@@ -4600,6 +4633,7 @@ module ts {
|
||||
// We're automatically in an ambient context if this is a .d.ts file.
|
||||
var inAmbientContext = fileExtensionIs(file.filename, ".d.ts");
|
||||
var inFunctionBlock = false;
|
||||
var inBlock = false;
|
||||
var parent: Node;
|
||||
visitNode(file);
|
||||
|
||||
@@ -4614,6 +4648,10 @@ module ts {
|
||||
if (isFunctionBlock(node)) {
|
||||
inFunctionBlock = true;
|
||||
}
|
||||
var savedInBlock = inBlock;
|
||||
if (node.kind === SyntaxKind.Block || node.kind === SyntaxKind.TryBlock || node.kind === SyntaxKind.FinallyBlock) {
|
||||
inBlock = true;
|
||||
}
|
||||
|
||||
var savedInAmbientContext = inAmbientContext
|
||||
if (node.flags & NodeFlags.Ambient) {
|
||||
@@ -4624,6 +4662,7 @@ module ts {
|
||||
|
||||
inAmbientContext = savedInAmbientContext;
|
||||
inFunctionBlock = savedInFunctionBlock;
|
||||
inBlock = savedInBlock;
|
||||
}
|
||||
|
||||
parent = savedParent;
|
||||
@@ -5085,7 +5124,8 @@ module ts {
|
||||
}
|
||||
|
||||
function checkFunctionDeclaration(node: FunctionLikeDeclaration) {
|
||||
return checkAnySignatureDeclaration(node) ||
|
||||
return checkForDisallowedModifiersInBlock(node) ||
|
||||
checkAnySignatureDeclaration(node) ||
|
||||
checkFunctionName(node.name) ||
|
||||
checkForBodyInAmbientContext(node.body, /*isConstructor:*/ false) ||
|
||||
checkForGenerator(node);
|
||||
@@ -5820,10 +5860,17 @@ module ts {
|
||||
}
|
||||
|
||||
function checkVariableStatement(node: VariableStatement) {
|
||||
return checkVariableDeclarations(node.declarations) ||
|
||||
return checkForDisallowedModifiersInBlock(node) ||
|
||||
checkVariableDeclarations(node.declarations) ||
|
||||
checkForDisallowedLetOrConstStatement(node);
|
||||
}
|
||||
|
||||
function checkForDisallowedModifiersInBlock(node: Node) {
|
||||
if (inBlock && node.modifiers) {
|
||||
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
|
||||
}
|
||||
}
|
||||
|
||||
function checkForDisallowedLetOrConstStatement(node: VariableStatement) {
|
||||
if (!allowLetAndConstDeclarations(node.parent)) {
|
||||
if (isLet(node)) {
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,12): error TS1005: ';' expected.
|
||||
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,4): error TS2304: Cannot find name 'declare'.
|
||||
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,4): error TS1184: Modifiers cannot appear here.
|
||||
|
||||
|
||||
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts (2 errors) ====
|
||||
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts (1 errors) ====
|
||||
{
|
||||
declare var x = this;
|
||||
~~~
|
||||
!!! error TS1005: ';' expected.
|
||||
~~~~~~~
|
||||
!!! error TS2304: Cannot find name 'declare'.
|
||||
!!! error TS1184: Modifiers cannot appear here.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user