Skip to content

Commit 3174cbc

Browse files
Use union types to make For/ForIn statements simpler.
Conflicts: src/services/syntax/SyntaxGenerator.js.map
1 parent 2288f42 commit 3174cbc

9 files changed

Lines changed: 76 additions & 115 deletions

src/services/syntax/SyntaxGenerator.js

Lines changed: 3 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/services/syntax/SyntaxGenerator.js.map

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/services/syntax/parser.ts

Lines changed: 36 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,61 +1710,46 @@ module TypeScript.Parser {
17101710

17111711
var _currentToken = currentToken();
17121712
var tokenKind = _currentToken.kind;
1713-
if (tokenKind === SyntaxKind.VarKeyword) {
1714-
// for ( var VariableDeclarationListNoIn; Expressionopt ; Expressionopt ) Statement
1713+
1714+
// If we see 'for ( ;' then there is no initializer, and this must be a 'for' statement.
1715+
// If we don't see a semicolon, then parse our a variable declaration or an initializer
1716+
// expression. Both could be hte start of a 'for' or 'for-in' statement. So, after that
1717+
// check to see if we have an 'in' keyword to make the final determination as to what we
1718+
// have.
1719+
1720+
// When trying to parse either a variable declaration or an expression do not allow 'in'
1721+
// to be parsed, as that will actually be consumed by the 'for in' statement production
1722+
// instead. Also, we allow any expression here (even though the grammar only allows for
1723+
// LeftHandSideExpression). We will make sure we actually have a LHS expression in the
1724+
// grammar walker.
1725+
var initializer = tokenKind === SyntaxKind.SemicolonToken
1726+
? undefined
1727+
: tokenKind === SyntaxKind.VarKeyword
1728+
? parseVariableDeclaration(/*allowIn:*/ false)
1729+
: parseExpression(/*allowIn:*/ false);
1730+
1731+
// In order to be a 'for-in' statement, we had to have an initializer of some sort, and
1732+
// we had to actually get an 'in' keyword.
1733+
if (initializer !== undefined && currentToken().kind === SyntaxKind.InKeyword) {
17151734
// for ( var VariableDeclarationNoIn in Expression ) Statement
1716-
return parseForOrForInStatementWithVariableDeclaration(forKeyword, openParenToken);
1717-
}
1718-
else if (tokenKind === SyntaxKind.SemicolonToken) {
1719-
// for ( ; Expressionopt ; Expressionopt ) Statement
1720-
return parseForStatementWithNoVariableDeclarationOrInitializer(forKeyword, openParenToken);
1721-
}
1722-
else {
1723-
// for ( ExpressionNoInopt; Expressionopt ; Expressionopt ) Statement
17241735
// for ( LeftHandSideExpression in Expression ) Statement
1725-
return parseForOrForInStatementWithInitializer(forKeyword, openParenToken);
1736+
return new ForInStatementSyntax(parseNodeData,
1737+
forKeyword, openParenToken, initializer, eatToken(SyntaxKind.InKeyword),
1738+
parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false));
17261739
}
1727-
}
1728-
1729-
function parseForOrForInStatementWithVariableDeclaration(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken): IStatementSyntax {
1730-
// Debug.assert(forKeyword.kind === SyntaxKind.ForKeyword && openParenToken.kind === SyntaxKind.OpenParenToken);
1731-
// Debug.assert(currentToken().kind === SyntaxKind.VarKeyword);
1732-
1733-
// for ( var VariableDeclarationListNoIn; Expressionopt ; Expressionopt ) Statement
1734-
// for ( var VariableDeclarationNoIn in Expression ) Statement
1735-
1736-
var variableDeclaration = parseVariableDeclaration(/*allowIn:*/ false);
1737-
return currentToken().kind === SyntaxKind.InKeyword
1738-
? parseForInStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, variableDeclaration, undefined)
1739-
: parseForStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, variableDeclaration, undefined);
1740-
}
1741-
1742-
function parseForInStatementWithVariableDeclarationOrInitializer(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, initializer: IExpressionSyntax): ForInStatementSyntax {
1743-
// for ( var VariableDeclarationNoIn in Expression ) Statement
1744-
1745-
return new ForInStatementSyntax(parseNodeData,
1746-
forKeyword, openParenToken, variableDeclaration, initializer, eatToken(SyntaxKind.InKeyword),
1747-
parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false));
1748-
}
1749-
1750-
function parseForOrForInStatementWithInitializer(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken): IStatementSyntax {
1751-
// Debug.assert(forKeyword.kind === SyntaxKind.ForKeyword && openParenToken.kind === SyntaxKind.OpenParenToken);
1752-
1753-
// for ( ExpressionNoInopt; Expressionopt ; Expressionopt ) Statement
1754-
// for ( LeftHandSideExpression in Expression ) Statement
1755-
1756-
var initializer = parseExpression(/*allowIn:*/ false);
1757-
return currentToken().kind === SyntaxKind.InKeyword
1758-
? parseForInStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, undefined, initializer)
1759-
: parseForStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, undefined, initializer);
1760-
}
1761-
1762-
function parseForStatementWithNoVariableDeclarationOrInitializer(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken): ForStatementSyntax {
1763-
// Debug.assert(forKeyword.kind === SyntaxKind.ForKeyword && openParenToken.kind === SyntaxKind.OpenParenToken);
1764-
// Debug.assert(currentToken().kind === SyntaxKind.SemicolonToken);
1765-
// for ( ; Expressionopt ; Expressionopt ) Statement
1740+
else {
1741+
// NOTE: From the es5 section on Automatic Semicolon Insertion.
1742+
// a semicolon is never inserted automatically if the semicolon would then ... become
1743+
// one of the two semicolons in the header of a for statement
17661744

1767-
return parseForStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, /*variableDeclaration:*/ undefined, /*initializer:*/ undefined);
1745+
// for (ExpressionNoInopt; Expressionopt ; Expressionopt ) Statement
1746+
// for (var VariableDeclarationListNoIn; Expressionopt; Expressionopt) Statement
1747+
return new ForStatementSyntax(parseNodeData,
1748+
forKeyword, openParenToken, initializer,
1749+
eatToken(SyntaxKind.SemicolonToken), tryParseForStatementCondition(),
1750+
eatToken(SyntaxKind.SemicolonToken), tryParseForStatementIncrementor(),
1751+
eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false));
1752+
}
17681753
}
17691754

