From 6a5fce18fea83362743a5a50e1d18e903b602a76 Mon Sep 17 00:00:00 2001 From: Mikkel Troels Kongsted Date: Thu, 23 Jan 2025 13:58:07 +0100 Subject: [PATCH] pretty report printing --- compiler/ctx.ts | 22 ++++++++++++++++- compiler/diagnostics.ts | 47 +++++++++++++++++++++++++++++++++--- compiler/test_diagnostics.ts | 41 +++++++++++++++++++++++++++++-- 3 files changed, 104 insertions(+), 6 deletions(-) diff --git a/compiler/ctx.ts b/compiler/ctx.ts index 001378c..74d9311 100644 --- a/compiler/ctx.ts +++ b/compiler/ctx.ts @@ -1,5 +1,5 @@ import * as ast from "./ast/mod.ts"; -import { prettyPrintReport, printStackTrace, Report } from "./diagnostics.ts"; +import { Pos, prettyPrintReport, printStackTrace, Report, Span } from "./diagnostics.ts"; export class Ctx { private fileIds = new Ids(); @@ -43,6 +43,26 @@ export class Ctx { return this.files.get(id(file))!; } + public filePosLineText(file: File, pos: Pos): string { + const fileTextLines = this.fileInfo(file).text.split("\n") + return fileTextLines[pos.line-1] + } + + public fileSpanText(file: File, span: Span): string { + let result = "" + const fileTextLines = this.fileInfo(file).text.split("\n") + + for(let i = 0; i < fileTextLines.length; i++) { + if (i > span.end.line-1) { + break; + } + if (i >= span.begin.line-1) { + result += fileTextLines[i] + "\n"; + } + } + return result + } + public report(rep: Report) { this.reports.push(rep); this.reportImmediately(rep); diff --git a/compiler/diagnostics.ts b/compiler/diagnostics.ts index 6170397..8c7f9d7 100644 --- a/compiler/diagnostics.ts +++ b/compiler/diagnostics.ts @@ -1,4 +1,5 @@ import { Ctx, File } from "./ctx.ts"; +import { exhausted } from "./util.ts"; export type Span = { begin: Pos; @@ -20,14 +21,54 @@ export type Report = { pos?: Pos; }; +function severityColor(severity: "fatal" | "error" | "warning" | "info") { + switch (severity) { + case "fatal": + return "\x1b[1m\x1b[31m"; + case "error": + return "\x1b[1m\x1b[31m"; + case "warning": + return "\x1b[1m\x1b[33m"; + case "info": + return "\x1b[1m\x1b[34m"; + } + exhausted(severity) +} + export function prettyPrintReport(ctx: Ctx, rep: Report) { const { severity, msg } = rep; - const origin = rep.origin ? `${rep.origin}: ` : ""; - console.error(`${origin}${severity}: ${msg}`); + const origin = rep.origin ? `\x1b[1m${rep.origin}:\x1b[0m ` : ""; + console.error(`${origin}${severityColor(severity)}${severity}:\x1b[0m \x1b[37m${msg}\x1b[0m`); if (rep.file && (rep.span || rep.pos)) { + const errorLineOffset = 2 const { absPath: path } = ctx.fileInfo(rep.file); const { line, col } = rep.span?.begin ?? rep.pos!; - console.error(` at ./${path}:${line}:${col}`); + console.error(` --> ./${path}:${line}:${col}`); + if (rep.span) { + const spanLines = ctx.fileSpanText(rep.file, rep.span).split("\n"); + spanLines.pop() + if (spanLines.length == 1) { + console.error(`${rep.span.begin.line.toString().padStart(4, ' ')}| ${spanLines[0]}`); + console.error(` | ${severityColor(severity)}${" ".repeat(rep.span.begin.col)}${"~".repeat(rep.span.end.col-rep.span.begin.col)}\x1b[0m`) + return + } + for (let i = 0; i < spanLines.length; i++) { + console.error(`${(rep.span.begin.line+i).toString().padStart(4, ' ')}| ${spanLines[i]}`); + if (i == 0) { + console.error(` | ${" ".repeat(rep.span.begin.col-1)}${severityColor(severity)}${"~".repeat(spanLines[i].length-(rep.span.begin.col-1))}\x1b[0m`) + } + else if (i == spanLines.length-1) { + console.error(` | ${severityColor(severity)}${"~".repeat(rep.span.end.col)}\x1b[0m`) + } + else { + console.error(` | ${severityColor(severity)}${"~".repeat(spanLines[i].length)}\x1b[0m`) + } + } + } + else if (rep.pos) { + console.error(`${rep.pos.line.toString().padStart(4, ' ')}| ${ctx.filePosLineText(rep.file, rep.pos)}`); + console.error(` | ${severityColor(severity)}${" ".repeat(rep.pos.col)}^\x1b[0m`) + } } } diff --git a/compiler/test_diagnostics.ts b/compiler/test_diagnostics.ts index 8b0bfd9..fb7d7dc 100644 --- a/compiler/test_diagnostics.ts +++ b/compiler/test_diagnostics.ts @@ -7,6 +7,14 @@ const text = ` make an error here `; +const biggerText = ` +dont make error here +not here but start error here +and here +also here but not here +or here +` + const file = ctx.addFile( "root", "path/file.ts", @@ -15,13 +23,42 @@ const file = ctx.addFile( text, ); +const biggerFile = ctx.addFile( + "root", + "path/file.ts", + "path/file.ts", + undefined, + biggerText, +); + prettyPrintReport(ctx, { file, msg: "an error", + severity: "fatal", + origin: "compiler", + span: { + begin: { idx: 5, line: 2, col: 5 }, + end: { idx: 13, line: 2, col: 13 }, + }, +}); + +prettyPrintReport(ctx, { + file: biggerFile, + msg: "an error", severity: "error", origin: "compiler", span: { - begin: { idx: 6, line: 2, col: 6 }, - end: { idx: 13, line: 2, col: 13 }, + begin: { idx: 6, line: 3, col: 14 }, + end: { idx: 13, line: 5, col: 13 }, + }, +}); + +prettyPrintReport(ctx, { + file, + msg: "an error", + severity: "warning", + origin: "compiler", + pos: { + idx: 6, line: 2, col: 8 }, });