const std = @import("std"); const Character = @import("character.zig").Character; const Self = @This(); charset: [256]bool = std.mem.zeroes([256]bool), pub inline fn is_set(self: *const Self, c: usize) bool { return self.charset[c]; } pub inline fn set(self: *Self, c: usize) void { self.charset[c] = true; } pub inline fn reset(self: *Self, c: usize) void { self.charset[c] = false; } pub inline fn set_if(self: *Self, c: usize, flag: bool) void { self.charset[c] = self.charset[c] or flag; } pub fn format( self: *const Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, ) !void { _ = fmt; _ = options; try writer.print("{{ ", .{}); for (self.charset, 0..) |is_first, index| { if (is_first) { if (index == Character.EPSILON) { try writer.print("{} ", .{Character { .epsilon = void{} }}); } else if (index == Character.END) { try writer.print("$ ", .{}); } else { try writer.print("'{c}' ", .{@as(u8, @truncate(index))}); } } } try writer.print("}}", .{}); } pub fn expect(self: *const Self, expected: []const u8) !void { var matrix = std.mem.zeroes([255]bool); for (expected) |c| { matrix[c] = true; } for (matrix, 0..) |contained, index| { if (self.is_set(index) != contained) { std.debug.print("expected {{ ", .{}); for (expected) |c| { if (c == Character.EPSILON) { std.debug.print("{} ", .{Character { .epsilon = void{} }}); } else if (c == Character.END) { std.debug.print("$ ", .{}); } else { std.debug.print("'{c}' ", .{c}); } } std.debug.print("}} but got {} (", .{self}); if (index == Character.EPSILON) { std.debug.print("{}", .{Character { .epsilon = void{} }}); } else if (index == Character.END) { std.debug.print("$", .{}); } else { std.debug.print("'{c}'", .{@as(u8, @truncate(index))}); } if (contained) { std.debug.print(" missing)\n", .{}); } else { std.debug.print(" not expected)\n", .{}); } return error.ExpectEqualError; } } }