From 6f03e2203f7027cf62c9bd331f86f172bf83b012 Mon Sep 17 00:00:00 2001 From: Oliver Stene Date: Sun, 8 Feb 2026 19:35:03 +0100 Subject: [PATCH] diagnostic --- compiler/Compiler/Diagnostic.cs | 77 +++++++++++++++++++++++++++++++++ compiler/Compiler/Program.cs | 41 ++---------------- compiler/Compiler/test.nub | 32 ++++++++++++++ 3 files changed, 113 insertions(+), 37 deletions(-) create mode 100644 compiler/Compiler/test.nub diff --git a/compiler/Compiler/Diagnostic.cs b/compiler/Compiler/Diagnostic.cs index 5b976c6..5ed6891 100644 --- a/compiler/Compiler/Diagnostic.cs +++ b/compiler/Compiler/Diagnostic.cs @@ -74,4 +74,81 @@ public enum DiagnosticSeverity public sealed class CompileException(Diagnostic diagnostic) : Exception { public readonly Diagnostic Diagnostic = diagnostic; +} + +public static class DiagnosticFormatter +{ + public static void Print(Diagnostic diagnostic, TextWriter writer) + { + var (label, color) = diagnostic.Severity switch + { + DiagnosticSeverity.Info => ("info", Ansi.Cyan), + DiagnosticSeverity.Warning => ("warning", Ansi.Yellow), + DiagnosticSeverity.Error => ("error", Ansi.Red), + _ => ("unknown", Ansi.Reset), + }; + + writer.Write(color); + writer.Write(label); + writer.Write(Ansi.Reset); + writer.Write(": "); + writer.WriteLine(diagnostic.Message); + + if (diagnostic.File is null) + return; + + var file = diagnostic.File; + var lineNumberWidth = diagnostic.File.Line.ToString().Length; + + writer.WriteLine($" {new string(' ', lineNumberWidth)}{file.File}:{file.Line}:{file.Column}"); + writer.WriteLine($"{new string(' ', lineNumberWidth)} | "); + + var sourceLine = TryReadLine(file.File, file.Line); + if (sourceLine != null) + { + writer.Write($"{file.Line.ToString().PadLeft(lineNumberWidth)} | "); + writer.WriteLine(sourceLine); + + writer.Write(new string(' ', lineNumberWidth)); + writer.Write(" | "); + writer.Write(new string(' ', file.Column - 1)); + writer.Write(color); + writer.Write(new string('^', Math.Max(1, file.Length))); + writer.WriteLine(Ansi.Reset); + } + + writer.WriteLine($"{new string(' ', lineNumberWidth)} |"); + + if (!string.IsNullOrWhiteSpace(diagnostic.Help)) + { + writer.WriteLine($" = help: {diagnostic.Help}"); + } + } + + private static string? TryReadLine(string file, int line) + { + try + { + using var reader = new StreamReader(file); + for (var i = 1; i < line; i++) + { + if (reader.ReadLine() == null) + return null; + } + + return reader.ReadLine(); + } + catch + { + return null; + } + } + + private static class Ansi + { + public const string Reset = "\e[0m"; + public const string Red = "\e[31m"; + public const string Yellow = "\e[33m"; + public const string Cyan = "\e[36m"; + } } \ No newline at end of file diff --git a/compiler/Compiler/Program.cs b/compiler/Compiler/Program.cs index a3781dd..c81f58e 100644 --- a/compiler/Compiler/Program.cs +++ b/compiler/Compiler/Program.cs @@ -1,45 +1,12 @@ using Compiler; -const string contents = """ - struct person { - age: i32 - name: string - } +var file = File.ReadAllText("test.nub"); - func main(: i32 { - let x: i32 = 23 - x = 24 - - if true { - x = 49 - } else { - x = 3 - } - - let i: i32 = 0 - - x = 1 + 2 * 34 - - while i < 10 { - i = i + 1 - x = i - } - - let me: person = struct person { age = 21 name = "Oliver" } - - do_something(me.name) - return x - } - - func do_something(text: string): void { - } - """; - -var tokens = Tokenizer.Tokenize("test.nub", contents, out var tokenizerDiagnostics); +var tokens = Tokenizer.Tokenize("test.nub", file, out var tokenizerDiagnostics); foreach (var diagnostic in tokenizerDiagnostics) { - Console.WriteLine(diagnostic.Message); + DiagnosticFormatter.Print(diagnostic, Console.Error); } if (tokenizerDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) @@ -51,7 +18,7 @@ var nodes = Parser.Parse("test.nub", tokens, out var parserDiagnostics); foreach (var diagnostic in parserDiagnostics) { - Console.WriteLine(diagnostic.Message); + DiagnosticFormatter.Print(diagnostic, Console.Error); } if (parserDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) diff --git a/compiler/Compiler/test.nub b/compiler/Compiler/test.nub new file mode 100644 index 0000000..fa400d3 --- /dev/null +++ b/compiler/Compiler/test.nub @@ -0,0 +1,32 @@ +struct person { + age: i32 + name: string +} + +func main(): i32 { + let x: i32 = 23 + x = 24 + + if true { + x = 49 + } else { + x = 3 + } + + let i: i32 = 0 + + x = 1 + 2 * 34 + + while i < 10 { + i = i + 1 + x = i + } + + let me: person = struct person { age = 21 name = "Oliver" } + + do_something(me.name) + return x +} + +func do_something(text: string): void { +} \ No newline at end of file