From e05b42dce4d74d3b0c03ca41f1c4e53286fdaa40 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:14:01 -0500 Subject: [PATCH 01/14] Update version --- Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj | 2 +- .../Shareds/Displays/Internals/IdeInfoDisplay.razor | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj b/Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj index 84fbf8cf7..fe20ed7fa 100644 --- a/Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj +++ b/Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - 0.9.7.10 + 0.9.7.11 diff --git a/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor b/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor index fcc354850..66a81d389 100644 --- a/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor +++ b/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor @@ -172,6 +172,14 @@ Recent Changes: + v 0.9.7.11 (WIP_DESCRIPTION) + + + WIP_DESCRIPTION + + + + v 0.9.7.10 (2024-12-18) From c6dbf0fa7c843ed86c46993cf8217691226b4227 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:51:49 -0500 Subject: [PATCH 02/14] || parserModel.TokenWalker.IsEof --- .../BinderCase/CSharpBinder.Expressions.cs | 38 ++++++++++------ .../ParserCase/Internals/ParseOthers.cs | 17 ++++++- .../CSharp/ParserCase/Internals/UtilityApi.cs | 5 +++ .../Parsers/ExpressionAsStatementTests.cs | 44 +++++++++++++++++++ 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 1036d1990..8fd7f54ae 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -52,6 +52,9 @@ public IExpressionNode AnyMergeToken( return EmptyExpressionNode.EmptyFollowsMemberAccessToken; } + if (UtilityApi.IsBinaryOperatorSyntaxKind(token.SyntaxKind)) + return HandleBinaryOperator(expressionPrimary, token, compilationUnit, ref parserModel); + switch (expressionPrimary.SyntaxKind) { case SyntaxKind.EmptyExpressionNode: @@ -136,6 +139,27 @@ public IExpressionNode AnyMergeExpression( return new BadExpressionNode(CSharpFacts.Types.Void.ToTypeClause(), expressionPrimary, expressionSecondary); }; } + + public IExpressionNode HandleBinaryOperator( + IExpressionNode expressionPrimary, ISyntaxToken token, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) + { + if (expressionPrimary.SyntaxKind == SyntaxKind.BinaryExpressionNode) + { + var precedencePrimary = UtilityApi.GetOperatorPrecedence(expressionPrimary.SyntaxKind); + var precedenceSecondary = UtilityApi.GetOperatorPrecedence(token.SyntaxKind); + + if (precedenceSecondary > precedencePrimary) + { + // TODO: Rotate the nodes? + } + } + + var typeClauseNode = expressionPrimary.ResultTypeClauseNode; + var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); + var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); + parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, binaryExpressionNode)); + return EmptyExpressionNode.Empty; + } public IExpressionNode AmbiguousIdentifierMergeToken( AmbiguousIdentifierExpressionNode ambiguousIdentifierExpressionNode, ISyntaxToken token, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) @@ -1179,19 +1203,7 @@ public IExpressionNode LambdaMergeExpression( public IExpressionNode LiteralMergeToken( LiteralExpressionNode literalExpressionNode, ISyntaxToken token, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) { - switch (token.SyntaxKind) - { - case SyntaxKind.PlusToken: - case SyntaxKind.MinusToken: - case SyntaxKind.StarToken: - case SyntaxKind.DivisionToken: - case SyntaxKind.EqualsEqualsToken: - var typeClauseNode = literalExpressionNode.ResultTypeClauseNode; - var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); - return new BinaryExpressionNode(literalExpressionNode, binaryOperatorNode); - default: - return new BadExpressionNode(CSharpFacts.Types.Void.ToTypeClause(), literalExpressionNode, token); - } + return new BadExpressionNode(CSharpFacts.Types.Void.ToTypeClause(), literalExpressionNode, token); } public IExpressionNode ParenthesizedMergeToken( diff --git a/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseOthers.cs b/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseOthers.cs index 0484f640e..d06926c88 100644 --- a/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseOthers.cs +++ b/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseOthers.cs @@ -180,7 +180,7 @@ public static IExpressionNode ParseExpression(CSharpCompilationUnit compilationU var indexTokenRoot = parserModel.TokenWalker.Index; var expressionPrimaryPreviousRoot = expressionPrimary; - while (!parserModel.TokenWalker.IsEof) + while (true) { #if DEBUG WriteExpressionList(parserModel.ExpressionList); @@ -208,7 +208,19 @@ public static IExpressionNode ParseExpression(CSharpCompilationUnit compilationU } } - if (forceExit) // delimiterExpressionTuple.ExpressionNode is null + // The while loop used to be while (!parserModel.TokenWalker.IsEof) + // This caused an issue where 'BubbleUpParseExpression(...)' would not run + // if the end of file was reached. + // + // Given how this parser is written, adding 'SyntaxKind.EndOfFile' to 'parserModel.ExpressionList' + // would follow the pattern of how 'SyntaxKind.StatementDelimiterToken' is written. + // + // But, the while (true) loop makes me extremely uncomfortable. + // + // So I added '|| parserModel.TokenWalker.IsEof' here. + // + // If upon further inspection on way or the other is deemed safe then this redundancy can be removed. + if (forceExit || parserModel.TokenWalker.IsEof) // delimiterExpressionTuple.ExpressionNode is null { expressionPrimary = BubbleUpParseExpression(0, expressionPrimary, compilationUnit, ref parserModel); break; @@ -292,6 +304,7 @@ public static IExpressionNode ParseExpression(CSharpCompilationUnit compilationU // It is vital that this 'clear' and 'add' are done in a way that permits an invoker of the 'ParseExpression' method to 'add' a similar 'forceExit' delimiter // Example: 'parserModel.ExpressionList.Add((SyntaxKind.CloseParenthesisToken, null));' parserModel.ExpressionList.Clear(); + parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, null)); parserModel.ExpressionList.Add((SyntaxKind.StatementDelimiterToken, null)); if (expressionPrimary.SyntaxKind == SyntaxKind.AmbiguousIdentifierExpressionNode) diff --git a/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/UtilityApi.cs b/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/UtilityApi.cs index a06d47b62..53ea93f30 100644 --- a/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/UtilityApi.cs +++ b/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/UtilityApi.cs @@ -81,6 +81,11 @@ public static bool IsBinaryOperatorSyntaxKind(SyntaxKind syntaxKind) case SyntaxKind.MinusToken: case SyntaxKind.StarToken: case SyntaxKind.DivisionToken: + case SyntaxKind.EqualsToken: + case SyntaxKind.EqualsEqualsToken: + case SyntaxKind.AmpersandAmpersandToken: + case SyntaxKind.PipePipeToken: + case SyntaxKind.QuestionMarkQuestionMarkToken: return true; default: return false; diff --git a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs index 8a0894f59..8ee8d4ebf 100644 --- a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs +++ b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs @@ -77,6 +77,50 @@ public void Numeric_Add_BinaryExpressionNode() Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); } + /// + /// When encountering a binary operator, + /// change control from the expressionPrimary to the binary operator making the decisions. + /// + /// "Push" the binary expression node onto the ExpressionList with an EndOfFileToken delimiter. + /// + /// Then return an EmptyExpressionNode. + /// + /// Whatever the EmptyExpressionNode becomes will then eventually bubble back up to + /// be used as the right operand. + /// + /// This is being said in reference to how things currently are erroneously done. + /// In which a BinaryExpressionNode explicitly is looking for certain SyntaxKind. + /// + /// Checking the SyntaxKind is fine for binding whether there is a syntax error due + /// to an operator not being defined for various operands. + /// + /// But in terms of the parsing of an expression, it needs to just start a fresh EmptyExpressionNode + /// and grab the right operand that way. + /// + [Fact] + public void Numeric_Add_BinaryExpressionNode_Number_FunctionInvocation() + { + var test = new Test(@"1 + SomeMethod()"); + var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; + + var binaryExpressionNode = (BinaryExpressionNode)topCodeBlock.GetChildList().Single(); + var textTypeClause = "int"; + + var leftLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.LeftExpressionNode; + Assert.Equal(textTypeClause, leftLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + var binaryOperatorNode = binaryExpressionNode.BinaryOperatorNode; + Assert.Equal(textTypeClause, binaryOperatorNode.LeftOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + //public ISyntaxToken binaryOperatorNode.OperatorToken { get; } + Assert.Equal(textTypeClause, binaryOperatorNode.RightOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; + Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + [Fact] public void Numeric_Add_BinaryExpressionNode_More() { From 304cda369cc819b560e8f856485817cca8ffcac3 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:19:42 -0500 Subject: [PATCH 03/14] Numeric_Add_BinaryExpressionNode_Number_FunctionInvocation --- .../CSharp/BinderCase/CSharpBinder.Expressions.cs | 14 ++++++++++++++ .../CSharp/ParserCase/Internals/ParseOthers.cs | 4 ++-- .../Parsers/ExpressionAsStatementTests.cs | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 8fd7f54ae..7f6dde9f1 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -109,6 +109,8 @@ public IExpressionNode AnyMergeExpression( switch (expressionPrimary.SyntaxKind) { + case SyntaxKind.BinaryExpressionNode: + return BinaryMergeExpression((BinaryExpressionNode)expressionPrimary, expressionSecondary, compilationUnit, ref parserModel); case SyntaxKind.ParenthesizedExpressionNode: return ParenthesizedMergeExpression((ParenthesizedExpressionNode)expressionPrimary, expressionSecondary, compilationUnit, ref parserModel); case SyntaxKind.CommaSeparatedExpressionNode: @@ -496,6 +498,18 @@ public IExpressionNode BinaryMergeToken( } } + public IExpressionNode BinaryMergeExpression( + BinaryExpressionNode binaryExpressionNode, IExpressionNode expressionSecondary, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) + { + if (binaryExpressionNode.RightExpressionNode.SyntaxKind == SyntaxKind.EmptyExpressionNode) + { + binaryExpressionNode.SetRightExpressionNode(expressionSecondary); + return binaryExpressionNode; + } + + return new BadExpressionNode(CSharpFacts.Types.Void.ToTypeClause(), binaryExpressionNode, expressionSecondary); + } + public IExpressionNode CommaSeparatedMergeToken( CommaSeparatedExpressionNode commaSeparatedExpressionNode, ISyntaxToken token, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) { diff --git a/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseOthers.cs b/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseOthers.cs index d06926c88..ddb1fdf7c 100644 --- a/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseOthers.cs +++ b/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseOthers.cs @@ -208,14 +208,14 @@ public static IExpressionNode ParseExpression(CSharpCompilationUnit compilationU } } - // The while loop used to be while (!parserModel.TokenWalker.IsEof) + // The while loop used to be 'while (!parserModel.TokenWalker.IsEof)' // This caused an issue where 'BubbleUpParseExpression(...)' would not run // if the end of file was reached. // // Given how this parser is written, adding 'SyntaxKind.EndOfFile' to 'parserModel.ExpressionList' // would follow the pattern of how 'SyntaxKind.StatementDelimiterToken' is written. // - // But, the while (true) loop makes me extremely uncomfortable. + // But, the 'while (true)' loop makes me extremely uncomfortable. // // So I added '|| parserModel.TokenWalker.IsEof' here. // diff --git a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs index 8ee8d4ebf..c0467370c 100644 --- a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs +++ b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs @@ -115,8 +115,8 @@ public void Numeric_Add_BinaryExpressionNode_Number_FunctionInvocation() Assert.Equal(textTypeClause, binaryOperatorNode.RightOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); Assert.Equal(textTypeClause, binaryOperatorNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); - var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; - Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + var rightFunctionInvocationNode = (FunctionInvocationNode)binaryExpressionNode.RightExpressionNode; + // Assert.Equal(textTypeClause, rightFunctionInvocationNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); } From 942d47cf201f00763954566fe48ea12d554e789a Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Thu, 19 Dec 2024 19:32:30 -0500 Subject: [PATCH 04/14] 1 + 1 + 1 --- .../BinderCase/CSharpBinder.Expressions.cs | 114 ++++++++++++++++-- .../Parsers/ExpressionAsStatementTests.cs | 3 +- 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 7f6dde9f1..a6a2fc441 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -145,22 +145,83 @@ public IExpressionNode AnyMergeExpression( public IExpressionNode HandleBinaryOperator( IExpressionNode expressionPrimary, ISyntaxToken token, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) { - if (expressionPrimary.SyntaxKind == SyntaxKind.BinaryExpressionNode) + Console.WriteLine("aaa HandleBinaryOperator"); + + var parentExpressionNode = GetParentNode(expressionPrimary, compilationUnit, ref parserModel); + + if (parentExpressionNode.SyntaxKind == SyntaxKind.BinaryExpressionNode) { - var precedencePrimary = UtilityApi.GetOperatorPrecedence(expressionPrimary.SyntaxKind); - var precedenceSecondary = UtilityApi.GetOperatorPrecedence(token.SyntaxKind); + Console.WriteLine("aaa if (parentExpressionNode.SyntaxKind == SyntaxKind.BinaryExpressionNode)"); + + var parentBinaryExpressionNode = (BinaryExpressionNode)parentExpressionNode; + var precedenceParent = UtilityApi.GetOperatorPrecedence(token.SyntaxKind); + + var precedenceChild = UtilityApi.GetOperatorPrecedence(parentBinaryExpressionNode.BinaryOperatorNode.OperatorToken.SyntaxKind); - if (precedenceSecondary > precedencePrimary) + if (parentBinaryExpressionNode.RightExpressionNode.SyntaxKind == SyntaxKind.EmptyExpressionNode) { - // TODO: Rotate the nodes? + if (precedenceParent >= precedenceChild) + { + // Child's left expression becomes the parent. + + parentBinaryExpressionNode.SetRightExpressionNode(expressionPrimary); + + var typeClauseNode = expressionPrimary.ResultTypeClauseNode; + var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); + var binaryExpressionNode = new BinaryExpressionNode(parentBinaryExpressionNode, binaryOperatorNode); + + ClearFromExpressionList(parentBinaryExpressionNode, compilationUnit, ref parserModel); + parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, binaryExpressionNode)); + + return EmptyExpressionNode.Empty; + } + else + { + // Parent's right expression becomes the child. + + var typeClauseNode = expressionPrimary.ResultTypeClauseNode; + var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); + var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); + + parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, binaryExpressionNode)); + + parentBinaryExpressionNode.SetRightExpressionNode(binaryExpressionNode); + + return EmptyExpressionNode.Empty; + } + } + else + { + // Weird situation? + // This sounds like it just wouldn't compile. + // + // Something like: + // 1 + 2 3 + 4 + // + // NOTE: There is no operator between the '2' and the '3'. + // It is just two binary expressions side by side. + // + // I think you'd want to pretend that the parent binary expression didn't exist + // for the sake of parser recovery. + + var typeClauseNode = expressionPrimary.ResultTypeClauseNode; + var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); + var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); + + ClearFromExpressionList(parentBinaryExpressionNode, compilationUnit, ref parserModel); + parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, binaryExpressionNode)); + return EmptyExpressionNode.Empty; } } - var typeClauseNode = expressionPrimary.ResultTypeClauseNode; - var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); - var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); - parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, binaryExpressionNode)); - return EmptyExpressionNode.Empty; + // Scope to avoid variable name collision. + { + var typeClauseNode = expressionPrimary.ResultTypeClauseNode; + var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); + var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); + parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, binaryExpressionNode)); + return EmptyExpressionNode.Empty; + } } public IExpressionNode AmbiguousIdentifierMergeToken( @@ -1643,4 +1704,37 @@ public void ClearFromExpressionList(IExpressionNode expressionNode, CSharpCompil parserModel.ExpressionList.RemoveAt(i); } } + + /// + /// 'bool foundChild' usage: + /// If the child is NOT in the ExpressionList then this is true, + /// + /// But, if the child is in the ExpressionList, and is not the final entry in the ExpressionList, + /// then this needs to be set to 'false', otherwise a descendent node of 'childExpressionNode' + /// will be thought to be the parent node due to the list being traversed end to front order. + /// + public IExpressionNode GetParentNode( + IExpressionNode childExpressionNode, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel, bool foundChild = true) + { + for (int i = parserModel.ExpressionList.Count - 1; i > -1; i--) + { + var delimiterExpressionTuple = parserModel.ExpressionList[i]; + + if (foundChild) + { + if (delimiterExpressionTuple.ExpressionNode is null) + break; + + if (!Object.ReferenceEquals(childExpressionNode, delimiterExpressionTuple.ExpressionNode)) + return delimiterExpressionTuple.ExpressionNode; + } + else + { + if (Object.ReferenceEquals(childExpressionNode, delimiterExpressionTuple.ExpressionNode)) + foundChild = true; + } + } + + return EmptyExpressionNode.Empty; + } } diff --git a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs index c0467370c..211e3037b 100644 --- a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs +++ b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs @@ -126,8 +126,9 @@ public void Numeric_Add_BinaryExpressionNode_More() { var test = new Test(@"1 + 1 + 1"); var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; - + var binaryExpressionNode = (BinaryExpressionNode)topCodeBlock.GetChildList().Single(); + WriteChildrenIndentedRecursive(topCodeBlock); var textTypeClause = "int"; // Left Expression From e66b2f0b7279c8f497b7b392dff513a17ea0dc28 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:15:58 -0500 Subject: [PATCH 05/14] Numeric_Star_BinaryExpressionNode_Precedence_B() --- .../BinderCase/CSharpBinder.Expressions.cs | 14 +- .../Parsers/ExpressionAsStatementTests.cs | 126 ++++++++++++++++++ 2 files changed, 138 insertions(+), 2 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index a6a2fc441..c169d83b9 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -154,16 +154,20 @@ public IExpressionNode HandleBinaryOperator( Console.WriteLine("aaa if (parentExpressionNode.SyntaxKind == SyntaxKind.BinaryExpressionNode)"); var parentBinaryExpressionNode = (BinaryExpressionNode)parentExpressionNode; - var precedenceParent = UtilityApi.GetOperatorPrecedence(token.SyntaxKind); + var precedenceParent = UtilityApi.GetOperatorPrecedence(parentBinaryExpressionNode.BinaryOperatorNode.OperatorToken.SyntaxKind); - var precedenceChild = UtilityApi.GetOperatorPrecedence(parentBinaryExpressionNode.BinaryOperatorNode.OperatorToken.SyntaxKind); + var precedenceChild = UtilityApi.GetOperatorPrecedence(token.SyntaxKind); if (parentBinaryExpressionNode.RightExpressionNode.SyntaxKind == SyntaxKind.EmptyExpressionNode) { + Console.WriteLine("aaa if (parentBinaryExpressionNode.RightExpressionNode.SyntaxKind == SyntaxKind.EmptyExpressionNode)"); + if (precedenceParent >= precedenceChild) { // Child's left expression becomes the parent. + Console.WriteLine("aaa if (precedenceParent >= precedenceChild)"); + parentBinaryExpressionNode.SetRightExpressionNode(expressionPrimary); var typeClauseNode = expressionPrimary.ResultTypeClauseNode; @@ -179,6 +183,8 @@ public IExpressionNode HandleBinaryOperator( { // Parent's right expression becomes the child. + Console.WriteLine("aaa else...precedenceParent < precedenceChild"); + var typeClauseNode = expressionPrimary.ResultTypeClauseNode; var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); @@ -204,6 +210,8 @@ public IExpressionNode HandleBinaryOperator( // I think you'd want to pretend that the parent binary expression didn't exist // for the sake of parser recovery. + Console.WriteLine("aaa else...parentBinaryExpressionNode.RightExpressionNode.SyntaxKind != SyntaxKind.EmptyExpressionNode"); + var typeClauseNode = expressionPrimary.ResultTypeClauseNode; var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); @@ -216,6 +224,8 @@ public IExpressionNode HandleBinaryOperator( // Scope to avoid variable name collision. { + Console.WriteLine("aaa default?"); + var typeClauseNode = expressionPrimary.ResultTypeClauseNode; var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); diff --git a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs index 211e3037b..f306991c3 100644 --- a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs +++ b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs @@ -229,6 +229,132 @@ public void Numeric_Star_BinaryExpressionNode() Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); } + [Fact] + public void Numeric_Star_BinaryExpressionNode_Precedence_A() + { + var test = new Test(@"1 + 2 * 3"); + var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; + + var binaryExpressionNode = (BinaryExpressionNode)topCodeBlock.GetChildList().Single(); + WriteChildrenIndentedRecursive(topCodeBlock); + var textTypeClause = "int"; + + // Left Expression + { + var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; + Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("1", rightLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + } + + // Operator + { + var binaryOperatorNode = binaryExpressionNode.BinaryOperatorNode; + Assert.Equal(textTypeClause, binaryOperatorNode.LeftOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("+", binaryOperatorNode.OperatorToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.RightOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + + // Right Expression + { + var rightBinaryExpressionNode = (BinaryExpressionNode)binaryExpressionNode.LeftExpressionNode; + Assert.Equal(textTypeClause, rightBinaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + // Temporarily swap variables for sanity #change + var rememberBinaryExpressionNode = binaryExpressionNode; + binaryExpressionNode = rightBinaryExpressionNode; + // Inner Binary Expression + { + var leftLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.LeftExpressionNode; + Assert.Equal(textTypeClause, leftLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("2", leftLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + + var binaryOperatorNode = binaryExpressionNode.BinaryOperatorNode; + Assert.Equal(textTypeClause, binaryOperatorNode.LeftOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("*", binaryOperatorNode.OperatorToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.RightOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; + Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("3", rightLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + + Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + + // Temporarily swap variables for sanity #restore + binaryExpressionNode = rememberBinaryExpressionNode; + } + + // Result + { + Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + } + + [Fact] + public void Numeric_Star_BinaryExpressionNode_Precedence_B() + { + var test = new Test(@"1 * 2 + 3"); + var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; + + var binaryExpressionNode = (BinaryExpressionNode)topCodeBlock.GetChildList().Single(); + WriteChildrenIndentedRecursive(topCodeBlock); + var textTypeClause = "int"; + + // Left Expression + { + var leftBinaryExpressionNode = (BinaryExpressionNode)binaryExpressionNode.LeftExpressionNode; + Assert.Equal(textTypeClause, leftBinaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + // Temporarily swap variables for sanity #change + var rememberBinaryExpressionNode = binaryExpressionNode; + binaryExpressionNode = leftBinaryExpressionNode; + // Inner Binary Expression + { + var leftLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.LeftExpressionNode; + Assert.Equal(textTypeClause, leftLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("1", leftLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + + var binaryOperatorNode = binaryExpressionNode.BinaryOperatorNode; + Assert.Equal(textTypeClause, binaryOperatorNode.LeftOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("*", binaryOperatorNode.OperatorToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.RightOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; + Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("2", rightLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + + Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + + // Temporarily swap variables for sanity #restore + binaryExpressionNode = rememberBinaryExpressionNode; + } + + // Operator + { + var binaryOperatorNode = binaryExpressionNode.BinaryOperatorNode; + Assert.Equal(textTypeClause, binaryOperatorNode.LeftOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("+", binaryOperatorNode.OperatorToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.RightOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + + // Right Expression + { + var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; + Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("3", rightLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + } + + // Result + { + Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + } + [Fact] public void Numeric_Division_BinaryExpressionNode() { From a33475aff32021471ed98ac9b3419ab34e07102d Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:19:55 -0500 Subject: [PATCH 06/14] Numeric_Star_BinaryExpressionNode_Precedence_A() --- .../CSharp/BinderCase/CSharpBinder.Expressions.cs | 2 +- .../CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index c169d83b9..11238a690 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -191,7 +191,7 @@ public IExpressionNode HandleBinaryOperator( parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, binaryExpressionNode)); - parentBinaryExpressionNode.SetRightExpressionNode(binaryExpressionNode); + //parentBinaryExpressionNode.SetRightExpressionNode(binaryExpressionNode); return EmptyExpressionNode.Empty; } diff --git a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs index f306991c3..7b4d52566 100644 --- a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs +++ b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs @@ -241,7 +241,7 @@ public void Numeric_Star_BinaryExpressionNode_Precedence_A() // Left Expression { - var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; + var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.LeftExpressionNode; Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); Assert.Equal("1", rightLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); } @@ -257,7 +257,7 @@ public void Numeric_Star_BinaryExpressionNode_Precedence_A() // Right Expression { - var rightBinaryExpressionNode = (BinaryExpressionNode)binaryExpressionNode.LeftExpressionNode; + var rightBinaryExpressionNode = (BinaryExpressionNode)binaryExpressionNode.RightExpressionNode; Assert.Equal(textTypeClause, rightBinaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); // Temporarily swap variables for sanity #change From 59aed8212533aac01442d68d435ff3e7f91836f5 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:22:42 -0500 Subject: [PATCH 07/14] Numeric_Star_BinaryExpressionNode_Precedence_Parent_EqualTo_Child() --- .../Parsers/ExpressionAsStatementTests.cs | 67 ++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs index 7b4d52566..6328afb32 100644 --- a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs +++ b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs @@ -230,7 +230,7 @@ public void Numeric_Star_BinaryExpressionNode() } [Fact] - public void Numeric_Star_BinaryExpressionNode_Precedence_A() + public void Numeric_Star_BinaryExpressionNode_Precedence_Parent_LessThan_Child() { var test = new Test(@"1 + 2 * 3"); var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; @@ -293,7 +293,7 @@ public void Numeric_Star_BinaryExpressionNode_Precedence_A() } [Fact] - public void Numeric_Star_BinaryExpressionNode_Precedence_B() + public void Numeric_Star_BinaryExpressionNode_Precedence_Parent_GreaterThan_Child() { var test = new Test(@"1 * 2 + 3"); var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; @@ -355,6 +355,69 @@ public void Numeric_Star_BinaryExpressionNode_Precedence_B() } } + [Fact] + public void Numeric_Star_BinaryExpressionNode_Precedence_Parent_EqualTo_Child() + { + var test = new Test(@"1 * 2 * 3"); + var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; + + var binaryExpressionNode = (BinaryExpressionNode)topCodeBlock.GetChildList().Single(); + WriteChildrenIndentedRecursive(topCodeBlock); + var textTypeClause = "int"; + + // Left Expression + { + var leftBinaryExpressionNode = (BinaryExpressionNode)binaryExpressionNode.LeftExpressionNode; + Assert.Equal(textTypeClause, leftBinaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + // Temporarily swap variables for sanity #change + var rememberBinaryExpressionNode = binaryExpressionNode; + binaryExpressionNode = leftBinaryExpressionNode; + // Inner Binary Expression + { + var leftLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.LeftExpressionNode; + Assert.Equal(textTypeClause, leftLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("1", leftLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + + var binaryOperatorNode = binaryExpressionNode.BinaryOperatorNode; + Assert.Equal(textTypeClause, binaryOperatorNode.LeftOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("*", binaryOperatorNode.OperatorToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.RightOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + + var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; + Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("2", rightLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + + Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + + // Temporarily swap variables for sanity #restore + binaryExpressionNode = rememberBinaryExpressionNode; + } + + // Operator + { + var binaryOperatorNode = binaryExpressionNode.BinaryOperatorNode; + Assert.Equal(textTypeClause, binaryOperatorNode.LeftOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("*", binaryOperatorNode.OperatorToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.RightOperandTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal(textTypeClause, binaryOperatorNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + + // Right Expression + { + var rightLiteralExpressionNode = (LiteralExpressionNode)binaryExpressionNode.RightExpressionNode; + Assert.Equal(textTypeClause, rightLiteralExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + Assert.Equal("3", rightLiteralExpressionNode.LiteralSyntaxToken.TextSpan.GetText()); + } + + // Result + { + Assert.Equal(textTypeClause, binaryExpressionNode.ResultTypeClauseNode.TypeIdentifierToken.TextSpan.GetText()); + } + } + [Fact] public void Numeric_Division_BinaryExpressionNode() { From 3ccc09e2c969b3e0e4bedd33e3b425f5ba7b2d8c Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:07:50 -0500 Subject: [PATCH 08/14] Remove: Console.WriteLine --- .../BinderCase/CSharpBinder.Expressions.cs | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 11238a690..11c0eaa41 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -145,29 +145,21 @@ public IExpressionNode AnyMergeExpression( public IExpressionNode HandleBinaryOperator( IExpressionNode expressionPrimary, ISyntaxToken token, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) { - Console.WriteLine("aaa HandleBinaryOperator"); - var parentExpressionNode = GetParentNode(expressionPrimary, compilationUnit, ref parserModel); if (parentExpressionNode.SyntaxKind == SyntaxKind.BinaryExpressionNode) - { - Console.WriteLine("aaa if (parentExpressionNode.SyntaxKind == SyntaxKind.BinaryExpressionNode)"); - + { var parentBinaryExpressionNode = (BinaryExpressionNode)parentExpressionNode; var precedenceParent = UtilityApi.GetOperatorPrecedence(parentBinaryExpressionNode.BinaryOperatorNode.OperatorToken.SyntaxKind); var precedenceChild = UtilityApi.GetOperatorPrecedence(token.SyntaxKind); if (parentBinaryExpressionNode.RightExpressionNode.SyntaxKind == SyntaxKind.EmptyExpressionNode) - { - Console.WriteLine("aaa if (parentBinaryExpressionNode.RightExpressionNode.SyntaxKind == SyntaxKind.EmptyExpressionNode)"); - + { if (precedenceParent >= precedenceChild) { // Child's left expression becomes the parent. - Console.WriteLine("aaa if (precedenceParent >= precedenceChild)"); - parentBinaryExpressionNode.SetRightExpressionNode(expressionPrimary); var typeClauseNode = expressionPrimary.ResultTypeClauseNode; @@ -183,8 +175,6 @@ public IExpressionNode HandleBinaryOperator( { // Parent's right expression becomes the child. - Console.WriteLine("aaa else...precedenceParent < precedenceChild"); - var typeClauseNode = expressionPrimary.ResultTypeClauseNode; var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); @@ -210,8 +200,6 @@ public IExpressionNode HandleBinaryOperator( // I think you'd want to pretend that the parent binary expression didn't exist // for the sake of parser recovery. - Console.WriteLine("aaa else...parentBinaryExpressionNode.RightExpressionNode.SyntaxKind != SyntaxKind.EmptyExpressionNode"); - var typeClauseNode = expressionPrimary.ResultTypeClauseNode; var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); @@ -223,9 +211,7 @@ public IExpressionNode HandleBinaryOperator( } // Scope to avoid variable name collision. - { - Console.WriteLine("aaa default?"); - + { var typeClauseNode = expressionPrimary.ResultTypeClauseNode; var binaryOperatorNode = new BinaryOperatorNode(typeClauseNode, token, typeClauseNode, typeClauseNode); var binaryExpressionNode = new BinaryExpressionNode(expressionPrimary, binaryOperatorNode); From 045a2d55c4828af2a07693b398fc490bbccbb7a2 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:36:44 -0500 Subject: [PATCH 09/14] Fix: optional argument entry in listing --- .../CSharp/ParserCase/Internals/ParseFunctions.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseFunctions.cs b/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseFunctions.cs index 2d88c37c6..f1e520ff4 100644 --- a/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseFunctions.cs +++ b/Source/Lib/CompilerServices/CSharp/ParserCase/Internals/ParseFunctions.cs @@ -168,7 +168,6 @@ public static FunctionArgumentsListingNode HandleFunctionArguments(CSharpCompila if (successTypeClauseNode) { - // 'TypeClauseNode' or 'VariableDeclarationNode' var successNameableToken = false; if (UtilityApi.IsConvertibleToIdentifierToken(parserModel.TokenWalker.Current.SyntaxKind)) @@ -178,7 +177,11 @@ public static FunctionArgumentsListingNode HandleFunctionArguments(CSharpCompila if (parserModel.TokenWalker.Current.SyntaxKind == SyntaxKind.EqualsToken) { - // Optional + _ = parserModel.TokenWalker.Consume(); + + parserModel.ExpressionList.Add((SyntaxKind.CloseParenthesisToken, null)); + parserModel.ExpressionList.Add((SyntaxKind.CommaToken, null)); + var expressionNode = ParseOthers.ParseExpression(compilationUnit, ref parserModel); } var variableDeclarationNode = new VariableDeclarationNode( From 0dbd167f19d5e4e4f70510a32a313e9976dcce68 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:36:25 -0500 Subject: [PATCH 10/14] Parse optional parameters --- .../BinderCase/CSharpBinder.Expressions.cs | 49 +++++++++++++++---- .../CSharp/ParserCase/CSharpParserModel.cs | 11 +++++ 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 11c0eaa41..2d7daea71 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -242,10 +242,8 @@ public IExpressionNode AmbiguousIdentifierMergeToken( BindFunctionInvocationNode( functionInvocationNode, compilationUnit); - - parserModel.ExpressionList.Add((SyntaxKind.CloseParenthesisToken, functionInvocationNode)); - parserModel.ExpressionList.Add((SyntaxKind.CommaToken, functionInvocationNode.FunctionParametersListingNode)); - return EmptyExpressionNode.Empty; + + return ParseFunctionParametersListingNode(functionInvocationNode, functionInvocationNode.FunctionParametersListingNode, compilationUnit, ref parserModel); } else if (token.SyntaxKind == SyntaxKind.OpenAngleBracketToken) { @@ -628,9 +626,8 @@ public IExpressionNode ConstructorInvocationMergeToken( constructorInvocationExpressionNode.SetFunctionParametersListingNode(functionParametersListingNode); constructorInvocationExpressionNode.ConstructorInvocationStageKind = ConstructorInvocationStageKind.FunctionParameters; - parserModel.ExpressionList.Add((SyntaxKind.CloseParenthesisToken, constructorInvocationExpressionNode)); - parserModel.ExpressionList.Add((SyntaxKind.CommaToken, constructorInvocationExpressionNode.FunctionParametersListingNode)); - return EmptyExpressionNode.Empty; + + return ParseFunctionParametersListingNode(constructorInvocationExpressionNode, constructorInvocationExpressionNode.FunctionParametersListingNode, compilationUnit, ref parserModel); case SyntaxKind.CloseParenthesisToken: if (constructorInvocationExpressionNode.FunctionParametersListingNode is not null) { @@ -1056,6 +1053,10 @@ public IExpressionNode FunctionParametersListingMergeToken( { case SyntaxKind.CommaToken: parserModel.ExpressionList.Add((SyntaxKind.CommaToken, functionParametersListingNode)); + parserModel.ExpressionList.Add((SyntaxKind.ColonToken, functionParametersListingNode)); + return ParseNamedParameterSyntaxAndReturnEmptyExpressionNode(compilationUnit, ref parserModel); + case SyntaxKind.ColonToken: + parserModel.ExpressionList.Add((SyntaxKind.ColonToken, functionParametersListingNode)); return EmptyExpressionNode.Empty; default: return new BadExpressionNode(CSharpFacts.Types.Void.ToTypeClause(), functionParametersListingNode, token); @@ -1065,6 +1066,13 @@ public IExpressionNode FunctionParametersListingMergeToken( public IExpressionNode FunctionParametersListingMergeExpression( FunctionParametersListingNode functionParametersListingNode, IExpressionNode expressionSecondary, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) { + Console.WriteLine("aaa FunctionParametersListingMergeExpression"); + if (parserModel.TokenWalker.Current.SyntaxKind == SyntaxKind.ColonToken) + { + Console.WriteLine($"aaa CURRENT optional? bbb {expressionSecondary.SyntaxKind}"); + return functionParametersListingNode; + } + if (expressionSecondary.SyntaxKind == SyntaxKind.EmptyExpressionNode) return functionParametersListingNode; @@ -1406,9 +1414,7 @@ public IExpressionNode TypeClauseMergeToken( functionInvocationNode, compilationUnit); - parserModel.ExpressionList.Add((SyntaxKind.CloseParenthesisToken, functionInvocationNode)); - parserModel.ExpressionList.Add((SyntaxKind.CommaToken, functionInvocationNode.FunctionParametersListingNode)); - return EmptyExpressionNode.Empty; + return ParseFunctionParametersListingNode(functionInvocationNode, functionInvocationNode.FunctionParametersListingNode, compilationUnit, ref parserModel); } goto default; @@ -1733,4 +1739,27 @@ public IExpressionNode GetParentNode( return EmptyExpressionNode.Empty; } + + /// + /// The argument 'IExpressionNode functionInvocationNode' is not of type 'FunctionInvocationNode' + /// in order to permit this method to be invoked for 'ConstructorInvocationExpressionNode' as well. + /// + public IExpressionNode ParseFunctionParametersListingNode(IExpressionNode functionInvocationNode, FunctionParametersListingNode functionParametersListingNode, CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) + { + parserModel.ExpressionList.Add((SyntaxKind.CloseParenthesisToken, functionInvocationNode)); + parserModel.ExpressionList.Add((SyntaxKind.CommaToken, functionParametersListingNode)); + parserModel.ExpressionList.Add((SyntaxKind.ColonToken, functionParametersListingNode)); + return ParseNamedParameterSyntaxAndReturnEmptyExpressionNode(compilationUnit, ref parserModel); + } + + public IExpressionNode ParseNamedParameterSyntaxAndReturnEmptyExpressionNode(CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) + { + if (parserModel.TokenWalker.Peek(2).SyntaxKind == SyntaxKind.ColonToken) + { + _ = parserModel.TokenWalker.Consume(); // Consume the identifier + _ = parserModel.TokenWalker.Consume(); // Consume the ColonToken + } + + return EmptyExpressionNode.Empty; + } } diff --git a/Source/Lib/CompilerServices/CSharp/ParserCase/CSharpParserModel.cs b/Source/Lib/CompilerServices/CSharp/ParserCase/CSharpParserModel.cs index 86e4381a1..6b13ce8d9 100644 --- a/Source/Lib/CompilerServices/CSharp/ParserCase/CSharpParserModel.cs +++ b/Source/Lib/CompilerServices/CSharp/ParserCase/CSharpParserModel.cs @@ -43,7 +43,18 @@ public CSharpParserModel( public TokenWalker TokenWalker { get; } public Stack SyntaxStack { get; set; } public CSharpStatementBuilder StatementBuilder { get; set; } = new(); + + /// + /// The C# IParserModel implementation will only "short circuit" if the 'SyntaxKind DelimiterSyntaxKind' + /// is registered as a delimiter. + /// + /// This is done in order to speed up the while loop, as the list of short circuits doesn't have to be + /// iterated unless the current token is a possible delimiter. + /// + /// Luthetus.CompilerServices.CSharp.ParserCase.Internals.ParseOthers.SyntaxIsEndDelimiter(SyntaxKind syntaxKind) {...} + /// public List<(SyntaxKind DelimiterSyntaxKind, IExpressionNode ExpressionNode)> ExpressionList { get; set; } + public IExpressionNode? NoLongerRelevantExpressionNode { get; set; } public List TryParseExpressionSyntaxKindList { get; } = new(); public IExpressionNode ForceParseExpressionInitialPrimaryExpression { get; set; } From 0c46d4f1f3941a433eea5be8bdddf34bfc2c9033 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:37:06 -0500 Subject: [PATCH 11/14] Pseudo amend previous commit: this parses named parameters --- .../CSharp/BinderCase/CSharpBinder.Expressions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 2d7daea71..e3fd06cce 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -1756,7 +1756,7 @@ public IExpressionNode ParseNamedParameterSyntaxAndReturnEmptyExpressionNode(CSh { if (parserModel.TokenWalker.Peek(2).SyntaxKind == SyntaxKind.ColonToken) { - _ = parserModel.TokenWalker.Consume(); // Consume the identifier + _ = parserModel.TokenWalker.Consume(); // Consume the identifierx _ = parserModel.TokenWalker.Consume(); // Consume the ColonToken } From ed30adbd624df596c18267662011e7c610d5a266 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:37:50 -0500 Subject: [PATCH 12/14] Parse named parameters (see 2 commits previous with wrong name) --- .../CSharp/BinderCase/CSharpBinder.Expressions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index e3fd06cce..2d7daea71 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -1756,7 +1756,7 @@ public IExpressionNode ParseNamedParameterSyntaxAndReturnEmptyExpressionNode(CSh { if (parserModel.TokenWalker.Peek(2).SyntaxKind == SyntaxKind.ColonToken) { - _ = parserModel.TokenWalker.Consume(); // Consume the identifierx + _ = parserModel.TokenWalker.Consume(); // Consume the identifier _ = parserModel.TokenWalker.Consume(); // Consume the ColonToken } From 5789695acbf1dfde089c98207f746bcdd164a70c Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:47:24 -0500 Subject: [PATCH 13/14] Named parameters: 'CreateVariableSymbol' --- .../BinderCase/CSharpBinder.Expressions.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 2d7daea71..deb1d9cce 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -1754,10 +1754,20 @@ public IExpressionNode ParseFunctionParametersListingNode(IExpressionNode functi public IExpressionNode ParseNamedParameterSyntaxAndReturnEmptyExpressionNode(CSharpCompilationUnit compilationUnit, ref CSharpParserModel parserModel) { - if (parserModel.TokenWalker.Peek(2).SyntaxKind == SyntaxKind.ColonToken) + if (UtilityApi.IsConvertibleToIdentifierToken(parserModel.TokenWalker.Peek(1).SyntaxKind) && + parserModel.TokenWalker.Peek(2).SyntaxKind == SyntaxKind.ColonToken) { - _ = parserModel.TokenWalker.Consume(); // Consume the identifier - _ = parserModel.TokenWalker.Consume(); // Consume the ColonToken + // Consume the open parenthesis + _ = parserModel.TokenWalker.Consume(); + + // Consume the identifierToken + compilationUnit.Binder.CreateVariableSymbol( + UtilityApi.ConvertToIdentifierToken(parserModel.TokenWalker.Consume(), compilationUnit, ref parserModel), + VariableKind.Local, + compilationUnit); + + // Consume the ColonToken + _ = parserModel.TokenWalker.Consume(); } return EmptyExpressionNode.Empty; From 3f9762974f7687b7269058b8739de9055c9ea83a Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:06:00 -0500 Subject: [PATCH 14/14] Update IdeInfoDisplay.razor --- .../Displays/Internals/IdeInfoDisplay.razor | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor b/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor index 66a81d389..1c0a0718b 100644 --- a/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor +++ b/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor @@ -172,11 +172,28 @@ Recent Changes: - v 0.9.7.11 (WIP_DESCRIPTION) + v 0.9.7.11 (2024-12-20) - WIP_DESCRIPTION - + Text Editor NuGet Package v3.5.0 (by the end of the day I will publish this) + (nuget.org) + + + Fix: optional argument entry in function definition signature + + + Fix: named parameters in function invocation + + + Started logic for operator precedence. + + + Support more operators such as '||'. + + + Expressions are now parsed properly when terminated by the end of file + (rather than for example: a StatementDelimiterToken ';') +