so... jai :D
This commit is contained in:
96
src/errors.zig
Normal file
96
src/errors.zig
Normal file
@@ -0,0 +1,96 @@
|
||||
const std = @import("std");
|
||||
const Span = @import("ast.zig").Span;
|
||||
|
||||
pub const Level = enum {
|
||||
err,
|
||||
warn,
|
||||
note,
|
||||
};
|
||||
|
||||
pub const SourceLoc = struct {
|
||||
line: u32,
|
||||
col: u32,
|
||||
|
||||
pub fn compute(source: []const u8, byte_offset: u32) SourceLoc {
|
||||
var line: u32 = 1;
|
||||
var col: u32 = 1;
|
||||
for (source[0..byte_offset]) |c| {
|
||||
if (c == '\n') {
|
||||
line += 1;
|
||||
col = 1;
|
||||
} else {
|
||||
col += 1;
|
||||
}
|
||||
}
|
||||
return .{ .line = line, .col = col };
|
||||
}
|
||||
};
|
||||
|
||||
pub const Diagnostic = struct {
|
||||
level: Level,
|
||||
message: []const u8,
|
||||
span: ?Span,
|
||||
};
|
||||
|
||||
pub const DiagnosticList = struct {
|
||||
items: std.ArrayList(Diagnostic) = .empty,
|
||||
allocator: std.mem.Allocator,
|
||||
source: []const u8,
|
||||
file_name: []const u8,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, source: []const u8, file_name: []const u8) DiagnosticList {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.source = source,
|
||||
.file_name = file_name,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *DiagnosticList) void {
|
||||
self.items.deinit(self.allocator);
|
||||
}
|
||||
|
||||
pub fn add(self: *DiagnosticList, level: Level, message: []const u8, span: ?Span) void {
|
||||
// Deduplicate: skip if same level+span+message already exists
|
||||
for (self.items.items) |d| {
|
||||
if (d.level == level and std.mem.eql(u8, d.message, message)) {
|
||||
const a = d.span orelse continue;
|
||||
const b = span orelse continue;
|
||||
if (a.start == b.start and a.end == b.end) return;
|
||||
}
|
||||
}
|
||||
self.items.append(self.allocator, .{
|
||||
.level = level,
|
||||
.message = message,
|
||||
.span = span,
|
||||
}) catch {};
|
||||
}
|
||||
|
||||
pub fn addFmt(self: *DiagnosticList, level: Level, span: ?Span, comptime fmt: []const u8, args: anytype) void {
|
||||
const message = std.fmt.allocPrint(self.allocator, fmt, args) catch "diagnostic format error";
|
||||
self.add(level, message, span);
|
||||
}
|
||||
|
||||
pub fn hasErrors(self: *const DiagnosticList) bool {
|
||||
for (self.items.items) |d| {
|
||||
if (d.level == .err) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn render(self: *const DiagnosticList, writer: anytype) !void {
|
||||
for (self.items.items) |d| {
|
||||
const level_str = switch (d.level) {
|
||||
.err => "error",
|
||||
.warn => "warning",
|
||||
.note => "note",
|
||||
};
|
||||
if (d.span) |span| {
|
||||
const loc = SourceLoc.compute(self.source, span.start);
|
||||
try writer.print("{s}:{d}:{d}: {s}: {s}\n", .{ self.file_name, loc.line, loc.col, level_str, d.message });
|
||||
} else {
|
||||
try writer.print("{s}: {s}: {s}\n", .{ self.file_name, level_str, d.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user