17701755
function tryParseForStatementCondition(): IExpressionSyntax {
@@ -1788,18 +1773,6 @@ module TypeScript.Parser {
17881773
return undefined;
17891774
}
17901775

1791-
function parseForStatementWithVariableDeclarationOrInitializer(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, initializer: IExpressionSyntax): ForStatementSyntax {
1792-
// NOTE: From the es5 section on Automatic Semicolon Insertion.
1793-
// a semicolon is never inserted automatically if the semicolon would then ... become
1794-
// one of the two semicolons in the header of a for statement
1795-
1796-
return new ForStatementSyntax(parseNodeData,
1797-
forKeyword, openParenToken, variableDeclaration, initializer,
1798-
eatToken(SyntaxKind.SemicolonToken), tryParseForStatementCondition(),
1799-
eatToken(SyntaxKind.SemicolonToken), tryParseForStatementIncrementor(),
1800-
eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false));
1801-
}
1802-
18031776
function tryEatBreakOrContinueLabel(): ISyntaxToken {
18041777
// If there is no newline after the break keyword, then we can consume an optional
18051778
// identifier.

src/services/syntax/prettyPrinter.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -820,8 +820,7 @@ module TypeScript.PrettyPrinter {
820820
this.appendToken(node.forKeyword);
821821
this.ensureSpace();
822822
this.appendToken(node.openParenToken);
823-
this.appendNode(node.variableDeclaration);
824-
this.appendElement(node.initializer);
823+
visitNodeOrToken(this, node.initializer);
825824
this.appendToken(node.firstSemicolonToken);
826825

827826
if (node.condition) {
@@ -844,12 +843,11 @@ module TypeScript.PrettyPrinter {
844843
this.appendToken(node.forKeyword);
845844
this.ensureSpace();
846845
this.appendToken(node.openParenToken);
847-
this.appendNode(node.variableDeclaration);
848846
this.appendElement(node.left);
849847
this.ensureSpace();
850848
this.appendToken(node.inKeyword);
851849
this.ensureSpace();
852-
this.appendElement(node.expression);
850+
this.appendElement(node.right);
853851
this.appendToken(node.closeParenToken);
854852
this.appendBlockOrStatement(node.statement);
855853
}

src/services/syntax/syntaxGenerator.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -790,8 +790,7 @@ var definitions:ITypeDefinition[] = [
790790
children: [
791791
<any>{ name: 'forKeyword', isToken: true, excludeFromAST: true },
792792
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
793-
<any>{ name: 'variableDeclaration', type: 'VariableDeclarationSyntax', isOptional: true },
794-
<any>{ name: 'initializer', type: 'IExpressionSyntax', isOptional: true },
793+
<any>{ name: 'initializer', type: 'VariableDeclarationSyntax | IExpressionSyntax', isOptional: true },
795794
<any>{ name: 'firstSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
796795
<any>{ name: 'condition', type: 'IExpressionSyntax', isOptional: true },
797796
<any>{ name: 'secondSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
@@ -807,10 +806,9 @@ var definitions:ITypeDefinition[] = [
807806
children: [
808807
<any>{ name: 'forKeyword', isToken: true, excludeFromAST: true },
809808
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
810-
<any>{ name: 'variableDeclaration', type: 'VariableDeclarationSyntax', isOptional: true },
811-
<any>{ name: 'left', type: 'IExpressionSyntax', isOptional: true },
809+
<any>{ name: 'left', type: 'VariableDeclarationSyntax | IExpressionSyntax' },
812810
<any>{ name: 'inKeyword', isToken: true, excludeFromAST: true },
813-
<any>{ name: 'expression', type: 'IExpressionSyntax' },
811+
<any>{ name: 'right', type: 'IExpressionSyntax' },
814812
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
815813
<any>{ name: 'statement', type: 'IStatementSyntax' }
816814
]

src/services/syntax/syntaxInterfaces.generated.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -296,28 +296,26 @@ module TypeScript {
296296
export interface ForStatementSyntax extends ISyntaxNode, IStatementSyntax {
297297
forKeyword: ISyntaxToken;
298298
openParenToken: ISyntaxToken;
299-
variableDeclaration: VariableDeclarationSyntax;
300-
initializer: IExpressionSyntax;
299+
initializer: VariableDeclarationSyntax | IExpressionSyntax;
301300
firstSemicolonToken: ISyntaxToken;
302301
condition: IExpressionSyntax;
303302
secondSemicolonToken: ISyntaxToken;
304303
incrementor: IExpressionSyntax;
305304
closeParenToken: ISyntaxToken;
306305
statement: IStatementSyntax;
307306
}
308-
export interface ForStatementConstructor { new (data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, initializer: IExpressionSyntax, firstSemicolonToken: ISyntaxToken, condition: IExpressionSyntax, secondSemicolonToken: ISyntaxToken, incrementor: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax): ForStatementSyntax }
307+
export interface ForStatementConstructor { new (data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, initializer: VariableDeclarationSyntax | IExpressionSyntax, firstSemicolonToken: ISyntaxToken, condition: IExpressionSyntax, secondSemicolonToken: ISyntaxToken, incrementor: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax): ForStatementSyntax }
309308

310309
export interface ForInStatementSyntax extends ISyntaxNode, IStatementSyntax {
311310
forKeyword: ISyntaxToken;
312311
openParenToken: ISyntaxToken;
313-
variableDeclaration: VariableDeclarationSyntax;
314-
left: IExpressionSyntax;
312+
left: VariableDeclarationSyntax | IExpressionSyntax;
315313
inKeyword: ISyntaxToken;
316-
expression: IExpressionSyntax;
314+
right: IExpressionSyntax;
317315
closeParenToken: ISyntaxToken;
318316
statement: IStatementSyntax;
319317
}
320-
export interface ForInStatementConstructor { new (data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, left: IExpressionSyntax, inKeyword: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax): ForInStatementSyntax }
318+
export interface ForInStatementConstructor { new (data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, left: VariableDeclarationSyntax | IExpressionSyntax, inKeyword: ISyntaxToken, right: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax): ForInStatementSyntax }
321319

322320
export interface EmptyStatementSyntax extends ISyntaxNode, IStatementSyntax {
323321
semicolonToken: ISyntaxToken;

0 commit comments

Comments
 (0)