You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
3.1 KiB
100 lines
3.1 KiB
const std = @import("std"); |
|
const Allocator = std.mem.Allocator; |
|
|
|
const Error = @import("./error.zig").Error; |
|
const Trap = @import("./trap.zig").Trap; |
|
const TrapCode = @import("./trap.zig").TrapCode; |
|
const TrapError = @import("./trap.zig").TrapError; |
|
|
|
pub const ExitStatus = c_int; |
|
|
|
pub const ErrorUnion = union(enum) { |
|
none: void, |
|
err: ?ExitStatus, |
|
trap: ?TrapCode, |
|
}; |
|
|
|
pub const Diagnostics = struct { |
|
allocator: Allocator, |
|
debug_print: bool, |
|
data: ErrorUnion = .{ .none = {} }, |
|
message: ?[]const u8 = null, |
|
|
|
pub fn init(allocator: Allocator, debug_print: bool) !*Diagnostics { |
|
var result = try allocator.create(Diagnostics); |
|
result.* = .{ .allocator = allocator, .debug_print = debug_print }; |
|
return result; |
|
} |
|
|
|
pub fn clear(self: *Diagnostics) void { |
|
if (self.message) |msg| self.allocator.free(msg); |
|
self.data = .{ .none = {} }; |
|
self.message = null; |
|
} |
|
|
|
pub fn deinit(self: *Diagnostics) void { |
|
if (self.message) |msg| self.allocator.free(msg); |
|
self.allocator.destroy(self); |
|
} |
|
|
|
pub fn handleError( |
|
err: ?*Error, |
|
err_enum: anyerror, |
|
result: anytype, |
|
diag: ?*Diagnostics, |
|
) @TypeOf(err_enum)!@TypeOf(result) { |
|
if (err) |e| { |
|
defer e.deinit(); |
|
if (diag) |d| { |
|
var msg = e.getMessage(); |
|
defer msg.deinit(); |
|
// If the message ends with NUL byte, don't include it. |
|
const size = if (msg.data[msg.size - 1] == 0) msg.size - 1 else msg.size; |
|
d.data = .{ .err = e.getExitStatus() }; |
|
d.message = try d.allocator.alloc(u8, size); |
|
@memcpy(@constCast(d.message.?), msg.data); |
|
if (d.debug_print) std.debug.print("{s}\n", .{d.message.?}); |
|
} |
|
return err_enum; |
|
} else { |
|
if (diag) |d| d.clear(); |
|
return result; |
|
} |
|
} |
|
|
|
pub fn handleTrap( |
|
trap: ?*Trap, |
|
result: anytype, |
|
diag: ?*Diagnostics, |
|
) !@TypeOf(result) { |
|
if (trap) |t| { |
|
defer t.deinit(); |
|
const code = t.getTrapCode(); |
|
if (diag) |d| { |
|
var msg = t.getMessage(); |
|
defer msg.deinit(); |
|
// If the message ends with NUL byte, don't include it. |
|
const size = if (msg.data[msg.size - 1] == 0) msg.size - 1 else msg.size; |
|
d.data = .{ .trap = code }; |
|
d.message = try d.allocator.alloc(u8, size); |
|
@memcpy(@constCast(d.message.?), msg.data); |
|
if (d.debug_print) std.debug.print("{s}\n", .{d.message.?}); |
|
} |
|
return if (code) |c| c.toError() else TrapError.UnknownTrap; |
|
} else { |
|
if (diag) |d| d.clear(); |
|
return result; |
|
} |
|
} |
|
|
|
pub fn handleErrorOrTrap( |
|
err: ?*Error, |
|
err_enum: anyerror, |
|
trap: ?*Trap, |
|
result: anytype, |
|
diag: ?*Diagnostics, |
|
) !@TypeOf(result) { |
|
try handleError(err, err_enum, {}, diag); |
|
return try handleTrap(trap, result, diag); |
|
} |
|
};
|
|
|