authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2023-10-18 18:00:50-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2023-10-18 18:30:32-07:00
log81a61c8ecd7a970dc96a6068cf8587fd81ebd6e4
tree5f01df7d4b47a48bd25e505457a4fd0cf51d41b6
parent32bc077672cc3d7c468b4531c52d160ee12fb89f

Sync resinator with upstream and fix INCLUDE env var handling

The INCLUDE variable being used during `.rc` preprocessing was an accidental regression in https://github.com/ziglang/zig/pull/17412. Closes #17585. resinator changes: source_mapping: Protect against NUL bytes in #line filenames lex: Avoid recalculating column on every tab stop within string literals Proper error handling for failing to open cwd instead of `catch unreachable` Use platform-specific delimiter for INCLUDE env var parsing

8 files changed, 119 insertions(+), 78 deletions(-)

src/Compilation.zig+4
...@@ -4755,6 +4755,10 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -4755,6 +4755,10 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
4755 };4755 };
4756 defer options.deinit();4756 defer options.deinit();
47574757
4758 // We never want to read the INCLUDE environment variable, so
4759 // unconditionally set `ignore_include_env_var` to true
4760 options.ignore_include_env_var = true;
4761
4758 var argv = std.ArrayList([]const u8).init(comp.gpa);4762 var argv = std.ArrayList([]const u8).init(comp.gpa);
4759 defer argv.deinit();4763 defer argv.deinit();
47604764
src/introspect.zig-2
...@@ -157,8 +157,6 @@ pub const EnvVar = enum {...@@ -157,8 +157,6 @@ pub const EnvVar = enum {
157 NO_COLOR,157 NO_COLOR,
158 XDG_CACHE_HOME,158 XDG_CACHE_HOME,
159 HOME,159 HOME,
160 /// https://github.com/ziglang/zig/issues/17585
161 INCLUDE,
162160
163 pub fn isSet(comptime ev: EnvVar) bool {161 pub fn isSet(comptime ev: EnvVar) bool {
164 return std.process.hasEnvVarConstant(@tagName(ev));162 return std.process.hasEnvVarConstant(@tagName(ev));
src/resinator/compile.zig+25-8
...@@ -28,7 +28,6 @@ const windows1252 = @import("windows1252.zig");...@@ -28,7 +28,6 @@ const windows1252 = @import("windows1252.zig");
28const lang = @import("lang.zig");28const lang = @import("lang.zig");
29const code_pages = @import("code_pages.zig");29const code_pages = @import("code_pages.zig");
30const errors = @import("errors.zig");30const errors = @import("errors.zig");
31const introspect = @import("../introspect.zig");
3231
33pub const CompileOptions = struct {32pub const CompileOptions = struct {
34 cwd: std.fs.Dir,33 cwd: std.fs.Dir,
...@@ -89,10 +88,23 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option...@@ -89,10 +88,23 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option
89 }88 }
90 }89 }
91 // Re-open the passed in cwd since we want to be able to close it (std.fs.cwd() shouldn't be closed)90 // Re-open the passed in cwd since we want to be able to close it (std.fs.cwd() shouldn't be closed)
92 // `catch unreachable` since `options.cwd` is expected to be a valid dir handle, so opening91 const cwd_dir = options.cwd.openDir(".", .{}) catch |err| {
93 // a new handle to it should be fine as well.92 try options.diagnostics.append(.{
94 // TODO: Maybe catch and return an error instead93 .err = .failed_to_open_cwd,
95 const cwd_dir = options.cwd.openDir(".", .{}) catch @panic("unable to open dir");94 .token = .{
95 .id = .invalid,
96 .start = 0,
97 .end = 0,
98 .line_number = 1,
99 },
100 .print_source_line = false,
101 .extra = .{ .file_open_error = .{
102 .err = ErrorDetails.FileOpenError.enumFromError(err),
103 .filename_string_index = undefined,
104 } },
105 });
106 return error.CompileError;
107 };
96 try search_dirs.append(.{ .dir = cwd_dir, .path = null });108 try search_dirs.append(.{ .dir = cwd_dir, .path = null });
97 for (options.extra_include_paths) |extra_include_path| {109 for (options.extra_include_paths) |extra_include_path| {
98 var dir = openSearchPathDir(options.cwd, extra_include_path) catch {110 var dir = openSearchPathDir(options.cwd, extra_include_path) catch {
...@@ -111,11 +123,16 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option...@@ -111,11 +123,16 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option
111 try search_dirs.append(.{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });123 try search_dirs.append(.{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });
112 }124 }
113 if (!options.ignore_include_env_var) {125 if (!options.ignore_include_env_var) {
114 const INCLUDE = (introspect.EnvVar.INCLUDE.get(allocator) catch @panic("OOM")) orelse "";126 const INCLUDE = std.process.getEnvVarOwned(allocator, "INCLUDE") catch "";
115 defer allocator.free(INCLUDE);127 defer allocator.free(INCLUDE);
116128
117 // TODO: Should this be platform-specific? How does windres/llvm-rc handle this (if at all)?129 // The only precedence here is llvm-rc which also uses the platform-specific
118 var it = std.mem.tokenize(u8, INCLUDE, ";");130 // delimiter. There's no precedence set by `rc.exe` since it's Windows-only.
131 const delimiter = switch (builtin.os.tag) {
132 .windows => ';',
133 else => ':',
134 };
135 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);
119 while (it.next()) |search_path| {136 while (it.next()) |search_path| {
120 var dir = openSearchPathDir(options.cwd, search_path) catch continue;137 var dir = openSearchPathDir(options.cwd, search_path) catch continue;
121 errdefer dir.close();138 errdefer dir.close();
src/resinator/errors.zig+22-9
...@@ -395,6 +395,10 @@ pub const ErrorDetails = struct {...@@ -395,6 +395,10 @@ pub const ErrorDetails = struct {
395 // General (used in various places)395 // General (used in various places)
396 /// `number` is populated and contains the value that the ordinal would have in the Win32 RC compiler implementation396 /// `number` is populated and contains the value that the ordinal would have in the Win32 RC compiler implementation
397 win32_non_ascii_ordinal,397 win32_non_ascii_ordinal,
398
399 // Initialization
400 /// `file_open_error` is populated, but `filename_string_index` is not
401 failed_to_open_cwd,
398 };402 };
399403
400 pub fn render(self: ErrorDetails, writer: anytype, source: []const u8, strings: []const []const u8) !void {404 pub fn render(self: ErrorDetails, writer: anytype, source: []const u8, strings: []const []const u8) !void {
...@@ -766,6 +770,9 @@ pub const ErrorDetails = struct {...@@ -766,6 +770,9 @@ pub const ErrorDetails = struct {
766 .note => return writer.print("the Win32 RC compiler would accept this as an ordinal but its value would be {}", .{self.extra.number}),770 .note => return writer.print("the Win32 RC compiler would accept this as an ordinal but its value would be {}", .{self.extra.number}),
767 .hint => return,771 .hint => return,
768 },772 },
773 .failed_to_open_cwd => {
774 try writer.print("failed to open CWD for compilation: {s}", .{@tagName(self.extra.file_open_error.err)});
775 },
769 }776 }
770 }777 }
771778
...@@ -804,7 +811,8 @@ pub const ErrorDetails = struct {...@@ -804,7 +811,8 @@ pub const ErrorDetails = struct {
804 .point_offset = self.token.start - source_line_start,811 .point_offset = self.token.start - source_line_start,
805 .after_len = after: {812 .after_len = after: {
806 const end = @min(source_line_end, if (self.token_span_end) |span_end| span_end.end else self.token.end);813 const end = @min(source_line_end, if (self.token_span_end) |span_end| span_end.end else self.token.end);
807 if (end == self.token.start) break :after 0;814 // end may be less than start when pointing to EOF
815 if (end <= self.token.start) break :after 0;
808 break :after end - self.token.start - 1;816 break :after end - self.token.start - 1;
809 },817 },
810 },818 },
...@@ -816,13 +824,18 @@ pub fn renderErrorMessage(allocator: std.mem.Allocator, writer: anytype, tty_con...@@ -816,13 +824,18 @@ pub fn renderErrorMessage(allocator: std.mem.Allocator, writer: anytype, tty_con
816 if (err_details.type == .hint) return;824 if (err_details.type == .hint) return;
817825
818 const source_line_start = err_details.token.getLineStart(source);826 const source_line_start = err_details.token.getLineStart(source);
819 const column = err_details.token.calculateColumn(source, 1, source_line_start);827 // Treat tab stops as 1 column wide for error display purposes,
820828 // and add one to get a 1-based column
821 // var counting_writer_container = std.io.countingWriter(writer);829 const column = err_details.token.calculateColumn(source, 1, source_line_start) + 1;
822 // const counting_writer = counting_writer_container.writer();830
823831 const corresponding_span: ?SourceMappings.SourceSpan = if (source_mappings != null and source_mappings.?.has(err_details.token.line_number))
824 const corresponding_span: ?SourceMappings.SourceSpan = if (source_mappings) |mappings| mappings.get(err_details.token.line_number) else null;832 source_mappings.?.get(err_details.token.line_number)
825 const corresponding_file: ?[]const u8 = if (source_mappings) |mappings| mappings.files.get(corresponding_span.?.filename_offset) else null;833 else
834 null;
835 const corresponding_file: ?[]const u8 = if (source_mappings != null and corresponding_span != null)
836 source_mappings.?.files.get(corresponding_span.?.filename_offset)
837 else
838 null;
826839
827 const err_line = if (corresponding_span) |span| span.start_line else err_details.token.line_number;840 const err_line = if (corresponding_span) |span| span.start_line else err_details.token.line_number;
828841
...@@ -897,7 +910,7 @@ pub fn renderErrorMessage(allocator: std.mem.Allocator, writer: anytype, tty_con...@@ -897,7 +910,7 @@ pub fn renderErrorMessage(allocator: std.mem.Allocator, writer: anytype, tty_con
897 try writer.writeByte('\n');910 try writer.writeByte('\n');
898 try tty_config.setColor(writer, .reset);911 try tty_config.setColor(writer, .reset);
899912
900 if (source_mappings) |_| {913 if (corresponding_span != null and corresponding_file != null) {
901 var corresponding_lines = try CorrespondingLines.init(allocator, cwd, err_details, source_line_for_display_buf.items, corresponding_span.?, corresponding_file.?);914 var corresponding_lines = try CorrespondingLines.init(allocator, cwd, err_details, source_line_for_display_buf.items, corresponding_span.?, corresponding_file.?);
902 defer corresponding_lines.deinit(allocator);915 defer corresponding_lines.deinit(allocator);
903916
src/resinator/lex.zig+48-54
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
66
7const std = @import("std");7const std = @import("std");
8const ErrorDetails = @import("errors.zig").ErrorDetails;8const ErrorDetails = @import("errors.zig").ErrorDetails;
9const columnsUntilTabStop = @import("literals.zig").columnsUntilTabStop;9const columnWidth = @import("literals.zig").columnWidth;
10const code_pages = @import("code_pages.zig");10const code_pages = @import("code_pages.zig");
11const CodePage = code_pages.CodePage;11const CodePage = code_pages.CodePage;
12const SourceMappings = @import("source_mapping.zig").SourceMappings;12const SourceMappings = @import("source_mapping.zig").SourceMappings;
...@@ -69,17 +69,14 @@ pub const Token = struct {...@@ -69,17 +69,14 @@ pub const Token = struct {
69 };69 };
70 }70 }
7171
72 /// Returns 0-based column
72 pub fn calculateColumn(token: Token, source: []const u8, tab_columns: usize, maybe_line_start: ?usize) usize {73 pub fn calculateColumn(token: Token, source: []const u8, tab_columns: usize, maybe_line_start: ?usize) usize {
73 const line_start = maybe_line_start orelse token.getLineStart(source);74 const line_start = maybe_line_start orelse token.getLineStart(source);
7475
75 var i: usize = line_start;76 var i: usize = line_start;
76 var column: usize = 0;77 var column: usize = 0;
77 while (i < token.start) : (i += 1) {78 while (i < token.start) : (i += 1) {
78 const c = source[i];79 column += columnWidth(column, source[i], tab_columns);
79 switch (c) {
80 '\t' => column += columnsUntilTabStop(column, tab_columns),
81 else => column += 1,
82 }
83 }80 }
84 return column;81 return column;
85 }82 }
...@@ -109,6 +106,7 @@ pub const Token = struct {...@@ -109,6 +106,7 @@ pub const Token = struct {
109 const line_start = maybe_line_start orelse token.getLineStart(source);106 const line_start = maybe_line_start orelse token.getLineStart(source);
110107
111 var line_end = line_start + 1;108 var line_end = line_start + 1;
109 if (line_end >= source.len or source[line_end] == '\n') return source[line_start..line_start];
112 while (line_end < source.len and source[line_end] != '\n') : (line_end += 1) {}110 while (line_end < source.len and source[line_end] != '\n') : (line_end += 1) {}
113 while (line_end > 0 and source[line_end - 1] == '\r') : (line_end -= 1) {}111 while (line_end > 0 and source[line_end - 1] == '\r') : (line_end -= 1) {}
114112
...@@ -404,6 +402,9 @@ pub const Lexer = struct {...@@ -404,6 +402,9 @@ pub const Lexer = struct {
404 // TODO: Understand this more, bring it more in line with how the Win32 limits work.402 // TODO: Understand this more, bring it more in line with how the Win32 limits work.
405 // Alternatively, do something that makes more sense but may be more permissive.403 // Alternatively, do something that makes more sense but may be more permissive.
406 var string_literal_length: usize = 0;404 var string_literal_length: usize = 0;
405 // Keeping track of the string literal column prevents pathological edge cases when
406 // there are tons of tab stop characters within a string literal.
407 var string_literal_column: usize = 0;
407 var string_literal_collapsing_whitespace: bool = false;408 var string_literal_collapsing_whitespace: bool = false;
408 var still_could_have_exponent: bool = true;409 var still_could_have_exponent: bool = true;
409 var exponent_index: ?usize = null;410 var exponent_index: ?usize = null;
...@@ -471,6 +472,14 @@ pub const Lexer = struct {...@@ -471,6 +472,14 @@ pub const Lexer = struct {
471 self.at_start_of_line = false;472 self.at_start_of_line = false;
472 string_literal_collapsing_whitespace = false;473 string_literal_collapsing_whitespace = false;
473 string_literal_length = 0;474 string_literal_length = 0;
475
476 var dummy_token = Token{
477 .start = self.index,
478 .end = self.index,
479 .line_number = self.line_handler.line_number,
480 .id = .invalid,
481 };
482 string_literal_column = dummy_token.calculateColumn(self.buffer, 8, null);
474 },483 },
475 '+', '&', '|' => {484 '+', '&', '|' => {
476 self.index += 1;485 self.index += 1;
...@@ -618,6 +627,14 @@ pub const Lexer = struct {...@@ -618,6 +627,14 @@ pub const Lexer = struct {
618 state = .quoted_wide_string;627 state = .quoted_wide_string;
619 string_literal_collapsing_whitespace = false;628 string_literal_collapsing_whitespace = false;
620 string_literal_length = 0;629 string_literal_length = 0;
630
631 var dummy_token = Token{
632 .start = self.index,
633 .end = self.index,
634 .line_number = self.line_handler.line_number,
635 .id = .invalid,
636 };
637 string_literal_column = dummy_token.calculateColumn(self.buffer, 8, null);
621 },638 },
622 else => {639 else => {
623 state = .literal;640 state = .literal;
...@@ -695,18 +712,23 @@ pub const Lexer = struct {...@@ -695,18 +712,23 @@ pub const Lexer = struct {
695 },712 },
696 .quoted_ascii_string, .quoted_wide_string => switch (c) {713 .quoted_ascii_string, .quoted_wide_string => switch (c) {
697 '"' => {714 '"' => {
715 string_literal_column += 1;
698 state = if (state == .quoted_ascii_string) .quoted_ascii_string_maybe_end else .quoted_wide_string_maybe_end;716 state = if (state == .quoted_ascii_string) .quoted_ascii_string_maybe_end else .quoted_wide_string_maybe_end;
699 },717 },
700 '\\' => {718 '\\' => {
719 string_literal_length += 1;
720 string_literal_column += 1;
701 state = if (state == .quoted_ascii_string) .quoted_ascii_string_escape else .quoted_wide_string_escape;721 state = if (state == .quoted_ascii_string) .quoted_ascii_string_escape else .quoted_wide_string_escape;
702 },722 },
703 '\r' => {723 '\r' => {
724 string_literal_column = 0;
704 // \r doesn't count towards string literal length725 // \r doesn't count towards string literal length
705726
706 // Increment line number but don't affect the result token's line number727 // Increment line number but don't affect the result token's line number
707 _ = self.incrementLineNumber();728 _ = self.incrementLineNumber();
708 },729 },
709 '\n' => {730 '\n' => {
731 string_literal_column = 0;
710 // first \n expands to <space><\n>732 // first \n expands to <space><\n>
711 if (!string_literal_collapsing_whitespace) {733 if (!string_literal_collapsing_whitespace) {
712 string_literal_length += 2;734 string_literal_length += 2;
...@@ -720,33 +742,17 @@ pub const Lexer = struct {...@@ -720,33 +742,17 @@ pub const Lexer = struct {
720 // only \t, space, Vertical Tab, and Form Feed count as whitespace when collapsing742 // only \t, space, Vertical Tab, and Form Feed count as whitespace when collapsing
721 '\t', ' ', '\x0b', '\x0c' => {743 '\t', ' ', '\x0b', '\x0c' => {
722 if (!string_literal_collapsing_whitespace) {744 if (!string_literal_collapsing_whitespace) {
723 if (c == '\t') {745 // Literal tab characters are counted as the number of space characters
724 // Literal tab characters are counted as the number of space characters746 // needed to reach the next 8-column tab stop.
725 // needed to reach the next 8-column tab stop.747 const width = columnWidth(string_literal_column, @intCast(c), 8);
726 //748 string_literal_length += width;
727 // This implemention is ineffecient but hopefully it's enough of an749 string_literal_column += width;
728 // edge case that it doesn't matter too much. Literal tab characters in
729 // string literals being replaced by a variable number of spaces depending
730 // on which column the tab character is located in the source .rc file seems
731 // like it has extremely limited use-cases, so it seems unlikely that it's used
732 // in real .rc files.
733 var dummy_token = Token{
734 .start = self.index,
735 .end = self.index,
736 .line_number = self.line_handler.line_number,
737 .id = .invalid,
738 };
739 dummy_token.start = self.index;
740 const current_column = dummy_token.calculateColumn(self.buffer, 8, null);
741 string_literal_length += columnsUntilTabStop(current_column, 8);
742 } else {
743 string_literal_length += 1;
744 }
745 }750 }
746 },751 },
747 else => {752 else => {
748 string_literal_collapsing_whitespace = false;753 string_literal_collapsing_whitespace = false;
749 string_literal_length += 1;754 string_literal_length += 1;
755 string_literal_column += 1;
750 },756 },
751 },757 },
752 .quoted_ascii_string_escape, .quoted_wide_string_escape => switch (c) {758 .quoted_ascii_string_escape, .quoted_wide_string_escape => switch (c) {
...@@ -760,14 +766,19 @@ pub const Lexer = struct {...@@ -760,14 +766,19 @@ pub const Lexer = struct {
760 return error.FoundCStyleEscapedQuote;766 return error.FoundCStyleEscapedQuote;
761 },767 },
762 else => {768 else => {
769 string_literal_length += 1;
770 string_literal_column += 1;
763 state = if (state == .quoted_ascii_string_escape) .quoted_ascii_string else .quoted_wide_string;771 state = if (state == .quoted_ascii_string_escape) .quoted_ascii_string else .quoted_wide_string;
764 },772 },
765 },773 },
766 .quoted_ascii_string_maybe_end, .quoted_wide_string_maybe_end => switch (c) {774 .quoted_ascii_string_maybe_end, .quoted_wide_string_maybe_end => switch (c) {
767 '"' => {775 '"' => {
768 state = if (state == .quoted_ascii_string_maybe_end) .quoted_ascii_string else .quoted_wide_string;776 state = if (state == .quoted_ascii_string_maybe_end) .quoted_ascii_string else .quoted_wide_string;
769 // Escaped quotes only count as 1 char for string literal length checks,777 // Escaped quotes count as 1 char for string literal length checks.
770 // so we don't increment string_literal_length here.778 // Since we did not increment on the first " (because it could have been
779 // the end of the quoted string), we increment here
780 string_literal_length += 1;
781 string_literal_column += 1;
771 },782 },
772 else => {783 else => {
773 result.id = if (state == .quoted_ascii_string_maybe_end) .quoted_ascii_string else .quoted_wide_string;784 result.id = if (state == .quoted_ascii_string_maybe_end) .quoted_ascii_string else .quoted_wide_string;
...@@ -807,6 +818,8 @@ pub const Lexer = struct {...@@ -807,6 +818,8 @@ pub const Lexer = struct {
807 }818 }
808 }819 }
809820
821 result.end = self.index;
822
810 if (result.id == .quoted_ascii_string or result.id == .quoted_wide_string) {823 if (result.id == .quoted_ascii_string or result.id == .quoted_wide_string) {
811 if (string_literal_length > self.max_string_literal_codepoints) {824 if (string_literal_length > self.max_string_literal_codepoints) {
812 self.error_context_token = result;825 self.error_context_token = result;
...@@ -814,7 +827,6 @@ pub const Lexer = struct {...@@ -814,7 +827,6 @@ pub const Lexer = struct {
814 }827 }
815 }828 }
816829
817 result.end = self.index;
818 return result;830 return result;
819 }831 }
820832
...@@ -877,6 +889,7 @@ pub const Lexer = struct {...@@ -877,6 +889,7 @@ pub const Lexer = struct {
877 .end = end,889 .end = end,
878 .line_number = self.line_handler.line_number,890 .line_number = self.line_handler.line_number,
879 };891 };
892 errdefer self.error_context_token = token;
880 const full_command = self.buffer[start..end];893 const full_command = self.buffer[start..end];
881 var command = full_command;894 var command = full_command;
882895
...@@ -901,7 +914,6 @@ pub const Lexer = struct {...@@ -901,7 +914,6 @@ pub const Lexer = struct {
901 }914 }
902915
903 if (command.len == 0 or command[0] != '(') {916 if (command.len == 0 or command[0] != '(') {
904 self.error_context_token = token;
905 return error.CodePagePragmaMissingLeftParen;917 return error.CodePagePragmaMissingLeftParen;
906 }918 }
907 command = command[1..];919 command = command[1..];
...@@ -917,7 +929,6 @@ pub const Lexer = struct {...@@ -917,7 +929,6 @@ pub const Lexer = struct {
917 }929 }
918930
919 if (num_str.len == 0) {931 if (num_str.len == 0) {
920 self.error_context_token = token;
921 return error.CodePagePragmaNotInteger;932 return error.CodePagePragmaNotInteger;
922 }933 }
923934
...@@ -926,7 +937,6 @@ pub const Lexer = struct {...@@ -926,7 +937,6 @@ pub const Lexer = struct {
926 }937 }
927938
928 if (command.len == 0 or command[0] != ')') {939 if (command.len == 0 or command[0] != ')') {
929 self.error_context_token = token;
930 return error.CodePagePragmaMissingRightParen;940 return error.CodePagePragmaMissingRightParen;
931 }941 }
932942
...@@ -943,41 +953,26 @@ pub const Lexer = struct {...@@ -943,41 +953,26 @@ pub const Lexer = struct {
943 //953 //
944 // Instead of that, we just have a separate error specifically for overflow.954 // Instead of that, we just have a separate error specifically for overflow.
945 const num = parseCodePageNum(num_str) catch |err| switch (err) {955 const num = parseCodePageNum(num_str) catch |err| switch (err) {
946 error.InvalidCharacter => {956 error.InvalidCharacter => return error.CodePagePragmaNotInteger,
947 self.error_context_token = token;957 error.Overflow => return error.CodePagePragmaOverflow,
948 return error.CodePagePragmaNotInteger;
949 },
950 error.Overflow => {
951 self.error_context_token = token;
952 return error.CodePagePragmaOverflow;
953 },
954 };958 };
955959
956 // Anything that starts with 0 but does not resolve to 0 is treated as invalid, e.g. 01252960 // Anything that starts with 0 but does not resolve to 0 is treated as invalid, e.g. 01252
957 if (num_str[0] == '0' and num != 0) {961 if (num_str[0] == '0' and num != 0) {
958 self.error_context_token = token;
959 return error.CodePagePragmaInvalidCodePage;962 return error.CodePagePragmaInvalidCodePage;
960 }963 }
961 // Anything that resolves to 0 is treated as 'not an integer' by the Win32 implementation.964 // Anything that resolves to 0 is treated as 'not an integer' by the Win32 implementation.
962 else if (num == 0) {965 else if (num == 0) {
963 self.error_context_token = token;
964 return error.CodePagePragmaNotInteger;966 return error.CodePagePragmaNotInteger;
965 }967 }
966 // Anything above u16 max is not going to be found since our CodePage enum is backed by a u16.968 // Anything above u16 max is not going to be found since our CodePage enum is backed by a u16.
967 if (num > std.math.maxInt(u16)) {969 if (num > std.math.maxInt(u16)) {
968 self.error_context_token = token;
969 return error.CodePagePragmaInvalidCodePage;970 return error.CodePagePragmaInvalidCodePage;
970 }971 }
971972
972 break :code_page code_pages.CodePage.getByIdentifierEnsureSupported(@intCast(num)) catch |err| switch (err) {973 break :code_page code_pages.CodePage.getByIdentifierEnsureSupported(@intCast(num)) catch |err| switch (err) {
973 error.InvalidCodePage => {974 error.InvalidCodePage => return error.CodePagePragmaInvalidCodePage,
974 self.error_context_token = token;975 error.UnsupportedCodePage => return error.CodePagePragmaUnsupportedCodePage,
975 return error.CodePagePragmaInvalidCodePage;
976 },
977 error.UnsupportedCodePage => {
978 self.error_context_token = token;
979 return error.CodePagePragmaUnsupportedCodePage;
980 },
981 };976 };
982 };977 };
983978
...@@ -990,7 +985,6 @@ pub const Lexer = struct {...@@ -990,7 +985,6 @@ pub const Lexer = struct {
990 // to still be able to work correctly after this error is returned.985 // to still be able to work correctly after this error is returned.
991 if (self.source_mappings) |source_mappings| {986 if (self.source_mappings) |source_mappings| {
992 if (!source_mappings.isRootFile(token.line_number)) {987 if (!source_mappings.isRootFile(token.line_number)) {
993 self.error_context_token = token;
994 return error.CodePagePragmaInIncludedFile;988 return error.CodePagePragmaInIncludedFile;
995 }989 }
996 }990 }
src/resinator/literals.zig+7
...@@ -775,6 +775,13 @@ pub fn columnsUntilTabStop(column: usize, tab_columns: usize) usize {...@@ -775,6 +775,13 @@ pub fn columnsUntilTabStop(column: usize, tab_columns: usize) usize {
775 return tab_columns - (column % tab_columns);775 return tab_columns - (column % tab_columns);
776}776}
777777
778pub fn columnWidth(cur_column: usize, c: u8, tab_columns: usize) usize {
779 return switch (c) {
780 '\t' => columnsUntilTabStop(cur_column, tab_columns),
781 else => 1,
782 };
783}
784
778pub const Number = struct {785pub const Number = struct {
779 value: u32,786 value: u32,
780 is_long: bool = false,787 is_long: bool = false,
src/resinator/preprocess.zig+9-4
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
3const cli = @import("cli.zig");4const cli = @import("cli.zig");
4const introspect = @import("../introspect.zig");
55
6pub const IncludeArgs = struct {6pub const IncludeArgs = struct {
7 clang_target: ?[]const u8 = null,7 clang_target: ?[]const u8 = null,
...@@ -68,10 +68,15 @@ pub fn appendClangArgs(arena: Allocator, argv: *std.ArrayList([]const u8), optio...@@ -68,10 +68,15 @@ pub fn appendClangArgs(arena: Allocator, argv: *std.ArrayList([]const u8), optio
68 }68 }
6969
70 if (!options.ignore_include_env_var) {70 if (!options.ignore_include_env_var) {
71 const INCLUDE = (introspect.EnvVar.INCLUDE.get(arena) catch @panic("OOM")) orelse "";71 const INCLUDE = std.process.getEnvVarOwned(arena, "INCLUDE") catch "";
7272
73 // TODO: Should this be platform-specific? How does windres/llvm-rc handle this (if at all)?73 // The only precedence here is llvm-rc which also uses the platform-specific
74 var it = std.mem.tokenize(u8, INCLUDE, ";");74 // delimiter. There's no precedence set by `rc.exe` since it's Windows-only.
75 const delimiter = switch (builtin.os.tag) {
76 .windows => ';',
77 else => ':',
78 };
79 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);
75 while (it.next()) |include_path| {80 while (it.next()) |include_path| {
76 try argv.append("-isystem");81 try argv.append("-isystem");
77 try argv.append(include_path);82 try argv.append(include_path);
src/resinator/source_mapping.zig+4-1
...@@ -240,6 +240,9 @@ pub fn handleLineCommand(allocator: Allocator, line_command: []const u8, current...@@ -240,6 +240,9 @@ pub fn handleLineCommand(allocator: Allocator, line_command: []const u8, current
240 };240 };
241 defer allocator.free(filename);241 defer allocator.free(filename);
242242
243 // \x00 bytes in the filename is incompatible with how StringTable works
244 if (std.mem.indexOfScalar(u8, filename, '\x00') != null) return;
245
243 current_mapping.line_num = linenum;246 current_mapping.line_num = linenum;
244 current_mapping.filename.clearRetainingCapacity();247 current_mapping.filename.clearRetainingCapacity();
245 try current_mapping.filename.appendSlice(allocator, filename);248 try current_mapping.filename.appendSlice(allocator, filename);
...@@ -441,7 +444,7 @@ pub const SourceMappings = struct {...@@ -441,7 +444,7 @@ pub const SourceMappings = struct {
441 ptr.* = span;444 ptr.* = span;
442 }445 }
443446
444 pub fn has(self: *SourceMappings, line_num: usize) bool {447 pub fn has(self: SourceMappings, line_num: usize) bool {
445 return self.mapping.items.len >= line_num;448 return self.mapping.items.len >= line_num;
446 }449 }
447450