Skip to content

Commit

Permalink
Merge pull request #378 from huntercfreeman/optimizations
Browse files Browse the repository at this point in the history
Optimizations
  • Loading branch information
Luthetus authored Dec 16, 2024
2 parents 4fce43a + bf12308 commit ed78f3d
Show file tree
Hide file tree
Showing 15 changed files with 312 additions and 207 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,7 @@ public IExpressionNode EmptyMergeToken(
return emptyExpressionNode;
case SyntaxKind.InTokenKeyword:
case SyntaxKind.RefTokenKeyword:
case SyntaxKind.ParamsTokenKeyword:
return emptyExpressionNode;
case SyntaxKind.OpenAngleBracketToken:
var genericParametersListingNode = new GenericParametersListingNode(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,15 @@ public bool TryAddReturnTypeClauseNodeByScope(

goto default;
}
case SyntaxKind.ConstructorDefinitionNode:
{
var constructorDefinitionNode = (ConstructorDefinitionNode)syntaxNode;

if (constructorDefinitionNode.FunctionIdentifier.ConstructorWasInvoked)
return (constructorDefinitionNode.FunctionIdentifier.TextSpan.StartingIndexInclusive, constructorDefinitionNode.FunctionIdentifier.TextSpan.EndingIndexExclusive);

goto default;
}
case SyntaxKind.VariableDeclarationNode:
{
var variableDeclarationNode = (VariableDeclarationNode)syntaxNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ public static FunctionArgumentsListingNode HandleFunctionArguments(CSharpCompila
}
else if (!corruptState)
{
if (parserModel.TokenWalker.Current.SyntaxKind == SyntaxKind.OutTokenKeyword ||
parserModel.TokenWalker.Current.SyntaxKind == SyntaxKind.InTokenKeyword ||
parserModel.TokenWalker.Current.SyntaxKind == SyntaxKind.RefTokenKeyword ||
parserModel.TokenWalker.Current.SyntaxKind == SyntaxKind.ParamsTokenKeyword)
{
_ = parserModel.TokenWalker.Consume();
}

var tokenIndexOriginal = parserModel.TokenWalker.Index;
var successTypeClauseNode = ParseOthers.TryParseExpression(SyntaxKind.TypeClauseNode, compilationUnit, ref parserModel, out var typeClauseNode);
var successName = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,42 @@ public static void StartStatement_Expression(CSharpCompilationUnit compilationUn
/// In order to "short circut" or "force exit" from the expression code back to the statement code,
/// if the root primary expression is not equal to the parserModel.ForceParseExpressionSyntaxKind
/// then stop.
///
/// ------------------------------
/// Retrospective comment (2024-12-16):
/// It appears that the 'SyntaxKind? syntaxKind'
/// argument is nullable in order to permit
/// usage of 'parserModel.ForceParseExpressionInitialPrimaryExpression'
/// without specifying a specific syntax kind?
///
/// The use case:
/// FunctionInvocationNode as a statement
/// will currently erroneously parse as a TypeClauseNode.
///
/// But, once the statement code receives the 'TypeClauseNode' result
/// from 'TryParseExpression', the next ISyntaxToken
/// is OpenParenthesisToken.
///
/// Therefore, it is obvious at this point that we really wanted
/// to parse a function invocation node.
///
/// But, if there is any code that comes after the function invocation,
/// and prior to the statement delimiter.
///
/// Then a FunctionInvocationNode would not sufficiently represent the statement-expression.
///
/// i.e.: MyMethod() + 2;
///
/// So, I cannot 'TryParseExpression' for a SyntaxKind.FunctionInvocationNode for this reason.
///
/// But, I need to initialize the 'ParseExpression' method with the 'TypeClauseNode'
/// (the 'TypeClauseNode' is in reality the function identifier / generic arguments to the function if there are any).
///
/// Then, the 'ParseExpression(...)' code can see that there is a 'TypeClauseNode' merging with an OpenParenthesisToken,
/// and that the only meaning this can have is function invocation.
///
/// At that point, go on to move the 'TypeClauseNode' to be a function identifier, and the
/// generic arguments for the function invocation, and go on from there.
/// </summary>
public static bool TryParseExpression(SyntaxKind? syntaxKind, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel, out IExpressionNode expressionNode)
{
Expand All @@ -94,7 +130,10 @@ public static bool TryParseExpression(SyntaxKind? syntaxKind, CSharpCompilationU
Console.WriteLine($"try => {expressionNode.SyntaxKind}\n");
#endif

return parserModel.TryParseExpressionSyntaxKindList.Contains(expressionNode.SyntaxKind);
if (parserModel.TryParseExpressionSyntaxKindList.Count == 0)
return true;
else
return parserModel.TryParseExpressionSyntaxKindList.Contains(expressionNode.SyntaxKind);
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public static void ParseIdentifierToken(CSharpCompilationUnit compilationUnit, r
parserModel.TryParseExpressionSyntaxKindList.Add(SyntaxKind.VariableReferenceNode);
parserModel.TryParseExpressionSyntaxKindList.Add(SyntaxKind.ConstructorInvocationExpressionNode);

if (parserModel.CurrentCodeBlockBuilder.CodeBlockOwner is not null &&
parserModel.CurrentCodeBlockBuilder.CodeBlockOwner.SyntaxKind != SyntaxKind.TypeDefinitionNode)
if ((parserModel.CurrentCodeBlockBuilder.CodeBlockOwner?.SyntaxKind ?? SyntaxKind.EmptyNode) !=
SyntaxKind.TypeDefinitionNode)
{
// There is a syntax conflict between a ConstructorDefinitionNode and a FunctionInvocationNode.
//
Expand All @@ -57,7 +57,7 @@ public static void ParseIdentifierToken(CSharpCompilationUnit compilationUnit, r

switch (expressionNode.SyntaxKind)
{
case SyntaxKind.TypeClauseNode:
case SyntaxKind.TypeClauseNode:
MoveToHandleTypeClauseNode(originalTokenIndex, (TypeClauseNode)expressionNode, compilationUnit, ref parserModel);
return;
case SyntaxKind.VariableDeclarationNode:
Expand Down Expand Up @@ -413,12 +413,10 @@ public static void ParseStatementDelimiterToken(StatementDelimiterToken statemen
{
if (parserModel.SyntaxStack.TryPeek(out var syntax) && syntax.SyntaxKind == SyntaxKind.NamespaceStatementNode)
{
var closureCurrentCompilationUnitBuilder = parserModel.CurrentCodeBlockBuilder;
ICodeBlockOwner? nextCodeBlockOwner = null;
var namespaceStatementNode = (NamespaceStatementNode)parserModel.SyntaxStack.Pop();

ICodeBlockOwner? nextCodeBlockOwner = namespaceStatementNode;
TypeClauseNode? scopeReturnTypeClauseNode = null;

var namespaceStatementNode = (NamespaceStatementNode)parserModel.SyntaxStack.Pop();
nextCodeBlockOwner = namespaceStatementNode;

namespaceStatementNode.SetStatementDelimiterToken(statementDelimiterToken, parserModel.DiagnosticBag, parserModel.TokenWalker);

Expand All @@ -440,15 +438,12 @@ public static void ParseStatementDelimiterToken(StatementDelimiterToken statemen
var pendingChild = parserModel.CurrentCodeBlockBuilder.InnerPendingCodeBlockOwner;

compilationUnit.Binder.OpenScope(pendingChild, CSharpFacts.Types.Void.ToTypeClause(), statementDelimiterToken.TextSpan, compilationUnit);
parserModel.CurrentCodeBlockBuilder = new(parserModel.CurrentCodeBlockBuilder, pendingChild);

parserModel.CurrentCodeBlockBuilder = new(parent: parserModel.CurrentCodeBlockBuilder, codeBlockOwner: pendingChild);
pendingChild.SetStatementDelimiterToken(statementDelimiterToken, parserModel.DiagnosticBag, parserModel.TokenWalker);
compilationUnit.Binder.OnBoundScopeCreatedAndSetAsCurrent(pendingChild, compilationUnit);

compilationUnit.Binder.CloseScope(statementDelimiterToken.TextSpan, compilationUnit, ref parserModel);

if (parserModel.CurrentCodeBlockBuilder.Parent is not null)
parserModel.CurrentCodeBlockBuilder = parserModel.CurrentCodeBlockBuilder.Parent;

parserModel.CurrentCodeBlockBuilder.InnerPendingCodeBlockOwner = null;
}
}

Expand Down
2 changes: 1 addition & 1 deletion Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>0.9.7.7</Version>
<Version>0.9.7.8</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,30 @@
Recent Changes:
<div>
<div>
<div>v <em class="luth_em">0.9.7.7 </em> (WIP_DATE)</div>
<div>v <em class="luth_em">0.9.7.8 </em> (2024-12-16)</div>
<ul>
<li>
Show function arguments in the tooltip.
</li>
<li>
Fix: single statement bodies 'if (true) aaa;'. This was breaking the scope logic.
</li>
<li>
Fix: function invocation as a statement.
</li>
<li>
Invoke 'ResourceWasModified(...)' first open of file. This permits consistent go-to definition resolution cross file.
</li>
<li>
Out, in, ref, params in function arguments listing (maybe in future change to check for any keyword?).
</li>
<li>
GetNodePositionIndices(...) for ConstructorDefinitionNode so the tooltip works.
</li>
</ul>
</div>
<div>
<div>v <em class="luth_em">0.9.7.7 </em> (2024-12-15)</div>
<ul>
<li>Reduce object allocations when parsing.</li>
<li>Reduce memory usage from parsing by 25%.</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

string? methodName;
GenericParametersListingNode? genericParametersListingNode;
FunctionArgumentsListingNode? functionArgumentsListingNode;
bool isConstructorInvocation = false;

if (syntaxViewModelLocal.DefinitionNode is null && syntaxViewModelLocal.TargetNode is null && syntaxViewModelLocal.TargetSymbol is null)
Expand All @@ -23,6 +24,7 @@
returnTypeClauseNodeText = null;
methodName = null;
genericParametersListingNode = null;
functionArgumentsListingNode = null;
}
else if (syntaxViewModelLocal.DefinitionNode is not null &&
(syntaxViewModelLocal.DefinitionNode.SyntaxKind == SyntaxKind.FunctionDefinitionNode ||
Expand All @@ -37,6 +39,7 @@
returnTypeClauseNodeText = null;
methodName = functionDefinitionNode.FunctionIdentifierToken.TextSpan.GetText();
genericParametersListingNode = functionDefinitionNode.GenericArgumentsListingNode;
functionArgumentsListingNode = functionDefinitionNode.FunctionArgumentsListingNode;
}
else if (syntaxViewModelLocal.DefinitionNode.SyntaxKind == SyntaxKind.ConstructorDefinitionNode)
{
Expand All @@ -45,13 +48,15 @@
returnTypeClauseNodeText = null;
methodName = null;
genericParametersListingNode = null;
functionArgumentsListingNode = constructorDefinitionNode.FunctionArgumentsListingNode;
}
else
{
returnTypeClauseNode = null;
returnTypeClauseNodeText = null;
methodName = "unknown syntax";
genericParametersListingNode = null;
functionArgumentsListingNode = null;
}
}
else if (syntaxViewModelLocal.TargetNode is not null &&
Expand All @@ -67,6 +72,7 @@
returnTypeClauseNodeText = null;
methodName = functionInvocationNode.FunctionInvocationIdentifierToken.TextSpan.GetText();
genericParametersListingNode = functionInvocationNode.GenericParametersListingNode;
functionArgumentsListingNode = null;
}
else if (syntaxViewModelLocal.TargetNode.SyntaxKind == SyntaxKind.ConstructorInvocationExpressionNode)
{
Expand All @@ -75,13 +81,15 @@
returnTypeClauseNodeText = null;
methodName = null;
genericParametersListingNode = null;
functionArgumentsListingNode = null;
}
else
{
returnTypeClauseNode = null;
returnTypeClauseNodeText = null;
methodName = "unknown syntax";
genericParametersListingNode = null;
functionArgumentsListingNode = null;
}
}
else if (syntaxViewModelLocal.TargetSymbol is not null &&
Expand All @@ -96,20 +104,23 @@
returnTypeClauseNodeText = null;
methodName = syntaxViewModelLocal.TargetSymbol.TextSpan.GetText();
genericParametersListingNode = null;
functionArgumentsListingNode = null;
}
else if (syntaxViewModelLocal.TargetSymbol.SyntaxKind == SyntaxKind.ConstructorSymbol)
{
returnTypeClauseNode = null;
returnTypeClauseNodeText = syntaxViewModelLocal.TargetSymbol.TextSpan.GetText();
methodName = null;
genericParametersListingNode = null;
functionArgumentsListingNode = null;
}
else
{
returnTypeClauseNode = null;
returnTypeClauseNodeText = null;
methodName = null;
genericParametersListingNode = null;
functionArgumentsListingNode = null;
}
}
else
Expand All @@ -119,6 +130,7 @@
returnTypeClauseNodeText = null;
methodName = null;
genericParametersListingNode = null;
functionArgumentsListingNode = null;
}
}

Expand Down Expand Up @@ -171,5 +183,30 @@
<GenericSyntaxDisplay SyntaxViewModel="syntaxViewModel" />
}

()
@if (functionArgumentsListingNode is null)
{
<text>()</text>
}
else
{
<text>(</text>
@for (int badIndex = 0; badIndex < functionArgumentsListingNode.FunctionArgumentEntryNodeList.Count; badIndex++)
{
var index = badIndex;
var argumentEntryNode = functionArgumentsListingNode.FunctionArgumentEntryNodeList[index];

var syntaxViewModel = new SyntaxViewModel(
targetSymbol: null,
targetNode: argumentEntryNode.VariableDeclarationNode,
definitionNode: argumentEntryNode.VariableDeclarationNode,
depth: syntaxViewModelLocal.Depth + 1);
<VariableSyntaxDisplay SyntaxViewModel="syntaxViewModel"/>

if (badIndex < functionArgumentsListingNode.FunctionArgumentEntryNodeList.Count - 1)
{
<text>, </text>
}
}
<text>)</text>
}
</span>
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,27 @@ public void IncrementLinks()

if (modelModifier is null)
return Task.CompletedTask;


// If this 'ApplySyntaxHighlighting(...)' isn't redundantly invoked prior to
// the upcoming 'ResourceWasModified(...)' invocation,
// then there is an obnoxious "flicker" upon opening a file for the first time.
//
// This is because it initially opens with 'plain text' syntax highlighting
// for all the text.
//
// Then very soon after it gets the correct syntax highlighting applied.
// The issue is specifically how quickly it gets the correct syntax highlighting.
//
// It is the same issue as putting a 'loading...' icon or text
// for an asynchronous event, but that event finishes in sub 200ms so the user
// sees a "flicker" of the 'loading...' text and it just is disorienting to see.
editContext.TextEditorService.ModelApi.ApplySyntaxHighlighting(
editContext,
modelModifier);

if (modelModifier.CompilerService is not null)
modelModifier.CompilerService.ResourceWasModified(_resourceUri, Array.Empty<TextEditorTextSpan>());

return Task.CompletedTask;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,15 @@ public Test(string sourceText)
{
SourceText = sourceText;
ResourceUri = new ResourceUri("./unitTesting.txt");
Lexer = new CSharpLexer(ResourceUri, SourceText);
Lexer.Lex();
Parser = new CSharpParser(Lexer);
CompilationUnit = Parser.Parse();
CompilationUnit.LexerOutput = CSharpLexer.Lex(ResourceUri, SourceText);
CSharpParser.Parse(CompilationUnit);
}

public string SourceText { get; set; }
public ResourceUri ResourceUri { get; set; }
public CSharpLexer Lexer { get; set; }
public CSharpParser Parser { get; set; }
public CompilationUnit CompilationUnit { get; set; }
public CSharpLexerOutput LexerOutput { get; set; }
public IBinder Binder => CompilationUnit.Binder;
public CSharpCompilationUnit CompilationUnit { get; set; }
}

[Fact]
Expand All @@ -49,7 +47,7 @@ public void TypeDefinitionNode_IdentifierToken()
var cSharpResource = new CSharpResource(test.ResourceUri, null);
cSharpResource.CompilationUnit = test.CompilationUnit;

var node = binder.GetSyntaxNode(13, test.ResourceUri, cSharpResource);
var node = binder.GetSyntaxNode(test.CompilationUnit, 13, test.ResourceUri, cSharpResource);

Assert.NotNull(node);
Assert.Equal(SyntaxKind.TypeDefinitionNode, node.SyntaxKind);
Expand All @@ -68,7 +66,7 @@ public void FunctionDefinitionNode_IdentifierToken()
var cSharpResource = new CSharpResource(test.ResourceUri, null);
cSharpResource.CompilationUnit = test.CompilationUnit;

var node = binder.GetSyntaxNode(12, test.ResourceUri, cSharpResource);
var node = binder.GetSyntaxNode(test.CompilationUnit, 12, test.ResourceUri, cSharpResource);

Assert.NotNull(node);
Assert.Equal(SyntaxKind.FunctionDefinitionNode, node.SyntaxKind);
Expand Down Expand Up @@ -96,7 +94,7 @@ public class BackgroundTask : IBackgroundTask
var cSharpResource = new CSharpResource(test.ResourceUri, null);
cSharpResource.CompilationUnit = test.CompilationUnit;

var node = binder.GetSyntaxNode(119, test.ResourceUri, cSharpResource);
var node = binder.GetSyntaxNode(test.CompilationUnit, 119, test.ResourceUri, cSharpResource);

Assert.NotNull(node);
Assert.Equal(SyntaxKind.TypeDefinitionNode, node.SyntaxKind);
Expand Down
Loading

0 comments on commit ed78f3d

Please sign in to comment.