diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/DiagnosticSink.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/DiagnosticSink.java index ba562483..956cfdfd 100644 --- a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/DiagnosticSink.java +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/DiagnosticSink.java @@ -1,4 +1,92 @@ package p.studio.compiler.source.diagnostics; -public class DiagnosticSink { +import p.studio.compiler.source.Span; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class DiagnosticSink extends ReadOnlyCollection { + private int errorCount = 0; + private int warningCount = 0; + + protected DiagnosticSink() { + super(new ArrayList<>()); + } + + public static DiagnosticSink empty() { + return new DiagnosticSink(); + } + + public DiagnosticSink report(final Diagnostic diagnostic) { + Objects.requireNonNull(diagnostic); + if (diagnostic.getSeverity().isError()) { + errorCount++; + } else { + warningCount++; + } + collection.add(diagnostic); + return this; + } + + public DiagnosticSink report( + final Severity severity, + final String code, + final String message, + final Span span) { + return report(severity, code, message, span, List.of()); + } + + public DiagnosticSink report( + final Severity severity, + final String code, + final String message, + final Span span, + final List related) { + return report(new Diagnostic( + Objects.requireNonNull(severity), + Objects.requireNonNull(code), + Objects.requireNonNull(message), + Objects.requireNonNull(span), + List.copyOf(Objects.requireNonNull(related)))); + } + + public DiagnosticSink error( + final String code, + final String message, + final Span span) { + return report(Severity.Error, code, message, span); + } + + public DiagnosticSink warning( + final String code, + final String message, + final Span span) { + return report(Severity.Warning, code, message, span); + } + + public DiagnosticSink merge(final DiagnosticSink diagnostics) { + Objects.requireNonNull(diagnostics); + for (final Diagnostic diagnostic : diagnostics) { + report(diagnostic); + } + return this; + } + + public boolean hasErrors() { + return errorCount > 0; + } + + public boolean hasWarnings() { + return warningCount > 0; + } + + public int errorCount() { + return errorCount; + } + + public int warningCount() { + return warningCount; + } } diff --git a/prometeu-compiler/prometeu-compiler-core/src/test/java/p/studio/compiler/source/diagnostics/DiagnosticSinkTest.java b/prometeu-compiler/prometeu-compiler-core/src/test/java/p/studio/compiler/source/diagnostics/DiagnosticSinkTest.java new file mode 100644 index 00000000..94f17fac --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/test/java/p/studio/compiler/source/diagnostics/DiagnosticSinkTest.java @@ -0,0 +1,42 @@ +package p.studio.compiler.source.diagnostics; + +import org.junit.jupiter.api.Test; +import p.studio.compiler.source.Span; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class DiagnosticSinkTest { + + @Test + void shouldReportAndCountDiagnostics() { + final var sink = DiagnosticSink.empty(); + + sink.error("E001", "Unknown symbol", Span.none()); + sink.warning("W001", "Unused declaration", Span.none()); + + assertEquals(2, sink.size()); + assertTrue(sink.hasErrors()); + assertTrue(sink.hasWarnings()); + assertEquals(1, sink.errorCount()); + assertEquals(1, sink.warningCount()); + } + + @Test + void shouldMergeDiagnostics() { + final var a = DiagnosticSink.empty() + .warning("W010", "Unused import", Span.none()); + final var b = DiagnosticSink.empty() + .error("E999", "Invalid type", Span.none()); + + a.merge(b); + + assertEquals(2, a.size()); + assertTrue(a.hasErrors()); + assertTrue(a.hasWarnings()); + assertEquals(1, a.errorCount()); + assertEquals(1, a.warningCount()); + assertEquals(1, b.errorCount()); + assertEquals(0, b.warningCount()); + } +}