aboutsummaryrefslogtreecommitdiff
path: root/lib/compiler/resinator/utils.zig
blob: b535ab9c713abb3504b7e23575c3931e6c2f045b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
const std = @import("std");
const builtin = @import("builtin");

pub const UncheckedSliceWriter = struct {
    const Self = @This();

    pos: usize = 0,
    slice: []u8,

    pub fn write(self: *Self, char: u8) void {
        self.slice[self.pos] = char;
        self.pos += 1;
    }

    pub fn writeSlice(self: *Self, slice: []const u8) void {
        for (slice) |c| {
            self.write(c);
        }
    }

    pub fn getWritten(self: Self) []u8 {
        return self.slice[0..self.pos];
    }
};

/// Cross-platform 'std.fs.Dir.openFile' wrapper that will always return IsDir if
/// a directory is attempted to be opened.
/// TODO: Remove once https://github.com/ziglang/zig/issues/5732 is addressed.
pub fn openFileNotDir(cwd: std.fs.Dir, path: []const u8, flags: std.fs.File.OpenFlags) std.fs.File.OpenError!std.fs.File {
    const file = try cwd.openFile(path, flags);
    errdefer file.close();
    // https://github.com/ziglang/zig/issues/5732
    if (builtin.os.tag != .windows) {
        const stat = try file.stat();

        if (stat.kind == .directory)
            return error.IsDir;
    }
    return file;
}

/// Emulates the Windows implementation of `iswdigit`, but only returns true
/// for the non-ASCII digits that `iswdigit` on Windows would return true for.
pub fn isNonAsciiDigit(c: u21) bool {
    return switch (c) {
        '²',
        '³',
        '¹',
        '\u{660}'...'\u{669}',
        '\u{6F0}'...'\u{6F9}',
        '\u{7C0}'...'\u{7C9}',
        '\u{966}'...'\u{96F}',
        '\u{9E6}'...'\u{9EF}',
        '\u{A66}'...'\u{A6F}',
        '\u{AE6}'...'\u{AEF}',
        '\u{B66}'...'\u{B6F}',
        '\u{BE6}'...'\u{BEF}',
        '\u{C66}'...'\u{C6F}',
        '\u{CE6}'...'\u{CEF}',
        '\u{D66}'...'\u{D6F}',
        '\u{E50}'...'\u{E59}',
        '\u{ED0}'...'\u{ED9}',
        '\u{F20}'...'\u{F29}',
        '\u{1040}'...'\u{1049}',
        '\u{1090}'...'\u{1099}',
        '\u{17E0}'...'\u{17E9}',
        '\u{1810}'...'\u{1819}',
        '\u{1946}'...'\u{194F}',
        '\u{19D0}'...'\u{19D9}',
        '\u{1B50}'...'\u{1B59}',
        '\u{1BB0}'...'\u{1BB9}',
        '\u{1C40}'...'\u{1C49}',
        '\u{1C50}'...'\u{1C59}',
        '\u{A620}'...'\u{A629}',
        '\u{A8D0}'...'\u{A8D9}',
        '\u{A900}'...'\u{A909}',
        '\u{AA50}'...'\u{AA59}',
        '\u{FF10}'...'\u{FF19}',
        => true,
        else => false,
    };
}

pub const ErrorMessageType = enum { err, warning, note };

/// Used for generic colored errors/warnings/notes, more context-specific error messages
/// are handled elsewhere.
pub fn renderErrorMessage(writer: *std.Io.Writer, config: std.Io.tty.Config, msg_type: ErrorMessageType, comptime format: []const u8, args: anytype) !void {
    switch (msg_type) {
        .err => {
            try config.setColor(writer, .bold);
            try config.setColor(writer, .red);
            try writer.writeAll("error: ");
        },
        .warning => {
            try config.setColor(writer, .bold);
            try config.setColor(writer, .yellow);
            try writer.writeAll("warning: ");
        },
        .note => {
            try config.setColor(writer, .reset);
            try config.setColor(writer, .cyan);
            try writer.writeAll("note: ");
        },
    }
    try config.setColor(writer, .reset);
    if (msg_type == .err) {
        try config.setColor(writer, .bold);
    }
    try writer.print(format, args);
    try writer.writeByte('\n');
    try config.setColor(writer, .reset);
}

pub fn isLineEndingPair(first: u8, second: u8) bool {
    if (first != '\r' and first != '\n') return false;
    if (second != '\r' and second != '\n') return false;

    // can't be \n\n or \r\r
    if (first == second) return false;

    return true;
}