Skip to content

Commit

Permalink
Merge pull request #41639 from CyrusNajmabadi/blockStackFrames
Browse files Browse the repository at this point in the history
Increase the amount of recursive parsing calls for statements+blocks.
  • Loading branch information
msftbot[bot] committed Feb 13, 2020
2 parents b73f69c + 29793af commit 76bdeb8
Showing 1 changed file with 49 additions and 56 deletions.
105 changes: 49 additions & 56 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Expand Up @@ -2450,7 +2450,7 @@ private DestructorDeclarationSyntax ParseDestructorDeclaration(SyntaxList<Attrib

if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken)
{
blockBody = this.ParseBlock(isMethodBody: true);
blockBody = this.ParseMethodOrAccessorBodyBlock(isAccessorBody: false);
}

if (this.CurrentToken.Kind == SyntaxKind.EqualsGreaterThanToken)
Expand All @@ -2477,25 +2477,6 @@ private DestructorDeclarationSyntax ParseDestructorDeclaration(SyntaxList<Attrib
}
}

private void ParseBodyOrSemicolon(out BlockSyntax body, out SyntaxToken semicolon)
{
if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken)
{
body = this.ParseBlock(isMethodBody: true);

semicolon = null;
if (this.CurrentToken.Kind == SyntaxKind.SemicolonToken)
{
semicolon = this.EatTokenWithPrejudice(ErrorCode.ERR_UnexpectedSemicolon);
}
}
else
{
semicolon = this.EatToken(SyntaxKind.SemicolonToken);
body = null;
}
}

private bool IsEndOfTypeParameterList()
{
if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken)
Expand Down Expand Up @@ -3305,7 +3286,7 @@ private AccessorDeclarationSyntax ParseAccessorDeclaration(bool isEvent)
{
if (!IsTerminator())
{
blockBody = this.ParseBlock(isMethodBody: true, isAccessorBody: true);
blockBody = this.ParseMethodOrAccessorBodyBlock(isAccessorBody: true);
}
else
{
Expand Down Expand Up @@ -6943,54 +6924,66 @@ private bool IsPossibleNewExpression()
return null;
}

// If "isMethodBody" is true, then this is the immediate body of a method/accessor.
// In this case, we create a many-child list if the body is not a small single statement.
// This then allows a "with many weak children" red node when the red node is created.
// If "isAccessorBody" is true, then we produce a special diagnostic if the open brace is
// missing. Also, "isMethodBody" must be true.
private BlockSyntax ParseBlock(bool isMethodBody = false, bool isAccessorBody = false)
/// <summary>
/// Used to parse the block-body for a method or accessor. For blocks that appear *inside*
/// method bodies, call <see cref="ParseBlock"/>.
/// </summary>
/// <param name="isAccessorBody">If is true, then we produce a special diagnostic if the
/// open brace is missing.</param>
private BlockSyntax ParseMethodOrAccessorBodyBlock(bool isAccessorBody)
{
// Check again for incremental re-use, since ParseBlock is called from a bunch of places
// other than ParseStatementCore()
// Check again for incremental re-use. This way if a method signature is edited we can
// still quickly re-sync on the body.
if (this.IsIncrementalAndFactoryContextMatches && this.CurrentNodeKind == SyntaxKind.Block)
{
return (BlockSyntax)this.EatNode();
}

// There's a special error code for a missing token after an accessor keyword
var openBrace = isAccessorBody && this.CurrentToken.Kind != SyntaxKind.OpenBraceToken
CSharpSyntaxNode openBrace = isAccessorBody && this.CurrentToken.Kind != SyntaxKind.OpenBraceToken
? this.AddError(
SyntaxFactory.MissingToken(SyntaxKind.OpenBraceToken),
IsFeatureEnabled(MessageID.IDS_FeatureExpressionBodiedAccessor)
? ErrorCode.ERR_SemiOrLBraceOrArrowExpected
: ErrorCode.ERR_SemiOrLBraceExpected)
? ErrorCode.ERR_SemiOrLBraceOrArrowExpected
: ErrorCode.ERR_SemiOrLBraceExpected)
: this.EatToken(SyntaxKind.OpenBraceToken);

var statements = _pool.Allocate<StatementSyntax>();
try
{
CSharpSyntaxNode tmp = openBrace;
this.ParseStatements(ref tmp, statements, stopOnSwitchSections: false);
openBrace = (SyntaxToken)tmp;
var closeBrace = this.EatToken(SyntaxKind.CloseBraceToken);
this.ParseStatements(ref openBrace, statements, stopOnSwitchSections: false);

SyntaxList<StatementSyntax> statementList;
if (isMethodBody && IsLargeEnoughNonEmptyStatementList(statements))
{
// Force creation a many-children list, even if only 1, 2, or 3 elements in the statement list.
statementList = new SyntaxList<StatementSyntax>(SyntaxList.List(((SyntaxListBuilder)statements).ToArray()));
}
else
{
statementList = statements;
}
var block = _syntaxFactory.Block(
(SyntaxToken)openBrace,
// Force creation a many-children list, even if only 1, 2, or 3 elements in the statement list.
IsLargeEnoughNonEmptyStatementList(statements)
? new SyntaxList<StatementSyntax>(SyntaxList.List(((SyntaxListBuilder)statements).ToArray()))
: statements,
this.EatToken(SyntaxKind.CloseBraceToken));

return _syntaxFactory.Block(openBrace, statementList, closeBrace);
}
finally
{
_pool.Free(statements);
}
_pool.Free(statements);
return block;
}

/// <summary>
/// Used to parse normal blocks that appear inside method bodies. For the top level block
/// of a method/accessor use <see cref="ParseMethodOrAccessorBodyBlock"/>.
/// </summary>
private BlockSyntax ParseBlock()
{
// Check again for incremental re-use, since ParseBlock is called from a bunch of places
// other than ParseStatementCore()
if (this.IsIncrementalAndFactoryContextMatches && this.CurrentNodeKind == SyntaxKind.Block)
return (BlockSyntax)this.EatNode();

CSharpSyntaxNode openBrace = this.EatToken(SyntaxKind.OpenBraceToken);

var statements = _pool.Allocate<StatementSyntax>();
this.ParseStatements(ref openBrace, statements, stopOnSwitchSections: false);

var block = _syntaxFactory.Block(
(SyntaxToken)openBrace,
statements,
this.EatToken(SyntaxKind.CloseBraceToken));

_pool.Free(statements);
return block;
}

// Is this statement list non-empty, and large enough to make using weak children beneficial?
Expand Down

0 comments on commit 76bdeb8

Please sign in to comment.