From a84c7c9f657d5d4238fb271fe40841b99f6722dd Mon Sep 17 00:00:00 2001 From: Chris Xu Date: Fri, 29 Nov 2024 15:06:50 -0800 Subject: [PATCH] Remove DiagnosticBag from SyntaxNode --- .../BinderTests/BoundNodeTests.cs | 8 +-- .../BinderTests/ConstantFoldingTests.cs | 8 +-- .../CodeAnalysis/ClrTypeCacheViewTests.cs | 2 +- .../ParserTests/IfUnlessStatementTests.cs | 17 ++--- .../ParserTests/SyntaxNodeTests.cs | 19 ++---- .../ParserTests/WhileUntilStatementTests.cs | 4 -- src/Todl.Compiler.Tests/TestUtils.cs | 66 ++++++++++++++++--- .../CodeAnalysis/Binding/BoundModule.cs | 7 +- .../Syntax/FunctionCallExpression.cs | 9 +-- .../CodeAnalysis/Syntax/IfUnlessStatement.cs | 13 ++-- .../CodeAnalysis/Syntax/NewExpression.cs | 6 +- .../CodeAnalysis/Syntax/Parser.cs | 7 +- .../CodeAnalysis/Syntax/SyntaxNode.cs | 26 ++------ .../CodeAnalysis/Syntax/SyntaxTree.cs | 29 +++++--- .../CodeGeneration/Compilation.cs | 2 +- src/Todl.Compiler/Evaluation/Evaluator.cs | 10 ++- 16 files changed, 135 insertions(+), 98 deletions(-) diff --git a/src/Todl.Compiler.Tests/CodeAnalysis/BinderTests/BoundNodeTests.cs b/src/Todl.Compiler.Tests/CodeAnalysis/BinderTests/BoundNodeTests.cs index dadeb05..247fca5 100644 --- a/src/Todl.Compiler.Tests/CodeAnalysis/BinderTests/BoundNodeTests.cs +++ b/src/Todl.Compiler.Tests/CodeAnalysis/BinderTests/BoundNodeTests.cs @@ -113,7 +113,7 @@ public static IEnumerable GetAllSyntaxNodesForTest() foreach (var inputText in testExpressions) { - var expression = SyntaxTree.ParseExpression(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var expression = SyntaxTree.ParseExpression(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); var binder = Binder.CreateScriptBinder(TestDefaults.DefaultClrTypeCache, diagnosticBuilder); yield return new object[] { expression, binder.BindExpression(expression) }; } @@ -121,7 +121,7 @@ public static IEnumerable GetAllSyntaxNodesForTest() // BoundVariableExpression requires special logic to work { var sourceText = SourceText.FromString("{ const a = 5; a; }"); - var blockStatement = SyntaxTree.ParseStatement(sourceText, TestDefaults.DefaultClrTypeCache); + var blockStatement = SyntaxTree.ParseStatement(sourceText, TestDefaults.DefaultClrTypeCache, diagnosticBuilder); var binder = Binder.CreateModuleBinder(TestDefaults.DefaultClrTypeCache, diagnosticBuilder); var boundBlockStatement = binder.BindStatement(blockStatement).As(); @@ -133,14 +133,14 @@ public static IEnumerable GetAllSyntaxNodesForTest() foreach (var inputText in testStatements) { - var statement = SyntaxTree.ParseStatement(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var statement = SyntaxTree.ParseStatement(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); var binder = Binder.CreateModuleBinder(TestDefaults.DefaultClrTypeCache, diagnosticBuilder); yield return new object[] { statement, binder.BindStatement(statement) }; } foreach (var inputText in testMembers) { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); var member = syntaxTree.Members[0]; var binder = Binder.CreateModuleBinder(TestDefaults.DefaultClrTypeCache, diagnosticBuilder); if (member is FunctionDeclarationMember functionDeclarationMember) diff --git a/src/Todl.Compiler.Tests/CodeAnalysis/BinderTests/ConstantFoldingTests.cs b/src/Todl.Compiler.Tests/CodeAnalysis/BinderTests/ConstantFoldingTests.cs index 1698e0b..e30c93b 100644 --- a/src/Todl.Compiler.Tests/CodeAnalysis/BinderTests/ConstantFoldingTests.cs +++ b/src/Todl.Compiler.Tests/CodeAnalysis/BinderTests/ConstantFoldingTests.cs @@ -30,7 +30,7 @@ public sealed class ConstantFoldingTests [InlineData("const a = ~10UL;", ~10UL)] public void ConstantFoldingUnaryOperatorTest(string inputText, object expectedValue) { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, new()); var module = BoundModule.Create(TestDefaults.DefaultClrTypeCache, new[] { syntaxTree }); module.GetDiagnostics().Should().BeEmpty(); @@ -54,7 +54,7 @@ public void ConstantFoldingUnaryOperatorTest(string inputText, object expectedVa [InlineData("const a = -20;", -20)] public void BasicConstantFoldingTests(string inputText, object expectedValue) { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, new()); var module = BoundModule.Create(TestDefaults.DefaultClrTypeCache, new[] { syntaxTree }); module.GetDiagnostics().Should().BeEmpty(); @@ -76,7 +76,7 @@ public void BasicConstantFoldingTests(string inputText, object expectedValue) [InlineData("const a = 10; let b = a + 10; const c = a + b;")] public void BasicConstantFoldingNegativeTests(string inputText) { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, new()); var module = BoundModule.Create(TestDefaults.DefaultClrTypeCache, new[] { syntaxTree }); module.GetDiagnostics().Should().BeEmpty(); @@ -88,7 +88,7 @@ public void BasicConstantFoldingNegativeTests(string inputText) [Fact] public void PartiallyFoldedConstantTests() { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString("let a = 10 + 10;"), TestDefaults.DefaultClrTypeCache); + var syntaxTree = SyntaxTree.Parse(SourceText.FromString("let a = 10 + 10;"), TestDefaults.DefaultClrTypeCache, new()); var module = BoundModule.Create(TestDefaults.DefaultClrTypeCache, new[] { syntaxTree }); module.GetDiagnostics().Should().BeEmpty(); diff --git a/src/Todl.Compiler.Tests/CodeAnalysis/ClrTypeCacheViewTests.cs b/src/Todl.Compiler.Tests/CodeAnalysis/ClrTypeCacheViewTests.cs index d66ac42..0bc835b 100644 --- a/src/Todl.Compiler.Tests/CodeAnalysis/ClrTypeCacheViewTests.cs +++ b/src/Todl.Compiler.Tests/CodeAnalysis/ClrTypeCacheViewTests.cs @@ -52,7 +52,7 @@ public void TestResolveBuiltInTypes(string typeName, Type targetType, SpecialTyp [InlineData("System.Uri", "import { Console, Uri } from System;", typeof(Uri))] public void TestResolveImportedTypes(string typeName, string importDirective, Type targetType) { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(importDirective), TestDefaults.DefaultClrTypeCache); + var syntaxTree = SyntaxTree.Parse(SourceText.FromString(importDirective), TestDefaults.DefaultClrTypeCache, new()); var resolvedType = syntaxTree.ClrTypeCacheView.ResolveBaseType(typeName); resolvedType.ClrType.AssemblyQualifiedName.Should().Be(targetType.AssemblyQualifiedName); resolvedType.SpecialType.Should().Be(SpecialType.None); diff --git a/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/IfUnlessStatementTests.cs b/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/IfUnlessStatementTests.cs index cb60d4f..9cf15ae 100644 --- a/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/IfUnlessStatementTests.cs +++ b/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/IfUnlessStatementTests.cs @@ -82,7 +82,6 @@ public void IfUnlessStatementsCanHaveMultipleElseClauses(string inputText, int e var ifUnlessStatement = TestUtils.ParseStatement(inputText); ifUnlessStatement.Should().NotBeNull(); ifUnlessStatement.ElseClauses.Should().HaveCount(expectedCount); - ifUnlessStatement.GetDiagnostics().Should().BeEmpty(); } [Theory] @@ -93,17 +92,17 @@ public void IfUnlessStatementsCanBeNested(string inputText) var ifUnlessStatement = TestUtils.ParseStatement(inputText); ifUnlessStatement.Should().NotBeNull(); ifUnlessStatement.ElseClauses.Should().HaveCount(1); - ifUnlessStatement.GetDiagnostics().Should().BeEmpty(); } [Fact] public void IfUnlessStatementsCannotHaveMoreThanOneBareElseClauses() { - var ifUnlessStatement = TestUtils.ParseStatement("if a == 0 { } else { } else { }"); + var diagnosticBuilder = new DiagnosticBag.Builder(); + var ifUnlessStatement = TestUtils.ParseStatement("if a == 0 { } else { } else { }", diagnosticBuilder); ifUnlessStatement.Should().NotBeNull(); ifUnlessStatement.ElseClauses.Should().HaveCount(2); - var diagnostics = ifUnlessStatement.GetDiagnostics(); + var diagnostics = diagnosticBuilder.Build(); diagnostics.Should().NotBeEmpty(); diagnostics.Count(d => d.ErrorCode == ErrorCode.DuplicateBareElseClauses).Should().Be(2); @@ -116,11 +115,12 @@ public void IfUnlessStatementsCannotHaveMoreThanOneBareElseClauses() [Fact] public void IfUnlessStatementsCannotHaveMisplacedElseClause() { - var ifUnlessStatement = TestUtils.ParseStatement("if a == 0 { } else { } else if b == 0 { }"); + var diagnosticBuilder = new DiagnosticBag.Builder(); + var ifUnlessStatement = TestUtils.ParseStatement("if a == 0 { } else { } else if b == 0 { }", diagnosticBuilder); ifUnlessStatement.Should().NotBeNull(); ifUnlessStatement.ElseClauses.Should().HaveCount(2); - var diagnostics = ifUnlessStatement.GetDiagnostics(); + var diagnostics = diagnosticBuilder.Build(); diagnostics.Should().NotBeEmpty(); diagnostics.Count(d => d.ErrorCode == ErrorCode.MisplacedBareElseClauses).Should().Be(1); @@ -133,11 +133,12 @@ public void IfUnlessStatementsCannotHaveMisplacedElseClause() [Fact] public void IfUnlessStatementsCannotHaveMismatchedIfOrUnlessKeywords() { - var ifUnlessStatement = TestUtils.ParseStatement("if a == 0 { } else unless b == 0 { }"); + var diagnosticBuilder = new DiagnosticBag.Builder(); + var ifUnlessStatement = TestUtils.ParseStatement("if a == 0 { } else unless b == 0 { }", diagnosticBuilder); ifUnlessStatement.Should().NotBeNull(); ifUnlessStatement.ElseClauses.Should().HaveCount(1); - var diagnostics = ifUnlessStatement.GetDiagnostics(); + var diagnostics = diagnosticBuilder.Build(); diagnostics.Should().NotBeEmpty(); diagnostics.Count(d => d.ErrorCode == ErrorCode.IfUnlessKeywordMismatch).Should().Be(1); diff --git a/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/SyntaxNodeTests.cs b/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/SyntaxNodeTests.cs index 41c1bb6..65b3c1a 100644 --- a/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/SyntaxNodeTests.cs +++ b/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/SyntaxNodeTests.cs @@ -5,6 +5,7 @@ using FluentAssertions; using Todl.Compiler.CodeAnalysis.Syntax; using Todl.Compiler.CodeAnalysis.Text; +using Todl.Compiler.Diagnostics; using Xunit; namespace Todl.Compiler.Tests.CodeAnalysis; @@ -26,14 +27,6 @@ public void SyntaxTreePropertyShouldNotBeNull(string inputTextIgnored, SyntaxNod syntaxNode.SyntaxTree.Should().NotBeNull(); } - [Theory] - [MemberData(nameof(GetAllSyntaxNodesForTest))] - [SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] - public void DiagnosticBagShouldNotBeNull(string inputTextIgnored, SyntaxNode syntaxNode) - { - syntaxNode.GetDiagnostics().Should().NotBeNull(); - } - [Fact] public void AllSyntaxNodeTypesNeedsToBeCoveredInTests() { @@ -99,27 +92,29 @@ public void AllSyntaxNodeTypesNeedsToBeCoveredInTests() public static IEnumerable GetAllSyntaxNodesForTest() { + var diagnosticBuilder = new DiagnosticBag.Builder(); + foreach (var inputText in testExpressions) { - var expression = SyntaxTree.ParseExpression(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var expression = SyntaxTree.ParseExpression(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); yield return new object[] { inputText, expression }; } foreach (var inputText in testStatements) { - var statement = SyntaxTree.ParseStatement(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var statement = SyntaxTree.ParseStatement(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); yield return new object[] { inputText, statement }; } foreach (var inputText in testDirectives) { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); yield return new object[] { inputText, syntaxTree.Directives[0] }; } foreach (var inputText in testMembers) { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var syntaxTree = SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); yield return new object[] { inputText, syntaxTree.Members[0] }; } } diff --git a/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/WhileUntilStatementTests.cs b/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/WhileUntilStatementTests.cs index ccf5383..b83790c 100644 --- a/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/WhileUntilStatementTests.cs +++ b/src/Todl.Compiler.Tests/CodeAnalysis/ParserTests/WhileUntilStatementTests.cs @@ -11,7 +11,6 @@ public void EmptyBreakStatementCanBeParsed() { var breakStatement = TestUtils.ParseStatement("break;"); breakStatement.Should().NotBeNull(); - breakStatement.GetDiagnostics().Should().BeEmpty(); breakStatement.BreakKeywordToken.Kind.Should().Be(SyntaxKind.BreakKeywordToken); breakStatement.SemicolonToken.Kind.Should().Be(SyntaxKind.SemicolonToken); @@ -23,7 +22,6 @@ public void EmptyContinueStatementCanBeParsed() { var continueStatement = TestUtils.ParseStatement("continue;"); continueStatement.Should().NotBeNull(); - continueStatement.GetDiagnostics().Should().BeEmpty(); continueStatement.ContinueKeywordToken.Kind.Should().Be(SyntaxKind.ContinueKeywordToken); continueStatement.SemicolonToken.Kind.Should().Be(SyntaxKind.SemicolonToken); @@ -37,7 +35,6 @@ public void WhileUntilStatementsCanHaveEmptyBody(string inputText, SyntaxKind ex { var whileUntilStatement = TestUtils.ParseStatement(inputText); whileUntilStatement.Should().NotBeNull(); - whileUntilStatement.GetDiagnostics().Should().BeEmpty(); whileUntilStatement.WhileOrUntilToken.Kind.Should().Be(expectedSyntaxKind); whileUntilStatement.BlockStatement.InnerStatements.Should().BeEmpty(); @@ -56,7 +53,6 @@ public void WhileUntilStatementsCanHaveOneOrMoreInnerStatements(string inputText { var whileUntilStatement = TestUtils.ParseStatement(inputText); whileUntilStatement.Should().NotBeNull(); - whileUntilStatement.GetDiagnostics().Should().BeEmpty(); whileUntilStatement.BlockStatement.InnerStatements.Should().HaveCount(expectedStatementsCount); } } diff --git a/src/Todl.Compiler.Tests/TestUtils.cs b/src/Todl.Compiler.Tests/TestUtils.cs index 31baf3e..4941ca7 100644 --- a/src/Todl.Compiler.Tests/TestUtils.cs +++ b/src/Todl.Compiler.Tests/TestUtils.cs @@ -21,7 +21,7 @@ internal static TBoundExpression BindExpression( string inputText, DiagnosticBag.Builder diagnosticBuilder) where TBoundExpression : BoundExpression { - var expression = SyntaxTree.ParseExpression(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var expression = SyntaxTree.ParseExpression(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); var binder = Binder.CreateModuleBinder(TestDefaults.DefaultClrTypeCache, diagnosticBuilder); return binder.BindExpression(expression).As(); } @@ -39,7 +39,7 @@ internal static TBoundStatement BindStatement( string inputText, DiagnosticBag.Builder diagnosticBuilder) where TBoundStatement : BoundStatement { - var statement = SyntaxTree.ParseStatement(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + var statement = SyntaxTree.ParseStatement(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); var binder = Binder.CreateModuleBinder(TestDefaults.DefaultClrTypeCache, diagnosticBuilder); return binder.BindStatement(statement).As(); } @@ -104,33 +104,79 @@ internal static void EmitStatementAndVerify(string input, params TestInstruction emitter.ILProcessor.Body.Instructions.ShouldHaveExactInstructionSequence(expectedInstructions); } + internal static SyntaxTree ParseSyntaxTree(string inputText, DiagnosticBag.Builder diagnosticBuilder) + => SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache, diagnosticBuilder); + internal static SyntaxTree ParseSyntaxTree(string inputText) - => SyntaxTree.Parse(SourceText.FromString(inputText), TestDefaults.DefaultClrTypeCache); + { + var diagnosticBuilder = new DiagnosticBag.Builder(); + var syntaxTree = ParseSyntaxTree(inputText, diagnosticBuilder); + diagnosticBuilder.Build().Should().BeEmpty(); + return syntaxTree; + } + + internal static TExpression ParseExpression(string sourceText, DiagnosticBag.Builder diagnosticBuilder) + where TExpression : Expression + => SyntaxTree.ParseExpression( + SourceText.FromString(sourceText), + TestDefaults.DefaultClrTypeCache, + diagnosticBuilder).As(); internal static TExpression ParseExpression(string sourceText) - where TExpression : Expression + where TExpression : Expression { - return SyntaxTree.ParseExpression(SourceText.FromString(sourceText), TestDefaults.DefaultClrTypeCache).As(); + var diagnosticBuilder = new DiagnosticBag.Builder(); + var expression = ParseExpression(sourceText, diagnosticBuilder); + diagnosticBuilder.Build().Should().BeEmpty(); + return expression; } + internal static TStatement ParseStatement(string sourceText, DiagnosticBag.Builder diagnosticBuilder) + where TStatement : Statement + => SyntaxTree.ParseStatement( + SourceText.FromString(sourceText), + TestDefaults.DefaultClrTypeCache, + diagnosticBuilder).As(); + internal static TStatement ParseStatement(string sourceText) where TStatement : Statement { - return SyntaxTree.ParseStatement(SourceText.FromString(sourceText), TestDefaults.DefaultClrTypeCache).As(); + var diagnosticBuilder = new DiagnosticBag.Builder(); + var statement = ParseStatement(sourceText, diagnosticBuilder); + diagnosticBuilder.Build().Should().BeEmpty(); + return statement; } + internal static TDirective ParseDirective(string sourceText, DiagnosticBag.Builder diagnosticBuilder) + where TDirective : Directive + => SyntaxTree.Parse( + SourceText.FromString(sourceText), + TestDefaults.DefaultClrTypeCache, + diagnosticBuilder).Directives[0].As(); + internal static TDirective ParseDirective(string sourceText) where TDirective : Directive { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(sourceText), TestDefaults.DefaultClrTypeCache); - return syntaxTree.Directives[0].As(); + var diagnosticBuilder = new DiagnosticBag.Builder(); + var directive = ParseDirective(sourceText, diagnosticBuilder); + diagnosticBuilder.Build().Should().BeEmpty(); + return directive; } + internal static TMember ParseMember(string sourceText, DiagnosticBag.Builder diagnosticBuilder) + where TMember : Member + => SyntaxTree.Parse( + SourceText.FromString(sourceText), + TestDefaults.DefaultClrTypeCache, + diagnosticBuilder).Members[0].As(); + internal static TMember ParseMember(string sourceText) where TMember : Member { - var syntaxTree = SyntaxTree.Parse(SourceText.FromString(sourceText), TestDefaults.DefaultClrTypeCache); - return syntaxTree.Members[0].As(); + var diagnosticBuilder = new DiagnosticBag.Builder(); + var member = ParseMember(sourceText, diagnosticBuilder); + diagnosticBuilder.Build().Should().BeEmpty(); + return member; } internal static void ShouldHaveExactInstructionSequence( diff --git a/src/Todl.Compiler/CodeAnalysis/Binding/BoundModule.cs b/src/Todl.Compiler/CodeAnalysis/Binding/BoundModule.cs index a06ab7d..501a64f 100644 --- a/src/Todl.Compiler/CodeAnalysis/Binding/BoundModule.cs +++ b/src/Todl.Compiler/CodeAnalysis/Binding/BoundModule.cs @@ -17,9 +17,14 @@ internal sealed class BoundModule : IDiagnosable public static BoundModule Create( ClrTypeCache clrTypeCache, IReadOnlyList syntaxTrees) + => Create(clrTypeCache, syntaxTrees, new()); + + public static BoundModule Create( + ClrTypeCache clrTypeCache, + IReadOnlyList syntaxTrees, + DiagnosticBag.Builder diagnosticBuilder) { syntaxTrees ??= Array.Empty(); - var diagnosticBuilder = new DiagnosticBag.Builder(); var binder = Binder.CreateModuleBinder(clrTypeCache, diagnosticBuilder); var entryPointType = binder.BindEntryPointTypeDefinition(syntaxTrees); diff --git a/src/Todl.Compiler/CodeAnalysis/Syntax/FunctionCallExpression.cs b/src/Todl.Compiler/CodeAnalysis/Syntax/FunctionCallExpression.cs index 80ea072..0b6bfe0 100644 --- a/src/Todl.Compiler/CodeAnalysis/Syntax/FunctionCallExpression.cs +++ b/src/Todl.Compiler/CodeAnalysis/Syntax/FunctionCallExpression.cs @@ -72,13 +72,12 @@ private Argument ParseArgument() private FunctionCallExpression ParseFunctionCallExpression(Expression baseExpression) { - var diagnosticBuilder = new DiagnosticBag.Builder(); var arguments = ParseCommaSeparatedSyntaxList(ParseArgument); var namedArguments = arguments.Items.Where(p => p.IsNamedArgument); if (namedArguments.Any() && namedArguments.Count() != arguments.Items.Length) { - diagnosticBuilder.Add( + ReportDiagnostic( new Diagnostic() { Message = "Either all or none of the arguments should be named arguments", @@ -96,8 +95,7 @@ private FunctionCallExpression ParseFunctionCallExpression(Expression baseExpres BaseExpression = memberAccessExpression.BaseExpression, DotToken = memberAccessExpression.DotToken, NameToken = memberAccessExpression.MemberIdentifierToken, - Arguments = arguments, - DiagnosticBuilder = diagnosticBuilder + Arguments = arguments }; } @@ -107,8 +105,7 @@ private FunctionCallExpression ParseFunctionCallExpression(Expression baseExpres { SyntaxTree = syntaxTree, NameToken = (baseExpression as NameExpression).SyntaxTokens[0], - Arguments = arguments, - DiagnosticBuilder = diagnosticBuilder + Arguments = arguments }; } } diff --git a/src/Todl.Compiler/CodeAnalysis/Syntax/IfUnlessStatement.cs b/src/Todl.Compiler/CodeAnalysis/Syntax/IfUnlessStatement.cs index 7aa8ba0..7cfe2d6 100644 --- a/src/Todl.Compiler/CodeAnalysis/Syntax/IfUnlessStatement.cs +++ b/src/Todl.Compiler/CodeAnalysis/Syntax/IfUnlessStatement.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Collections.Immutable; +using System.Collections.Immutable; using System.Linq; using Todl.Compiler.CodeAnalysis.Text; using Todl.Compiler.Diagnostics; @@ -47,14 +46,13 @@ private IfUnlessStatement ParseIfUnlessStatement() var conditionExpression = ParseExpression(); var blockStatement = ParseBlockStatement(); var elseClauses = ImmutableArray.CreateBuilder(); - var diagnosticBuilder = new DiagnosticBag.Builder(); while (Current.Kind == SyntaxKind.ElseKeywordToken) { var elseClause = ParseElseClause(); if (elseClause.IfOrUnlessToken.HasValue && elseClause.IfOrUnlessToken.Value.Kind != ifOrUnlessToken.Kind) { - diagnosticBuilder.Add(new Diagnostic() + ReportDiagnostic(new Diagnostic() { Message = "if/unless qualifier mismatch", ErrorCode = ErrorCode.IfUnlessKeywordMismatch, @@ -74,7 +72,7 @@ private IfUnlessStatement ParseIfUnlessStatement() { foreach (var b in bareElseClauses) { - diagnosticBuilder.Add(new Diagnostic() + ReportDiagnostic(new Diagnostic() { Message = "bare else clauses must be after all other else clauses", ErrorCode = ErrorCode.MisplacedBareElseClauses, @@ -88,7 +86,7 @@ private IfUnlessStatement ParseIfUnlessStatement() { foreach (var b in bareElseClauses) { - diagnosticBuilder.Add(new Diagnostic() + ReportDiagnostic(new Diagnostic() { Message = "duplicate bare else clauses", ErrorCode = ErrorCode.DuplicateBareElseClauses, @@ -105,8 +103,7 @@ private IfUnlessStatement ParseIfUnlessStatement() IfOrUnlessToken = ifOrUnlessToken, ConditionExpression = conditionExpression, BlockStatement = blockStatement, - ElseClauses = elseClauses.ToImmutable(), - DiagnosticBuilder = diagnosticBuilder + ElseClauses = elseClauses.ToImmutable() }; } diff --git a/src/Todl.Compiler/CodeAnalysis/Syntax/NewExpression.cs b/src/Todl.Compiler/CodeAnalysis/Syntax/NewExpression.cs index 5cc24fc..336e725 100644 --- a/src/Todl.Compiler/CodeAnalysis/Syntax/NewExpression.cs +++ b/src/Todl.Compiler/CodeAnalysis/Syntax/NewExpression.cs @@ -17,7 +17,6 @@ public sealed partial class Parser { private NewExpression ParseNewExpression() { - var diagnosticsBuilder = new DiagnosticBag.Builder(); var newKeywordToken = ExpectToken(SyntaxKind.NewKeywordToken); var typeNameExpression = ParseNameExpression(); var arguments = ParseCommaSeparatedSyntaxList(ParseArgument); @@ -25,7 +24,7 @@ private NewExpression ParseNewExpression() var namedArguments = arguments.Items.Where(p => p.IsNamedArgument); if (namedArguments.Any() && namedArguments.Count() != arguments.Items.Length) { - diagnosticsBuilder.Add( + ReportDiagnostic( new Diagnostic() { Message = "Either all or none of the arguments should be named arguments", @@ -40,8 +39,7 @@ private NewExpression ParseNewExpression() SyntaxTree = syntaxTree, NewKeywordToken = newKeywordToken, TypeNameExpression = typeNameExpression, - Arguments = arguments, - DiagnosticBuilder = diagnosticsBuilder + Arguments = arguments }; } } diff --git a/src/Todl.Compiler/CodeAnalysis/Syntax/Parser.cs b/src/Todl.Compiler/CodeAnalysis/Syntax/Parser.cs index 3a0477e..611dad6 100644 --- a/src/Todl.Compiler/CodeAnalysis/Syntax/Parser.cs +++ b/src/Todl.Compiler/CodeAnalysis/Syntax/Parser.cs @@ -10,6 +10,7 @@ namespace Todl.Compiler.CodeAnalysis.Syntax; public sealed partial class Parser { private readonly SyntaxTree syntaxTree; + private readonly DiagnosticBag.Builder diagnosticBuilder; private readonly ImmutableArray.Builder directives = ImmutableArray.CreateBuilder(); private readonly ImmutableArray.Builder members @@ -74,9 +75,10 @@ private SyntaxToken ExpectUntil(SyntaxKind syntaxKind, Action action) return ExpectToken(syntaxKind); } - internal Parser(SyntaxTree syntaxTree) + internal Parser(SyntaxTree syntaxTree, DiagnosticBag.Builder diagnosticBuilder) { this.syntaxTree = syntaxTree; + this.diagnosticBuilder = diagnosticBuilder; } public void Parse() @@ -166,4 +168,7 @@ private SyntaxToken ReportUnexpectedToken(SyntaxKind expectedSyntaxKind) ErrorCode = ErrorCode.UnexpectedToken }; } + + private void ReportDiagnostic(Diagnostic diagnostic) + => diagnosticBuilder.Add(diagnostic); } diff --git a/src/Todl.Compiler/CodeAnalysis/Syntax/SyntaxNode.cs b/src/Todl.Compiler/CodeAnalysis/Syntax/SyntaxNode.cs index 373309f..9ac2993 100644 --- a/src/Todl.Compiler/CodeAnalysis/Syntax/SyntaxNode.cs +++ b/src/Todl.Compiler/CodeAnalysis/Syntax/SyntaxNode.cs @@ -1,23 +1,9 @@ -using System.Collections.Generic; -using Todl.Compiler.CodeAnalysis.Text; -using Todl.Compiler.Diagnostics; +using Todl.Compiler.CodeAnalysis.Text; -namespace Todl.Compiler.CodeAnalysis.Syntax -{ - public abstract class SyntaxNode : IDiagnosable - { - public SyntaxTree SyntaxTree { get; internal init; } - public DiagnosticBag.Builder DiagnosticBuilder { get; internal init; } - public abstract TextSpan Text { get; } - - public virtual IEnumerable GetDiagnostics() - { - if (DiagnosticBuilder == null) - { - return DiagnosticBag.Empty; - } +namespace Todl.Compiler.CodeAnalysis.Syntax; - return DiagnosticBuilder.Build(); - } - } +public abstract class SyntaxNode +{ + public SyntaxTree SyntaxTree { get; internal init; } + public abstract TextSpan Text { get; } } diff --git a/src/Todl.Compiler/CodeAnalysis/Syntax/SyntaxTree.cs b/src/Todl.Compiler/CodeAnalysis/Syntax/SyntaxTree.cs index 67fd4b0..c415f20 100644 --- a/src/Todl.Compiler/CodeAnalysis/Syntax/SyntaxTree.cs +++ b/src/Todl.Compiler/CodeAnalysis/Syntax/SyntaxTree.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.Linq; using Todl.Compiler.CodeAnalysis.Text; +using Todl.Compiler.Diagnostics; namespace Todl.Compiler.CodeAnalysis.Syntax; @@ -19,10 +20,13 @@ public sealed class SyntaxTree public ImmutableArray Members => parser.Members; public ClrTypeCacheView ClrTypeCacheView { get; private set; } - internal SyntaxTree(SourceText sourceText, ClrTypeCache clrTypeCache) + internal SyntaxTree( + SourceText sourceText, + ClrTypeCache clrTypeCache, + DiagnosticBag.Builder diagnosticBuilder) { lexer = new Lexer() { SourceText = sourceText }; - parser = new Parser(this); + parser = new Parser(this, diagnosticBuilder); SourceText = sourceText; ClrTypeCache = clrTypeCache; @@ -50,23 +54,32 @@ private void Parse() ClrTypeCacheView = ClrTypeCache.CreateView(Directives.OfType()); } - public static SyntaxTree Parse(SourceText sourceText, ClrTypeCache clrTypeCache) + public static SyntaxTree Parse( + SourceText sourceText, + ClrTypeCache clrTypeCache, + DiagnosticBag.Builder diagnosticBuilder) { - var syntaxTree = new SyntaxTree(sourceText, clrTypeCache); + var syntaxTree = new SyntaxTree(sourceText, clrTypeCache, diagnosticBuilder); syntaxTree.Parse(); return syntaxTree; } // temporarily make available for tests and evaluator - internal static Expression ParseExpression(SourceText sourceText, ClrTypeCache clrTypeCache) + internal static Expression ParseExpression( + SourceText sourceText, + ClrTypeCache clrTypeCache, + DiagnosticBag.Builder diagnosticBuilder) { - var syntaxTree = new SyntaxTree(sourceText, clrTypeCache); + var syntaxTree = new SyntaxTree(sourceText, clrTypeCache, diagnosticBuilder); return syntaxTree.ParseExpression(); } - internal static Statement ParseStatement(SourceText sourceText, ClrTypeCache clrTypeCache) + internal static Statement ParseStatement( + SourceText sourceText, + ClrTypeCache clrTypeCache, + DiagnosticBag.Builder diagnosticBuilder) { - var syntaxTree = new SyntaxTree(sourceText, clrTypeCache); + var syntaxTree = new SyntaxTree(sourceText, clrTypeCache, diagnosticBuilder); return syntaxTree.ParseStatement(); } } diff --git a/src/Todl.Compiler/CodeGeneration/Compilation.cs b/src/Todl.Compiler/CodeGeneration/Compilation.cs index 47bf189..5275a24 100644 --- a/src/Todl.Compiler/CodeGeneration/Compilation.cs +++ b/src/Todl.Compiler/CodeGeneration/Compilation.cs @@ -50,7 +50,7 @@ public Compilation( ClrTypeCache = ClrTypeCache.FromAssemblies(metadataLoadContext.GetAssemblies(), metadataLoadContext.CoreAssembly); - var syntaxTrees = sourceTexts.Select(s => SyntaxTree.Parse(s, ClrTypeCache)); + var syntaxTrees = sourceTexts.Select(s => SyntaxTree.Parse(s, ClrTypeCache, diagnosticBuilder)); MainModule = BoundModule.Create(ClrTypeCache, syntaxTrees.ToImmutableList()); if (MainModule.EntryPoint is null) diff --git a/src/Todl.Compiler/Evaluation/Evaluator.cs b/src/Todl.Compiler/Evaluation/Evaluator.cs index 668285c..6521793 100644 --- a/src/Todl.Compiler/Evaluation/Evaluator.cs +++ b/src/Todl.Compiler/Evaluation/Evaluator.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Reflection; +using System.Runtime.InteropServices; using Todl.Compiler.CodeAnalysis; using Todl.Compiler.CodeAnalysis.Binding.BoundTree; using Todl.Compiler.CodeAnalysis.Symbols; @@ -12,8 +12,6 @@ namespace Todl.Compiler.Evaluation { - using Binder = CodeAnalysis.Binding.BoundTree.Binder; - /// /// An evaluator evaluates expressions and statements and give out results as output /// @@ -34,8 +32,9 @@ public Evaluator() public EvaluatorResult Evaluate(SourceText sourceText) { - var expression = SyntaxTree.ParseExpression(sourceText, clrTypeCache); - var diagnostics = expression.GetDiagnostics(); + var diagnosticBuilder = new DiagnosticBag.Builder(); + var expression = SyntaxTree.ParseExpression(sourceText, clrTypeCache, diagnosticBuilder); + var diagnostics = diagnosticBuilder.Build(); if (diagnostics.Any()) { @@ -47,7 +46,6 @@ public EvaluatorResult Evaluate(SourceText sourceText) }; } - var diagnosticBuilder = new DiagnosticBag.Builder(); var binder = Binder.CreateScriptBinder(clrTypeCache, diagnosticBuilder); var boundExpression = binder.BindExpression(expression);