Move variable statement checks to the grammar checker.
This commit is contained in:
parent
6900c8ff81
commit
07f41dc786
|
@ -2721,14 +2721,10 @@ module ts {
|
|||
}
|
||||
|
||||
// STATEMENTS
|
||||
function parseStatementAllowingLetDeclaration() {
|
||||
return parseStatement(/*allowLetAndConstDeclarations*/ true);
|
||||
}
|
||||
|
||||
function parseBlock(ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean): Block {
|
||||
var node = <Block>createNode(SyntaxKind.Block);
|
||||
if (parseExpected(SyntaxKind.OpenBraceToken) || ignoreMissingOpenBrace) {
|
||||
node.statements = parseList(ParsingContext.BlockStatements, checkForStrictMode, parseStatementAllowingLetDeclaration);
|
||||
node.statements = parseList(ParsingContext.BlockStatements, checkForStrictMode, parseStatement);
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
else {
|
||||
|
@ -2774,8 +2770,8 @@ module ts {
|
|||
parseExpected(SyntaxKind.OpenParenToken);
|
||||
node.expression = parseExpression();
|
||||
parseExpected(SyntaxKind.CloseParenToken);
|
||||
node.thenStatement = parseStatement(/*allowLetAndConstDeclarations*/ false);
|
||||
node.elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement(/*allowLetAndConstDeclarations*/ false) : undefined;
|
||||
node.thenStatement = parseStatement();
|
||||
node.elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined;
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
|
@ -2785,7 +2781,7 @@ module ts {
|
|||
|
||||
var saveInIterationStatement = inIterationStatement;
|
||||
inIterationStatement = ControlBlockContext.Nested;
|
||||
node.statement = parseStatement(/*allowLetAndConstDeclarations*/ false);
|
||||
node.statement = parseStatement();
|
||||
inIterationStatement = saveInIterationStatement;
|
||||
|
||||
parseExpected(SyntaxKind.WhileKeyword);
|
||||
|
@ -2810,7 +2806,7 @@ module ts {
|
|||
|
||||
var saveInIterationStatement = inIterationStatement;
|
||||
inIterationStatement = ControlBlockContext.Nested;
|
||||
node.statement = parseStatement(/*allowLetAndConstDeclarations*/ false);
|
||||
node.statement = parseStatement();
|
||||
inIterationStatement = saveInIterationStatement;
|
||||
|
||||
return finishNode(node);
|
||||
|
@ -2883,7 +2879,7 @@ module ts {
|
|||
|
||||
var saveInIterationStatement = inIterationStatement;
|
||||
inIterationStatement = ControlBlockContext.Nested;
|
||||
forOrForInStatement.statement = parseStatement(/*allowLetAndConstDeclarations*/ false);
|
||||
forOrForInStatement.statement = parseStatement();
|
||||
inIterationStatement = saveInIterationStatement;
|
||||
|
||||
return finishNode(forOrForInStatement);
|
||||
|
@ -2994,7 +2990,7 @@ module ts {
|
|||
parseExpected(SyntaxKind.OpenParenToken);
|
||||
node.expression = parseExpression();
|
||||
parseExpected(SyntaxKind.CloseParenToken);
|
||||
node.statement = parseStatement(/*allowLetAndConstDeclarations*/ false);
|
||||
node.statement = parseStatement();
|
||||
node = finishNode(node);
|
||||
if (isInStrictMode) {
|
||||
// Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such
|
||||
|
@ -3009,7 +3005,7 @@ module ts {
|
|||
parseExpected(SyntaxKind.CaseKeyword);
|
||||
node.expression = parseExpression();
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatementAllowingLetDeclaration);
|
||||
node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
|
@ -3017,7 +3013,7 @@ module ts {
|
|||
var node = <CaseOrDefaultClause>createNode(SyntaxKind.DefaultClause);
|
||||
parseExpected(SyntaxKind.DefaultKeyword);
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatementAllowingLetDeclaration);
|
||||
node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
|
@ -3124,9 +3120,9 @@ module ts {
|
|||
return token === SyntaxKind.WhileKeyword || token === SyntaxKind.DoKeyword || token === SyntaxKind.ForKeyword;
|
||||
}
|
||||
|
||||
function parseStatementWithLabelSet(allowLetAndConstDeclarations: boolean): Statement {
|
||||
function parseStatementWithLabelSet(): Statement {
|
||||
labelledStatementInfo.pushCurrentLabelSet(isIterationStatementStart());
|
||||
var statement = parseStatement(allowLetAndConstDeclarations);
|
||||
var statement = parseStatement();
|
||||
labelledStatementInfo.pop();
|
||||
return statement;
|
||||
}
|
||||
|
@ -3135,7 +3131,7 @@ module ts {
|
|||
return isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.ColonToken);
|
||||
}
|
||||
|
||||
function parseLabeledStatement(allowLetAndConstDeclarations: boolean): LabeledStatement {
|
||||
function parseLabeledStatement(): LabeledStatement {
|
||||
var node = <LabeledStatement>createNode(SyntaxKind.LabeledStatement);
|
||||
node.label = parseIdentifier();
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
|
@ -3147,7 +3143,7 @@ module ts {
|
|||
|
||||
// We only want to call parseStatementWithLabelSet when the label set is complete
|
||||
// Therefore, keep parsing labels until we know we're done.
|
||||
node.statement = isLabel() ? parseLabeledStatement(allowLetAndConstDeclarations) : parseStatementWithLabelSet(allowLetAndConstDeclarations);
|
||||
node.statement = isLabel() ? parseLabeledStatement() : parseStatementWithLabelSet();
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
|
@ -3220,7 +3216,7 @@ module ts {
|
|||
}
|
||||
}
|
||||
|
||||
function parseStatement(allowLetAndConstDeclarations: boolean): Statement {
|
||||
function parseStatement(): Statement {
|
||||
switch (token) {
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
return parseBlock(/* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false);
|
||||
|
@ -3228,7 +3224,7 @@ module ts {
|
|||
case SyntaxKind.LetKeyword:
|
||||
case SyntaxKind.ConstKeyword:
|
||||
// const here should always be parsed as const declaration because of check in 'isStatement'
|
||||
return parseVariableStatement(allowLetAndConstDeclarations);
|
||||
return parseVariableStatement();
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
return parseFunctionDeclaration();
|
||||
case SyntaxKind.SemicolonToken:
|
||||
|
@ -3261,10 +3257,9 @@ module ts {
|
|||
case SyntaxKind.DebuggerKeyword:
|
||||
return parseDebuggerStatement();
|
||||
default:
|
||||
if (isLabel()) {
|
||||
return parseLabeledStatement(allowLetAndConstDeclarations);
|
||||
}
|
||||
return parseExpressionStatement();
|
||||
return isLabel()
|
||||
? parseLabeledStatement()
|
||||
: parseExpressionStatement();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3307,43 +3302,26 @@ module ts {
|
|||
() => parseVariableDeclaration(flags, noIn), /*allowTrailingComma*/ false);
|
||||
}
|
||||
|
||||
function parseVariableStatement(allowLetAndConstDeclarations: boolean, pos?: number, flags?: NodeFlags): VariableStatement {
|
||||
function parseVariableStatement(pos?: number, flags?: NodeFlags): VariableStatement {
|
||||
var node = <VariableStatement>createNode(SyntaxKind.VariableStatement, pos);
|
||||
if (flags) node.flags = flags;
|
||||
var errorCountBeforeVarStatement = file._parserDiagnostics.length;
|
||||
if (flags) {
|
||||
node.flags = flags;
|
||||
}
|
||||
|
||||
if (token === SyntaxKind.LetKeyword) {
|
||||
node.flags |= NodeFlags.Let;
|
||||
}
|
||||
else if (token === SyntaxKind.ConstKeyword) {
|
||||
node.flags |= NodeFlags.Const;
|
||||
}
|
||||
else if (token !== SyntaxKind.VarKeyword) {
|
||||
error(Diagnostics.var_let_or_const_expected);
|
||||
else {
|
||||
Debug.assert(token === SyntaxKind.VarKeyword);
|
||||
}
|
||||
|
||||
nextToken();
|
||||
node.declarations = parseVariableDeclarationList(node.flags, /*noIn*/false);
|
||||
parseSemicolon();
|
||||
finishNode(node);
|
||||
if (!node.declarations.length && file._parserDiagnostics.length === errorCountBeforeVarStatement) {
|
||||
grammarErrorOnNode(node, Diagnostics.Variable_declaration_list_cannot_be_empty);
|
||||
}
|
||||
if (languageVersion < ScriptTarget.ES6) {
|
||||
if (node.flags & NodeFlags.Let) {
|
||||
grammarErrorOnNode(node, Diagnostics.let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
|
||||
}
|
||||
else if (node.flags & NodeFlags.Const) {
|
||||
grammarErrorOnNode(node, Diagnostics.const_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
|
||||
}
|
||||
}
|
||||
else if (!allowLetAndConstDeclarations) {
|
||||
if (node.flags & NodeFlags.Let) {
|
||||
grammarErrorOnNode(node, Diagnostics.let_declarations_can_only_be_declared_inside_a_block);
|
||||
}
|
||||
else if (node.flags & NodeFlags.Const) {
|
||||
grammarErrorOnNode(node, Diagnostics.const_declarations_can_only_be_declared_inside_a_block);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseFunctionDeclaration(pos?: number, flags?: NodeFlags): FunctionLikeDeclaration {
|
||||
|
@ -3895,7 +3873,7 @@ module ts {
|
|||
switch (token) {
|
||||
case SyntaxKind.VarKeyword:
|
||||
case SyntaxKind.LetKeyword:
|
||||
result = parseVariableStatement(/*allowLetAndConstDeclarations*/ true, pos, flags);
|
||||
result = parseVariableStatement(pos, flags);
|
||||
break;
|
||||
case SyntaxKind.ConstKeyword:
|
||||
var isConstEnum = lookAhead(() => nextToken() === SyntaxKind.EnumKeyword);
|
||||
|
@ -3903,7 +3881,7 @@ module ts {
|
|||
result = parseAndCheckEnumDeclaration(pos, flags | NodeFlags.Const);
|
||||
}
|
||||
else {
|
||||
result = parseVariableStatement(/*allowLetAndConstDeclarations*/ true, pos, flags);
|
||||
result = parseVariableStatement(pos, flags);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
|
@ -3955,7 +3933,7 @@ module ts {
|
|||
var statementStart = scanner.getTokenPos();
|
||||
var statementFirstTokenLength = scanner.getTextPos() - statementStart;
|
||||
var errorCountBeforeStatement = file._parserDiagnostics.length;
|
||||
var statement = parseStatement(/*allowLetAndConstDeclarations*/ true);
|
||||
var statement = parseStatement();
|
||||
|
||||
if (inAmbientContext && file._parserDiagnostics.length === errorCountBeforeStatement) {
|
||||
grammarErrorAtPos(statementStart, statementFirstTokenLength, Diagnostics.Statements_are_not_allowed_in_ambient_contexts);
|
||||
|
@ -4076,10 +4054,14 @@ module ts {
|
|||
|
||||
// We're automatically in an ambient context if this is a .d.ts file.
|
||||
var inAmbientContext = fileExtensionIs(file.filename, ".d.ts");
|
||||
|
||||
var parent: Node;
|
||||
visitNode(file);
|
||||
|
||||
function visitNode(node: Node): void {
|
||||
var savedParent = parent;
|
||||
node.parent = parent;
|
||||
parent = node;
|
||||
|
||||
// First recurse and perform all grammar checks on the children of this node.
|
||||
var savedInAmbientContext = inAmbientContext
|
||||
if (node.flags & NodeFlags.Ambient) {
|
||||
|
@ -4096,6 +4078,7 @@ module ts {
|
|||
}
|
||||
|
||||
inAmbientContext = savedInAmbientContext;
|
||||
parent = savedParent;
|
||||
}
|
||||
|
||||
function checkNode(node: Node) {
|
||||
|
@ -4121,6 +4104,7 @@ module ts {
|
|||
case SyntaxKind.SetAccessor: return visitSetAccessor(<MethodDeclaration>node);
|
||||
case SyntaxKind.TaggedTemplateExpression: return visitTaggedTemplateExpression(<TaggedTemplateExpression>node);
|
||||
case SyntaxKind.VariableDeclaration: return visitVariableDeclaration(<VariableDeclaration>node);
|
||||
case SyntaxKind.VariableStatement: return visitVariableStatement(<VariableStatement>node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4501,6 +4485,44 @@ module ts {
|
|||
reportInvalidUseInStrictMode(node.name);
|
||||
}
|
||||
}
|
||||
|
||||
function visitVariableStatement(node: VariableStatement) {
|
||||
if (!node.declarations.length) {
|
||||
grammarErrorOnNode(node, Diagnostics.Variable_declaration_list_cannot_be_empty);
|
||||
}
|
||||
if (languageVersion < ScriptTarget.ES6) {
|
||||
if (node.flags & NodeFlags.Let) {
|
||||
grammarErrorOnNode(node, Diagnostics.let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
|
||||
}
|
||||
else if (node.flags & NodeFlags.Const) {
|
||||
grammarErrorOnNode(node, Diagnostics.const_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
|
||||
}
|
||||
}
|
||||
else if (!allowLetAndConstDeclarations(node.parent)) {
|
||||
if (node.flags & NodeFlags.Let) {
|
||||
grammarErrorOnNode(node, Diagnostics.let_declarations_can_only_be_declared_inside_a_block);
|
||||
}
|
||||
else if (node.flags & NodeFlags.Const) {
|
||||
grammarErrorOnNode(node, Diagnostics.const_declarations_can_only_be_declared_inside_a_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function allowLetAndConstDeclarations(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
return false;
|
||||
case SyntaxKind.LabeledStatement:
|
||||
return allowLetAndConstDeclarations(node.parent);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function createProgram(rootNames: string[], options: CompilerOptions, host: CompilerHost): Program {
|
||||
|
|
27
tests/baselines/reference/letDeclarations-es5-1.errors.txt
Normal file
27
tests/baselines/reference/letDeclarations-es5-1.errors.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
tests/cases/compiler/letDeclarations-es5-1.ts(1,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5-1.ts(2,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5-1.ts(3,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5-1.ts(4,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5-1.ts(5,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5-1.ts(6,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
|
||||
|
||||
==== tests/cases/compiler/letDeclarations-es5-1.ts (6 errors) ====
|
||||
let l1;
|
||||
~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l2: number;
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l3, l4, l5 :string, l6;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l7 = false;
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l8: number = 23;
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l9 = 0, l10 :string = "", l11 = null;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
|
@ -1,34 +1,16 @@
|
|||
tests/cases/compiler/letDeclarations-es5.ts(2,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5.ts(3,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5.ts(4,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5.ts(6,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5.ts(7,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5.ts(8,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5.ts(10,8): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
tests/cases/compiler/letDeclarations-es5.ts(12,8): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
|
||||
|
||||
==== tests/cases/compiler/letDeclarations-es5.ts (8 errors) ====
|
||||
==== tests/cases/compiler/letDeclarations-es5.ts (2 errors) ====
|
||||
|
||||
let l1;
|
||||
~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l2: number;
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l3, l4, l5 :string, l6;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
|
||||
let l7 = false;
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l8: number = 23;
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
let l9 = 0, l10 :string = "", l11 = null;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
|
||||
|
||||
for(let l11 in {}) { }
|
||||
~~~~
|
||||
|
|
7
tests/cases/compiler/letDeclarations-es5-1.ts
Normal file
7
tests/cases/compiler/letDeclarations-es5-1.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
// @target: ES5
|
||||
let l1;
|
||||
let l2: number;
|
||||
let l3, l4, l5 :string, l6;
|
||||
let l7 = false;
|
||||
let l8: number = 23;
|
||||
let l9 = 0, l10 :string = "", l11 = null;
|
Loading…
Reference in a new issue