diagnostic
This commit is contained in:
@@ -75,3 +75,80 @@ public sealed class CompileException(Diagnostic diagnostic) : Exception
|
|||||||
{
|
{
|
||||||
public readonly Diagnostic Diagnostic = diagnostic;
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +1,12 @@
|
|||||||
using Compiler;
|
using Compiler;
|
||||||
|
|
||||||
const string contents = """
|
var file = File.ReadAllText("test.nub");
|
||||||
struct person {
|
|
||||||
age: i32
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
func main(: i32 {
|
var tokens = Tokenizer.Tokenize("test.nub", file, out var tokenizerDiagnostics);
|
||||||
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);
|
|
||||||
|
|
||||||
foreach (var diagnostic in tokenizerDiagnostics)
|
foreach (var diagnostic in tokenizerDiagnostics)
|
||||||
{
|
{
|
||||||
Console.WriteLine(diagnostic.Message);
|
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenizerDiagnostics.Any(x => x.Severity == DiagnosticSeverity.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)
|
foreach (var diagnostic in parserDiagnostics)
|
||||||
{
|
{
|
||||||
Console.WriteLine(diagnostic.Message);
|
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parserDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
if (parserDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||||
|
|||||||
32
compiler/Compiler/test.nub
Normal file
32
compiler/Compiler/test.nub
Normal file
@@ -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 {
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user