authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-27 16:05:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-28 18:30:57-07:00
log8d80d67693fe8b9ec99bdd9335172cfc0d9019ec
treea862c92c5b43d632c10b89b02cbb903b053a464d
parentf7884961c230367cefd3dfbf730ac5277297dc63

resinator: some updates to avoid GenericWriter

These are some hastily made, untested changes to get things compiling again, since Ryan is working on a better upgrade patchset in the meantime.

6 files changed, 199 insertions(+), 300 deletions(-)

lib/compiler/aro/aro/Compilation.zig+8-3
...@@ -537,8 +537,15 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi...@@ -537,8 +537,15 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
537 var allocating: std.Io.Writer.Allocating = .init(comp.gpa);537 var allocating: std.Io.Writer.Allocating = .init(comp.gpa);
538 defer allocating.deinit();538 defer allocating.deinit();
539539
540 const buf = &allocating.writer;540 generateBuiltinMacrosWriter(comp, system_defines_mode, &allocating.writer) catch |err| switch (err) {
541 error.WriteFailed => return error.OutOfMemory,
542 else => |e| return e,
543 };
541544
545 return comp.addSourceFromBuffer("<builtin>", allocating.written());
546}
547
548pub fn generateBuiltinMacrosWriter(comp: *Compilation, system_defines_mode: SystemDefinesMode, buf: *Writer) !void {
542 if (system_defines_mode == .include_system_defines) {549 if (system_defines_mode == .include_system_defines) {
543 try buf.writeAll(550 try buf.writeAll(
544 \\#define __VERSION__ "Aro551 \\#define __VERSION__ "Aro
...@@ -576,8 +583,6 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi...@@ -576,8 +583,6 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
576 if (system_defines_mode == .include_system_defines) {583 if (system_defines_mode == .include_system_defines) {
577 try comp.generateSystemDefines(buf);584 try comp.generateSystemDefines(buf);
578 }585 }
579
580 return comp.addSourceFromBuffer("<builtin>", allocating.written());
581}586}
582587
583fn generateFloatMacros(w: *Writer, prefix: []const u8, semantics: target_util.FPSemantics, ext: []const u8) !void {588fn generateFloatMacros(w: *Writer, prefix: []const u8, semantics: target_util.FPSemantics, ext: []const u8) !void {
lib/compiler/resinator/cli.zig+64-125
...@@ -520,8 +520,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -520,8 +520,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
520 // - or / on its own is an error520 // - or / on its own is an error
521 else => {521 else => {
522 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };522 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
523 var msg_writer = err_details.msg.writer(allocator);523 try err_details.msg.print(allocator, "invalid option: {s}", .{arg.prefixSlice()});
524 try msg_writer.print("invalid option: {s}", .{arg.prefixSlice()});
525 try diagnostics.append(err_details);524 try diagnostics.append(err_details);
526 arg_i += 1;525 arg_i += 1;
527 continue :next_arg;526 continue :next_arg;
...@@ -532,8 +531,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -532,8 +531,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
532 const args_remaining = args.len - arg_i;531 const args_remaining = args.len - arg_i;
533 if (args_remaining <= 2 and arg.looksLikeFilepath()) {532 if (args_remaining <= 2 and arg.looksLikeFilepath()) {
534 var err_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i };533 var err_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i };
535 var msg_writer = err_details.msg.writer(allocator);534 try err_details.msg.appendSlice(allocator, "this argument was inferred to be a filepath, so argument parsing was terminated");
536 try msg_writer.writeAll("this argument was inferred to be a filepath, so argument parsing was terminated");
537 try diagnostics.append(err_details);535 try diagnostics.append(err_details);
538536
539 break;537 break;
...@@ -550,16 +548,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -550,16 +548,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
550 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":output-format")) {548 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":output-format")) {
551 const value = arg.value(":output-format".len, arg_i, args) catch {549 const value = arg.value(":output-format".len, arg_i, args) catch {
552 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };550 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
553 var msg_writer = err_details.msg.writer(allocator);551 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":output-format".len) });
554 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":output-format".len) });
555 try diagnostics.append(err_details);552 try diagnostics.append(err_details);
556 arg_i += 1;553 arg_i += 1;
557 break :next_arg;554 break :next_arg;
558 };555 };
559 output_format = std.meta.stringToEnum(Options.OutputFormat, value.slice) orelse blk: {556 output_format = std.meta.stringToEnum(Options.OutputFormat, value.slice) orelse blk: {
560 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };557 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
561 var msg_writer = err_details.msg.writer(allocator);558 try err_details.msg.print(allocator, "invalid output format setting: {s} ", .{value.slice});
562 try msg_writer.print("invalid output format setting: {s} ", .{value.slice});
563 try diagnostics.append(err_details);559 try diagnostics.append(err_details);
564 break :blk output_format;560 break :blk output_format;
565 };561 };
...@@ -569,16 +565,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -569,16 +565,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
569 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":auto-includes")) {565 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":auto-includes")) {
570 const value = arg.value(":auto-includes".len, arg_i, args) catch {566 const value = arg.value(":auto-includes".len, arg_i, args) catch {
571 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };567 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
572 var msg_writer = err_details.msg.writer(allocator);568 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":auto-includes".len) });
573 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":auto-includes".len) });
574 try diagnostics.append(err_details);569 try diagnostics.append(err_details);
575 arg_i += 1;570 arg_i += 1;
576 break :next_arg;571 break :next_arg;
577 };572 };
578 options.auto_includes = std.meta.stringToEnum(Options.AutoIncludes, value.slice) orelse blk: {573 options.auto_includes = std.meta.stringToEnum(Options.AutoIncludes, value.slice) orelse blk: {
579 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };574 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
580 var msg_writer = err_details.msg.writer(allocator);575 try err_details.msg.print(allocator, "invalid auto includes setting: {s} ", .{value.slice});
581 try msg_writer.print("invalid auto includes setting: {s} ", .{value.slice});
582 try diagnostics.append(err_details);576 try diagnostics.append(err_details);
583 break :blk options.auto_includes;577 break :blk options.auto_includes;
584 };578 };
...@@ -587,16 +581,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -587,16 +581,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
587 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":input-format")) {581 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":input-format")) {
588 const value = arg.value(":input-format".len, arg_i, args) catch {582 const value = arg.value(":input-format".len, arg_i, args) catch {
589 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };583 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
590 var msg_writer = err_details.msg.writer(allocator);584 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":input-format".len) });
591 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":input-format".len) });
592 try diagnostics.append(err_details);585 try diagnostics.append(err_details);
593 arg_i += 1;586 arg_i += 1;
594 break :next_arg;587 break :next_arg;
595 };588 };
596 input_format = std.meta.stringToEnum(Options.InputFormat, value.slice) orelse blk: {589 input_format = std.meta.stringToEnum(Options.InputFormat, value.slice) orelse blk: {
597 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };590 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
598 var msg_writer = err_details.msg.writer(allocator);591 try err_details.msg.print(allocator, "invalid input format setting: {s} ", .{value.slice});
599 try msg_writer.print("invalid input format setting: {s} ", .{value.slice});
600 try diagnostics.append(err_details);592 try diagnostics.append(err_details);
601 break :blk input_format;593 break :blk input_format;
602 };594 };
...@@ -606,16 +598,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -606,16 +598,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
606 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile-fmt")) {598 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile-fmt")) {
607 const value = arg.value(":depfile-fmt".len, arg_i, args) catch {599 const value = arg.value(":depfile-fmt".len, arg_i, args) catch {
608 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };600 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
609 var msg_writer = err_details.msg.writer(allocator);601 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile-fmt".len) });
610 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile-fmt".len) });
611 try diagnostics.append(err_details);602 try diagnostics.append(err_details);
612 arg_i += 1;603 arg_i += 1;
613 break :next_arg;604 break :next_arg;
614 };605 };
615 options.depfile_fmt = std.meta.stringToEnum(Options.DepfileFormat, value.slice) orelse blk: {606 options.depfile_fmt = std.meta.stringToEnum(Options.DepfileFormat, value.slice) orelse blk: {
616 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };607 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
617 var msg_writer = err_details.msg.writer(allocator);608 try err_details.msg.print(allocator, "invalid depfile format setting: {s} ", .{value.slice});
618 try msg_writer.print("invalid depfile format setting: {s} ", .{value.slice});
619 try diagnostics.append(err_details);609 try diagnostics.append(err_details);
620 break :blk options.depfile_fmt;610 break :blk options.depfile_fmt;
621 };611 };
...@@ -624,8 +614,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -624,8 +614,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
624 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile")) {614 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile")) {
625 const value = arg.value(":depfile".len, arg_i, args) catch {615 const value = arg.value(":depfile".len, arg_i, args) catch {
626 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };616 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
627 var msg_writer = err_details.msg.writer(allocator);617 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile".len) });
628 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile".len) });
629 try diagnostics.append(err_details);618 try diagnostics.append(err_details);
630 arg_i += 1;619 arg_i += 1;
631 break :next_arg;620 break :next_arg;
...@@ -643,8 +632,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -643,8 +632,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
643 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":target")) {632 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":target")) {
644 const value = arg.value(":target".len, arg_i, args) catch {633 const value = arg.value(":target".len, arg_i, args) catch {
645 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };634 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
646 var msg_writer = err_details.msg.writer(allocator);635 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":target".len) });
647 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":target".len) });
648 try diagnostics.append(err_details);636 try diagnostics.append(err_details);
649 arg_i += 1;637 arg_i += 1;
650 break :next_arg;638 break :next_arg;
...@@ -655,8 +643,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -655,8 +643,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
655 const arch_str = target_it.first();643 const arch_str = target_it.first();
656 const arch = cvtres.supported_targets.Arch.fromStringIgnoreCase(arch_str) orelse {644 const arch = cvtres.supported_targets.Arch.fromStringIgnoreCase(arch_str) orelse {
657 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };645 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
658 var msg_writer = err_details.msg.writer(allocator);646 try err_details.msg.print(allocator, "invalid or unsupported target architecture: {s}", .{arch_str});
659 try msg_writer.print("invalid or unsupported target architecture: {s}", .{arch_str});
660 try diagnostics.append(err_details);647 try diagnostics.append(err_details);
661 arg_i += value.index_increment;648 arg_i += value.index_increment;
662 continue :next_arg;649 continue :next_arg;
...@@ -680,13 +667,11 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -680,13 +667,11 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
680 .prefix_len = arg.prefixSlice().len,667 .prefix_len = arg.prefixSlice().len,
681 .value_offset = arg.name_offset + 3,668 .value_offset = arg.name_offset + 3,
682 } };669 } };
683 var msg_writer = err_details.msg.writer(allocator);670 try err_details.msg.print(allocator, "missing value for {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
684 try msg_writer.print("missing value for {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
685 try diagnostics.append(err_details);671 try diagnostics.append(err_details);
686 }672 }
687 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };673 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
688 var msg_writer = err_details.msg.writer(allocator);674 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
689 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
690 try diagnostics.append(err_details);675 try diagnostics.append(err_details);
691 arg_i += 1;676 arg_i += 1;
692 continue :next_arg;677 continue :next_arg;
...@@ -695,16 +680,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -695,16 +680,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
695 else if (std.ascii.startsWithIgnoreCase(arg_name, "tn")) {680 else if (std.ascii.startsWithIgnoreCase(arg_name, "tn")) {
696 const value = arg.value(2, arg_i, args) catch no_value: {681 const value = arg.value(2, arg_i, args) catch no_value: {
697 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };682 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
698 var msg_writer = err_details.msg.writer(allocator);683 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
699 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
700 try diagnostics.append(err_details);684 try diagnostics.append(err_details);
701 // dummy zero-length slice starting where the value would have been685 // dummy zero-length slice starting where the value would have been
702 const value_start = arg.name_offset + 2;686 const value_start = arg.name_offset + 2;
703 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };687 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
704 };688 };
705 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };689 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
706 var msg_writer = err_details.msg.writer(allocator);690 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
707 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
708 try diagnostics.append(err_details);691 try diagnostics.append(err_details);
709 arg_i += value.index_increment;692 arg_i += value.index_increment;
710 continue :next_arg;693 continue :next_arg;
...@@ -716,16 +699,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -716,16 +699,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
716 {699 {
717 const value = arg.value(2, arg_i, args) catch no_value: {700 const value = arg.value(2, arg_i, args) catch no_value: {
718 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };701 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
719 var msg_writer = err_details.msg.writer(allocator);702 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
720 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
721 try diagnostics.append(err_details);703 try diagnostics.append(err_details);
722 // dummy zero-length slice starting where the value would have been704 // dummy zero-length slice starting where the value would have been
723 const value_start = arg.name_offset + 2;705 const value_start = arg.name_offset + 2;
724 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };706 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
725 };707 };
726 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };708 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
727 var msg_writer = err_details.msg.writer(allocator);709 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
728 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
729 try diagnostics.append(err_details);710 try diagnostics.append(err_details);
730 arg_i += value.index_increment;711 arg_i += value.index_increment;
731 continue :next_arg;712 continue :next_arg;
...@@ -733,8 +714,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -733,8 +714,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
733 // Unsupported MUI options that do not need a value714 // Unsupported MUI options that do not need a value
734 else if (std.ascii.startsWithIgnoreCase(arg_name, "g1")) {715 else if (std.ascii.startsWithIgnoreCase(arg_name, "g1")) {
735 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(2) };716 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(2) };
736 var msg_writer = err_details.msg.writer(allocator);717 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
737 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
738 try diagnostics.append(err_details);718 try diagnostics.append(err_details);
739 arg.name_offset += 2;719 arg.name_offset += 2;
740 }720 }
...@@ -747,15 +727,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -747,15 +727,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
747 std.ascii.startsWithIgnoreCase(arg_name, "ta"))727 std.ascii.startsWithIgnoreCase(arg_name, "ta"))
748 {728 {
749 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(2) };729 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(2) };
750 var msg_writer = err_details.msg.writer(allocator);730 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
751 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
752 try diagnostics.append(err_details);731 try diagnostics.append(err_details);
753 arg.name_offset += 2;732 arg.name_offset += 2;
754 } else if (std.ascii.startsWithIgnoreCase(arg_name, "fo")) {733 } else if (std.ascii.startsWithIgnoreCase(arg_name, "fo")) {
755 const value = arg.value(2, arg_i, args) catch {734 const value = arg.value(2, arg_i, args) catch {
756 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };735 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
757 var msg_writer = err_details.msg.writer(allocator);736 try err_details.msg.print(allocator, "missing output path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
758 try msg_writer.print("missing output path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
759 try diagnostics.append(err_details);737 try diagnostics.append(err_details);
760 arg_i += 1;738 arg_i += 1;
761 break :next_arg;739 break :next_arg;
...@@ -767,8 +745,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -767,8 +745,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
767 } else if (std.ascii.startsWithIgnoreCase(arg_name, "sl")) {745 } else if (std.ascii.startsWithIgnoreCase(arg_name, "sl")) {
768 const value = arg.value(2, arg_i, args) catch {746 const value = arg.value(2, arg_i, args) catch {
769 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };747 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
770 var msg_writer = err_details.msg.writer(allocator);748 try err_details.msg.print(allocator, "missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
771 try msg_writer.print("missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
772 try diagnostics.append(err_details);749 try diagnostics.append(err_details);
773 arg_i += 1;750 arg_i += 1;
774 break :next_arg;751 break :next_arg;
...@@ -776,24 +753,20 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -776,24 +753,20 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
776 const percent_str = value.slice;753 const percent_str = value.slice;
777 const percent: u32 = parsePercent(percent_str) catch {754 const percent: u32 = parsePercent(percent_str) catch {
778 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };755 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
779 var msg_writer = err_details.msg.writer(allocator);756 try err_details.msg.print(allocator, "invalid percent format '{s}'", .{percent_str});
780 try msg_writer.print("invalid percent format '{s}'", .{percent_str});
781 try diagnostics.append(err_details);757 try diagnostics.append(err_details);
782 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };758 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };
783 var note_writer = note_details.msg.writer(allocator);759 try note_details.msg.appendSlice(allocator, "string length percent must be an integer between 1 and 100 (inclusive)");
784 try note_writer.writeAll("string length percent must be an integer between 1 and 100 (inclusive)");
785 try diagnostics.append(note_details);760 try diagnostics.append(note_details);
786 arg_i += value.index_increment;761 arg_i += value.index_increment;
787 continue :next_arg;762 continue :next_arg;
788 };763 };
789 if (percent == 0 or percent > 100) {764 if (percent == 0 or percent > 100) {
790 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };765 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
791 var msg_writer = err_details.msg.writer(allocator);766 try err_details.msg.print(allocator, "percent out of range: {} (parsed from '{s}')", .{ percent, percent_str });
792 try msg_writer.print("percent out of range: {} (parsed from '{s}')", .{ percent, percent_str });
793 try diagnostics.append(err_details);767 try diagnostics.append(err_details);
794 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };768 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };
795 var note_writer = note_details.msg.writer(allocator);769 try note_details.msg.appendSlice(allocator, "string length percent must be an integer between 1 and 100 (inclusive)");
796 try note_writer.writeAll("string length percent must be an integer between 1 and 100 (inclusive)");
797 try diagnostics.append(note_details);770 try diagnostics.append(note_details);
798 arg_i += value.index_increment;771 arg_i += value.index_increment;
799 continue :next_arg;772 continue :next_arg;
...@@ -805,8 +778,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -805,8 +778,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
805 } else if (std.ascii.startsWithIgnoreCase(arg_name, "ln")) {778 } else if (std.ascii.startsWithIgnoreCase(arg_name, "ln")) {
806 const value = arg.value(2, arg_i, args) catch {779 const value = arg.value(2, arg_i, args) catch {
807 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };780 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
808 var msg_writer = err_details.msg.writer(allocator);781 try err_details.msg.print(allocator, "missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
809 try msg_writer.print("missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
810 try diagnostics.append(err_details);782 try diagnostics.append(err_details);
811 arg_i += 1;783 arg_i += 1;
812 break :next_arg;784 break :next_arg;
...@@ -814,16 +786,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -814,16 +786,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
814 const tag = value.slice;786 const tag = value.slice;
815 options.default_language_id = lang.tagToInt(tag) catch {787 options.default_language_id = lang.tagToInt(tag) catch {
816 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };788 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
817 var msg_writer = err_details.msg.writer(allocator);789 try err_details.msg.print(allocator, "invalid language tag: {s}", .{tag});
818 try msg_writer.print("invalid language tag: {s}", .{tag});
819 try diagnostics.append(err_details);790 try diagnostics.append(err_details);
820 arg_i += value.index_increment;791 arg_i += value.index_increment;
821 continue :next_arg;792 continue :next_arg;
822 };793 };
823 if (options.default_language_id.? == lang.LOCALE_CUSTOM_UNSPECIFIED) {794 if (options.default_language_id.? == lang.LOCALE_CUSTOM_UNSPECIFIED) {
824 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };795 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };
825 var msg_writer = err_details.msg.writer(allocator);796 try err_details.msg.print(allocator, "language tag '{s}' does not have an assigned ID so it will be resolved to LOCALE_CUSTOM_UNSPECIFIED (id=0x{x})", .{ tag, lang.LOCALE_CUSTOM_UNSPECIFIED });
826 try msg_writer.print("language tag '{s}' does not have an assigned ID so it will be resolved to LOCALE_CUSTOM_UNSPECIFIED (id=0x{x})", .{ tag, lang.LOCALE_CUSTOM_UNSPECIFIED });
827 try diagnostics.append(err_details);797 try diagnostics.append(err_details);
828 }798 }
829 arg_i += value.index_increment;799 arg_i += value.index_increment;
...@@ -831,8 +801,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -831,8 +801,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
831 } else if (std.ascii.startsWithIgnoreCase(arg_name, "l")) {801 } else if (std.ascii.startsWithIgnoreCase(arg_name, "l")) {
832 const value = arg.value(1, arg_i, args) catch {802 const value = arg.value(1, arg_i, args) catch {
833 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };803 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
834 var msg_writer = err_details.msg.writer(allocator);804 try err_details.msg.print(allocator, "missing language ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
835 try msg_writer.print("missing language ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
836 try diagnostics.append(err_details);805 try diagnostics.append(err_details);
837 arg_i += 1;806 arg_i += 1;
838 break :next_arg;807 break :next_arg;
...@@ -840,8 +809,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -840,8 +809,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
840 const num_str = value.slice;809 const num_str = value.slice;
841 options.default_language_id = lang.parseInt(num_str) catch {810 options.default_language_id = lang.parseInt(num_str) catch {
842 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };811 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
843 var msg_writer = err_details.msg.writer(allocator);812 try err_details.msg.print(allocator, "invalid language ID: {s}", .{num_str});
844 try msg_writer.print("invalid language ID: {s}", .{num_str});
845 try diagnostics.append(err_details);813 try diagnostics.append(err_details);
846 arg_i += value.index_increment;814 arg_i += value.index_increment;
847 continue :next_arg;815 continue :next_arg;
...@@ -860,16 +828,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -860,16 +828,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
860 {828 {
861 const value = arg.value(1, arg_i, args) catch no_value: {829 const value = arg.value(1, arg_i, args) catch no_value: {
862 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };830 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
863 var msg_writer = err_details.msg.writer(allocator);831 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
864 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
865 try diagnostics.append(err_details);832 try diagnostics.append(err_details);
866 // dummy zero-length slice starting where the value would have been833 // dummy zero-length slice starting where the value would have been
867 const value_start = arg.name_offset + 1;834 const value_start = arg.name_offset + 1;
868 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };835 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
869 };836 };
870 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };837 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
871 var msg_writer = err_details.msg.writer(allocator);838 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
872 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
873 try diagnostics.append(err_details);839 try diagnostics.append(err_details);
874 arg_i += value.index_increment;840 arg_i += value.index_increment;
875 continue :next_arg;841 continue :next_arg;
...@@ -882,16 +848,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -882,16 +848,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
882 {848 {
883 const value = arg.value(1, arg_i, args) catch no_value: {849 const value = arg.value(1, arg_i, args) catch no_value: {
884 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };850 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
885 var msg_writer = err_details.msg.writer(allocator);851 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
886 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
887 try diagnostics.append(err_details);852 try diagnostics.append(err_details);
888 // dummy zero-length slice starting where the value would have been853 // dummy zero-length slice starting where the value would have been
889 const value_start = arg.name_offset + 1;854 const value_start = arg.name_offset + 1;
890 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };855 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
891 };856 };
892 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };857 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
893 var msg_writer = err_details.msg.writer(allocator);858 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
894 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
895 try diagnostics.append(err_details);859 try diagnostics.append(err_details);
896 arg_i += value.index_increment;860 arg_i += value.index_increment;
897 continue :next_arg;861 continue :next_arg;
...@@ -899,15 +863,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -899,15 +863,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
899 // 1 char unsupported LCX/LCE options that do not need a value863 // 1 char unsupported LCX/LCE options that do not need a value
900 else if (std.ascii.startsWithIgnoreCase(arg_name, "t")) {864 else if (std.ascii.startsWithIgnoreCase(arg_name, "t")) {
901 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(1) };865 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(1) };
902 var msg_writer = err_details.msg.writer(allocator);866 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
903 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
904 try diagnostics.append(err_details);867 try diagnostics.append(err_details);
905 arg.name_offset += 1;868 arg.name_offset += 1;
906 } else if (std.ascii.startsWithIgnoreCase(arg_name, "c")) {869 } else if (std.ascii.startsWithIgnoreCase(arg_name, "c")) {
907 const value = arg.value(1, arg_i, args) catch {870 const value = arg.value(1, arg_i, args) catch {
908 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };871 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
909 var msg_writer = err_details.msg.writer(allocator);872 try err_details.msg.print(allocator, "missing code page ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
910 try msg_writer.print("missing code page ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
911 try diagnostics.append(err_details);873 try diagnostics.append(err_details);
912 arg_i += 1;874 arg_i += 1;
913 break :next_arg;875 break :next_arg;
...@@ -915,8 +877,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -915,8 +877,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
915 const num_str = value.slice;877 const num_str = value.slice;
916 const code_page_id = std.fmt.parseUnsigned(u16, num_str, 10) catch {878 const code_page_id = std.fmt.parseUnsigned(u16, num_str, 10) catch {
917 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };879 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
918 var msg_writer = err_details.msg.writer(allocator);880 try err_details.msg.print(allocator, "invalid code page ID: {s}", .{num_str});
919 try msg_writer.print("invalid code page ID: {s}", .{num_str});
920 try diagnostics.append(err_details);881 try diagnostics.append(err_details);
921 arg_i += value.index_increment;882 arg_i += value.index_increment;
922 continue :next_arg;883 continue :next_arg;
...@@ -924,16 +885,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -924,16 +885,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
924 options.default_code_page = code_pages.getByIdentifierEnsureSupported(code_page_id) catch |err| switch (err) {885 options.default_code_page = code_pages.getByIdentifierEnsureSupported(code_page_id) catch |err| switch (err) {
925 error.InvalidCodePage => {886 error.InvalidCodePage => {
926 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };887 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
927 var msg_writer = err_details.msg.writer(allocator);888 try err_details.msg.print(allocator, "invalid or unknown code page ID: {}", .{code_page_id});
928 try msg_writer.print("invalid or unknown code page ID: {}", .{code_page_id});
929 try diagnostics.append(err_details);889 try diagnostics.append(err_details);
930 arg_i += value.index_increment;890 arg_i += value.index_increment;
931 continue :next_arg;891 continue :next_arg;
932 },892 },
933 error.UnsupportedCodePage => {893 error.UnsupportedCodePage => {
934 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };894 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
935 var msg_writer = err_details.msg.writer(allocator);895 try err_details.msg.print(allocator, "unsupported code page: {s} (id={})", .{
936 try msg_writer.print("unsupported code page: {s} (id={})", .{
937 @tagName(code_pages.getByIdentifier(code_page_id) catch unreachable),896 @tagName(code_pages.getByIdentifier(code_page_id) catch unreachable),
938 code_page_id,897 code_page_id,
939 });898 });
...@@ -957,8 +916,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -957,8 +916,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
957 } else if (std.ascii.startsWithIgnoreCase(arg_name, "i")) {916 } else if (std.ascii.startsWithIgnoreCase(arg_name, "i")) {
958 const value = arg.value(1, arg_i, args) catch {917 const value = arg.value(1, arg_i, args) catch {
959 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };918 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
960 var msg_writer = err_details.msg.writer(allocator);919 try err_details.msg.print(allocator, "missing include path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
961 try msg_writer.print("missing include path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
962 try diagnostics.append(err_details);920 try diagnostics.append(err_details);
963 arg_i += 1;921 arg_i += 1;
964 break :next_arg;922 break :next_arg;
...@@ -986,15 +944,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -986,15 +944,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
986 // Undocumented option with unknown function944 // Undocumented option with unknown function
987 // TODO: More investigation to figure out what it does (if anything)945 // TODO: More investigation to figure out what it does (if anything)
988 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = arg.optionSpan(1) };946 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = arg.optionSpan(1) };
989 var msg_writer = err_details.msg.writer(allocator);947 try err_details.msg.print(allocator, "option {s}{s} has no effect (it is undocumented and its function is unknown in the Win32 RC compiler)", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
990 try msg_writer.print("option {s}{s} has no effect (it is undocumented and its function is unknown in the Win32 RC compiler)", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
991 try diagnostics.append(err_details);948 try diagnostics.append(err_details);
992 arg.name_offset += 1;949 arg.name_offset += 1;
993 } else if (std.ascii.startsWithIgnoreCase(arg_name, "d")) {950 } else if (std.ascii.startsWithIgnoreCase(arg_name, "d")) {
994 const value = arg.value(1, arg_i, args) catch {951 const value = arg.value(1, arg_i, args) catch {
995 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };952 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
996 var msg_writer = err_details.msg.writer(allocator);953 try err_details.msg.print(allocator, "missing symbol to define after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
997 try msg_writer.print("missing symbol to define after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
998 try diagnostics.append(err_details);954 try diagnostics.append(err_details);
999 arg_i += 1;955 arg_i += 1;
1000 break :next_arg;956 break :next_arg;
...@@ -1009,8 +965,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1009,8 +965,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1009 try options.define(symbol, symbol_value);965 try options.define(symbol, symbol_value);
1010 } else {966 } else {
1011 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };967 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };
1012 var msg_writer = err_details.msg.writer(allocator);968 try err_details.msg.print(allocator, "symbol \"{s}\" is not a valid identifier and therefore cannot be defined", .{symbol});
1013 try msg_writer.print("symbol \"{s}\" is not a valid identifier and therefore cannot be defined", .{symbol});
1014 try diagnostics.append(err_details);969 try diagnostics.append(err_details);
1015 }970 }
1016 arg_i += value.index_increment;971 arg_i += value.index_increment;
...@@ -1018,8 +973,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1018,8 +973,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1018 } else if (std.ascii.startsWithIgnoreCase(arg_name, "u")) {973 } else if (std.ascii.startsWithIgnoreCase(arg_name, "u")) {
1019 const value = arg.value(1, arg_i, args) catch {974 const value = arg.value(1, arg_i, args) catch {
1020 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };975 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
1021 var msg_writer = err_details.msg.writer(allocator);976 try err_details.msg.print(allocator, "missing symbol to undefine after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
1022 try msg_writer.print("missing symbol to undefine after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
1023 try diagnostics.append(err_details);977 try diagnostics.append(err_details);
1024 arg_i += 1;978 arg_i += 1;
1025 break :next_arg;979 break :next_arg;
...@@ -1029,16 +983,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1029,16 +983,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1029 try options.undefine(symbol);983 try options.undefine(symbol);
1030 } else {984 } else {
1031 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };985 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };
1032 var msg_writer = err_details.msg.writer(allocator);986 try err_details.msg.print(allocator, "symbol \"{s}\" is not a valid identifier and therefore cannot be undefined", .{symbol});
1033 try msg_writer.print("symbol \"{s}\" is not a valid identifier and therefore cannot be undefined", .{symbol});
1034 try diagnostics.append(err_details);987 try diagnostics.append(err_details);
1035 }988 }
1036 arg_i += value.index_increment;989 arg_i += value.index_increment;
1037 continue :next_arg;990 continue :next_arg;
1038 } else {991 } else {
1039 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };992 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
1040 var msg_writer = err_details.msg.writer(allocator);993 try err_details.msg.print(allocator, "invalid option: {s}{s}", .{ arg.prefixSlice(), arg.name() });
1041 try msg_writer.print("invalid option: {s}{s}", .{ arg.prefixSlice(), arg.name() });
1042 try diagnostics.append(err_details);994 try diagnostics.append(err_details);
1043 arg_i += 1;995 arg_i += 1;
1044 continue :next_arg;996 continue :next_arg;
...@@ -1055,16 +1007,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1055,16 +1007,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
10551007
1056 if (positionals.len == 0) {1008 if (positionals.len == 0) {
1057 var err_details = Diagnostics.ErrorDetails{ .print_args = false, .arg_index = arg_i };1009 var err_details = Diagnostics.ErrorDetails{ .print_args = false, .arg_index = arg_i };
1058 var msg_writer = err_details.msg.writer(allocator);1010 try err_details.msg.appendSlice(allocator, "missing input filename");
1059 try msg_writer.writeAll("missing input filename");
1060 try diagnostics.append(err_details);1011 try diagnostics.append(err_details);
10611012
1062 if (args.len > 0) {1013 if (args.len > 0) {
1063 const last_arg = args[args.len - 1];1014 const last_arg = args[args.len - 1];
1064 if (arg_i > 0 and last_arg.len > 0 and last_arg[0] == '/' and isSupportedInputExtension(std.fs.path.extension(last_arg))) {1015 if (arg_i > 0 and last_arg.len > 0 and last_arg[0] == '/' and isSupportedInputExtension(std.fs.path.extension(last_arg))) {
1065 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i - 1 };1016 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i - 1 };
1066 var note_writer = note_details.msg.writer(allocator);1017 try note_details.msg.appendSlice(allocator, "if this argument was intended to be the input filename, adding -- in front of it will exclude it from option parsing");
1067 try note_writer.writeAll("if this argument was intended to be the input filename, adding -- in front of it will exclude it from option parsing");
1068 try diagnostics.append(note_details);1018 try diagnostics.append(note_details);
1069 }1019 }
1070 }1020 }
...@@ -1099,16 +1049,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1099,16 +1049,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1099 if (positionals.len > 1) {1049 if (positionals.len > 1) {
1100 if (output_filename != null) {1050 if (output_filename != null) {
1101 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i + 1 };1051 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i + 1 };
1102 var msg_writer = err_details.msg.writer(allocator);1052 try err_details.msg.appendSlice(allocator, "output filename already specified");
1103 try msg_writer.writeAll("output filename already specified");
1104 try diagnostics.append(err_details);1053 try diagnostics.append(err_details);
1105 var note_details = Diagnostics.ErrorDetails{1054 var note_details = Diagnostics.ErrorDetails{
1106 .type = .note,1055 .type = .note,
1107 .arg_index = output_filename_context.arg.index,1056 .arg_index = output_filename_context.arg.index,
1108 .arg_span = output_filename_context.arg.value.argSpan(output_filename_context.arg.arg),1057 .arg_span = output_filename_context.arg.value.argSpan(output_filename_context.arg.arg),
1109 };1058 };
1110 var note_writer = note_details.msg.writer(allocator);1059 try note_details.msg.appendSlice(allocator, "output filename previously specified here");
1111 try note_writer.writeAll("output filename previously specified here");
1112 try diagnostics.append(note_details);1060 try diagnostics.append(note_details);
1113 } else {1061 } else {
1114 output_filename = positionals[1];1062 output_filename = positionals[1];
...@@ -1173,16 +1121,15 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1173,16 +1121,15 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1173 var print_output_format_source_note: bool = false;1121 var print_output_format_source_note: bool = false;
1174 if (options.depfile_path != null and (options.input_format == .res or options.output_format == .rcpp)) {1122 if (options.depfile_path != null and (options.input_format == .res or options.output_format == .rcpp)) {
1175 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = depfile_context.index, .arg_span = depfile_context.value.argSpan(depfile_context.arg) };1123 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = depfile_context.index, .arg_span = depfile_context.value.argSpan(depfile_context.arg) };
1176 var msg_writer = err_details.msg.writer(allocator);
1177 if (options.input_format == .res) {1124 if (options.input_format == .res) {
1178 try msg_writer.print("the {s}{s} option was ignored because the input format is '{s}'", .{1125 try err_details.msg.print(allocator, "the {s}{s} option was ignored because the input format is '{s}'", .{
1179 depfile_context.arg.prefixSlice(),1126 depfile_context.arg.prefixSlice(),
1180 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),1127 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),
1181 @tagName(options.input_format),1128 @tagName(options.input_format),
1182 });1129 });
1183 print_input_format_source_note = true;1130 print_input_format_source_note = true;
1184 } else if (options.output_format == .rcpp) {1131 } else if (options.output_format == .rcpp) {
1185 try msg_writer.print("the {s}{s} option was ignored because the output format is '{s}'", .{1132 try err_details.msg.print(allocator, "the {s}{s} option was ignored because the output format is '{s}'", .{
1186 depfile_context.arg.prefixSlice(),1133 depfile_context.arg.prefixSlice(),
1187 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),1134 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),
1188 @tagName(options.output_format),1135 @tagName(options.output_format),
...@@ -1193,16 +1140,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1193,16 +1140,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1193 }1140 }
1194 if (!isSupportedTransformation(options.input_format, options.output_format)) {1141 if (!isSupportedTransformation(options.input_format, options.output_format)) {
1195 var err_details = Diagnostics.ErrorDetails{ .arg_index = input_filename_arg_i, .print_args = false };1142 var err_details = Diagnostics.ErrorDetails{ .arg_index = input_filename_arg_i, .print_args = false };
1196 var msg_writer = err_details.msg.writer(allocator);1143 try err_details.msg.print(allocator, "input format '{s}' cannot be converted to output format '{s}'", .{ @tagName(options.input_format), @tagName(options.output_format) });
1197 try msg_writer.print("input format '{s}' cannot be converted to output format '{s}'", .{ @tagName(options.input_format), @tagName(options.output_format) });
1198 try diagnostics.append(err_details);1144 try diagnostics.append(err_details);
1199 print_input_format_source_note = true;1145 print_input_format_source_note = true;
1200 print_output_format_source_note = true;1146 print_output_format_source_note = true;
1201 }1147 }
1202 if (options.preprocess == .only and options.output_format != .rcpp) {1148 if (options.preprocess == .only and options.output_format != .rcpp) {
1203 var err_details = Diagnostics.ErrorDetails{ .arg_index = preprocess_only_context.index };1149 var err_details = Diagnostics.ErrorDetails{ .arg_index = preprocess_only_context.index };
1204 var msg_writer = err_details.msg.writer(allocator);1150 try err_details.msg.print(allocator, "the {s}{s} option cannot be used with output format '{s}'", .{
1205 try msg_writer.print("the {s}{s} option cannot be used with output format '{s}'", .{
1206 preprocess_only_context.arg.prefixSlice(),1151 preprocess_only_context.arg.prefixSlice(),
1207 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),1152 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),
1208 @tagName(options.output_format),1153 @tagName(options.output_format),
...@@ -1214,8 +1159,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1214,8 +1159,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1214 switch (input_format_source) {1159 switch (input_format_source) {
1215 .inferred_from_input_filename => {1160 .inferred_from_input_filename => {
1216 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };1161 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };
1217 var msg_writer = err_details.msg.writer(allocator);1162 try err_details.msg.appendSlice(allocator, "the input format was inferred from the input filename");
1218 try msg_writer.writeAll("the input format was inferred from the input filename");
1219 try diagnostics.append(err_details);1163 try diagnostics.append(err_details);
1220 },1164 },
1221 .input_format_arg => {1165 .input_format_arg => {
...@@ -1224,8 +1168,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1224,8 +1168,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1224 .arg_index = input_format_context.index,1168 .arg_index = input_format_context.index,
1225 .arg_span = input_format_context.value.argSpan(input_format_context.arg),1169 .arg_span = input_format_context.value.argSpan(input_format_context.arg),
1226 };1170 };
1227 var msg_writer = err_details.msg.writer(allocator);1171 try err_details.msg.appendSlice(allocator, "the input format was specified here");
1228 try msg_writer.writeAll("the input format was specified here");
1229 try diagnostics.append(err_details);1172 try diagnostics.append(err_details);
1230 },1173 },
1231 }1174 }
...@@ -1234,11 +1177,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1234,11 +1177,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1234 switch (output_format_source) {1177 switch (output_format_source) {
1235 .inferred_from_input_filename, .unable_to_infer_from_input_filename => {1178 .inferred_from_input_filename, .unable_to_infer_from_input_filename => {
1236 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };1179 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };
1237 var msg_writer = err_details.msg.writer(allocator);
1238 if (output_format_source == .inferred_from_input_filename) {1180 if (output_format_source == .inferred_from_input_filename) {
1239 try msg_writer.writeAll("the output format was inferred from the input filename");1181 try err_details.msg.appendSlice(allocator, "the output format was inferred from the input filename");
1240 } else {1182 } else {
1241 try msg_writer.writeAll("the output format was unable to be inferred from the input filename, so the default was used");1183 try err_details.msg.appendSlice(allocator, "the output format was unable to be inferred from the input filename, so the default was used");
1242 }1184 }
1243 try diagnostics.append(err_details);1185 try diagnostics.append(err_details);
1244 },1186 },
...@@ -1248,11 +1190,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1248,11 +1190,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1248 .arg => |ctx| .{ .type = .note, .arg_index = ctx.index, .arg_span = ctx.value.argSpan(ctx.arg) },1190 .arg => |ctx| .{ .type = .note, .arg_index = ctx.index, .arg_span = ctx.value.argSpan(ctx.arg) },
1249 .unspecified => unreachable,1191 .unspecified => unreachable,
1250 };1192 };
1251 var msg_writer = err_details.msg.writer(allocator);
1252 if (output_format_source == .inferred_from_output_filename) {1193 if (output_format_source == .inferred_from_output_filename) {
1253 try msg_writer.writeAll("the output format was inferred from the output filename");1194 try err_details.msg.appendSlice(allocator, "the output format was inferred from the output filename");
1254 } else {1195 } else {
1255 try msg_writer.writeAll("the output format was unable to be inferred from the output filename, so the default was used");1196 try err_details.msg.appendSlice(allocator, "the output format was unable to be inferred from the output filename, so the default was used");
1256 }1197 }
1257 try diagnostics.append(err_details);1198 try diagnostics.append(err_details);
1258 },1199 },
...@@ -1262,14 +1203,12 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1262,14 +1203,12 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1262 .arg_index = output_format_context.index,1203 .arg_index = output_format_context.index,
1263 .arg_span = output_format_context.value.argSpan(output_format_context.arg),1204 .arg_span = output_format_context.value.argSpan(output_format_context.arg),
1264 };1205 };
1265 var msg_writer = err_details.msg.writer(allocator);1206 try err_details.msg.appendSlice(allocator, "the output format was specified here");
1266 try msg_writer.writeAll("the output format was specified here");
1267 try diagnostics.append(err_details);1207 try diagnostics.append(err_details);
1268 },1208 },
1269 .inferred_from_preprocess_only => {1209 .inferred_from_preprocess_only => {
1270 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = preprocess_only_context.index };1210 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = preprocess_only_context.index };
1271 var msg_writer = err_details.msg.writer(allocator);1211 try err_details.msg.print(allocator, "the output format was inferred from the usage of the {s}{s} option", .{
1272 try msg_writer.print("the output format was inferred from the usage of the {s}{s} option", .{
1273 preprocess_only_context.arg.prefixSlice(),1212 preprocess_only_context.arg.prefixSlice(),
1274 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),1213 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),
1275 });1214 });
lib/compiler/resinator/compile.zig+56-114
...@@ -61,7 +61,7 @@ pub const CompileOptions = struct {...@@ -61,7 +61,7 @@ pub const CompileOptions = struct {
61 warn_instead_of_error_on_invalid_code_page: bool = false,61 warn_instead_of_error_on_invalid_code_page: bool = false,
62};62};
6363
64pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, options: CompileOptions) !void {64pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer, options: CompileOptions) !void {
65 var lexer = lex.Lexer.init(source, .{65 var lexer = lex.Lexer.init(source, .{
66 .default_code_page = options.default_code_page,66 .default_code_page = options.default_code_page,
67 .source_mappings = options.source_mappings,67 .source_mappings = options.source_mappings,
...@@ -194,7 +194,7 @@ pub const Compiler = struct {...@@ -194,7 +194,7 @@ pub const Compiler = struct {
194 characteristics: u32 = 0,194 characteristics: u32 = 0,
195 };195 };
196196
197 pub fn writeRoot(self: *Compiler, root: *Node.Root, writer: anytype) !void {197 pub fn writeRoot(self: *Compiler, root: *Node.Root, writer: *std.Io.Writer) !void {
198 try writeEmptyResource(writer);198 try writeEmptyResource(writer);
199 for (root.body) |node| {199 for (root.body) |node| {
200 try self.writeNode(node, writer);200 try self.writeNode(node, writer);
...@@ -236,7 +236,7 @@ pub const Compiler = struct {...@@ -236,7 +236,7 @@ pub const Compiler = struct {
236 }236 }
237 }237 }
238238
239 pub fn writeNode(self: *Compiler, node: *Node, writer: anytype) !void {239 pub fn writeNode(self: *Compiler, node: *Node, writer: *std.Io.Writer) !void {
240 switch (node.id) {240 switch (node.id) {
241 .root => unreachable, // writeRoot should be called directly instead241 .root => unreachable, // writeRoot should be called directly instead
242 .resource_external => try self.writeResourceExternal(@alignCast(@fieldParentPtr("base", node)), writer),242 .resource_external => try self.writeResourceExternal(@alignCast(@fieldParentPtr("base", node)), writer),
...@@ -479,7 +479,7 @@ pub const Compiler = struct {...@@ -479,7 +479,7 @@ pub const Compiler = struct {
479 return buf.toOwnedSlice();479 return buf.toOwnedSlice();
480 }480 }
481481
482 pub fn writeResourceExternal(self: *Compiler, node: *Node.ResourceExternal, writer: anytype) !void {482 pub fn writeResourceExternal(self: *Compiler, node: *Node.ResourceExternal, writer: *std.Io.Writer) !void {
483 // Init header with data size zero for now, will need to fill it in later483 // Init header with data size zero for now, will need to fill it in later
484 var header = try self.resourceHeader(node.id, node.type, .{});484 var header = try self.resourceHeader(node.id, node.type, .{});
485 defer header.deinit(self.allocator);485 defer header.deinit(self.allocator);
...@@ -1226,33 +1226,31 @@ pub const Compiler = struct {...@@ -1226,33 +1226,31 @@ pub const Compiler = struct {
1226 }1226 }
12271227
1228 pub fn writeResourceRawData(self: *Compiler, node: *Node.ResourceRawData, writer: anytype) !void {1228 pub fn writeResourceRawData(self: *Compiler, node: *Node.ResourceRawData, writer: anytype) !void {
1229 var data_buffer = std.array_list.Managed(u8).init(self.allocator);1229 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1230 defer data_buffer.deinit();1230 defer data_buffer.deinit();
1231 // The header's data length field is a u32 so limit the resource's data size so that1231 // The header's data length field is a u32 so limit the resource's data size so that
1232 // we know we can always specify the real size.1232 // we know we can always specify the real size.
1233 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));1233 const data_writer = &data_buffer.writer;
1234 const data_writer = limited_writer.writer();
12351234
1236 for (node.raw_data) |expression| {1235 for (node.raw_data) |expression| {
1237 const data = try self.evaluateDataExpression(expression);1236 const data = try self.evaluateDataExpression(expression);
1238 defer data.deinit(self.allocator);1237 defer data.deinit(self.allocator);
1239 data.write(data_writer) catch |err| switch (err) {1238 data.write(data_writer) catch |err| switch (err) {
1240 error.NoSpaceLeft => {1239 error.WriteFailed => {
1241 return self.addErrorDetailsAndFail(.{1240 return self.addErrorDetailsAndFail(.{
1242 .err = .resource_data_size_exceeds_max,1241 .err = .resource_data_size_exceeds_max,
1243 .token = node.id,1242 .token = node.id,
1244 });1243 });
1245 },1244 },
1246 else => |e| return e,
1247 };1245 };
1248 }1246 }
12491247
1250 // This intCast can't fail because the limitedWriter above guarantees that1248 // This intCast can't fail because the limitedWriter above guarantees that
1251 // we will never write more than maxInt(u32) bytes.1249 // we will never write more than maxInt(u32) bytes.
1252 const data_len: u32 = @intCast(data_buffer.items.len);1250 const data_len: u32 = @intCast(data_buffer.written().len);
1253 try self.writeResourceHeader(writer, node.id, node.type, data_len, node.common_resource_attributes, self.state.language);1251 try self.writeResourceHeader(writer, node.id, node.type, data_len, node.common_resource_attributes, self.state.language);
12541252
1255 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);1253 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
1256 try writeResourceData(writer, &data_fbs, data_len);1254 try writeResourceData(writer, &data_fbs, data_len);
1257 }1255 }
12581256
...@@ -1306,16 +1304,15 @@ pub const Compiler = struct {...@@ -1306,16 +1304,15 @@ pub const Compiler = struct {
1306 }1304 }
13071305
1308 pub fn writeAccelerators(self: *Compiler, node: *Node.Accelerators, writer: anytype) !void {1306 pub fn writeAccelerators(self: *Compiler, node: *Node.Accelerators, writer: anytype) !void {
1309 var data_buffer = std.array_list.Managed(u8).init(self.allocator);1307 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1310 defer data_buffer.deinit();1308 defer data_buffer.deinit();
13111309
1312 // The header's data length field is a u32 so limit the resource's data size so that1310 // The header's data length field is a u32 so limit the resource's data size so that
1313 // we know we can always specify the real size.1311 // we know we can always specify the real size.
1314 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));1312 const data_writer = &data_buffer.writer;
1315 const data_writer = limited_writer.writer();
13161313
1317 self.writeAcceleratorsData(node, data_writer) catch |err| switch (err) {1314 self.writeAcceleratorsData(node, data_writer) catch |err| switch (err) {
1318 error.NoSpaceLeft => {1315 error.WriteFailed => {
1319 return self.addErrorDetailsAndFail(.{1316 return self.addErrorDetailsAndFail(.{
1320 .err = .resource_data_size_exceeds_max,1317 .err = .resource_data_size_exceeds_max,
1321 .token = node.id,1318 .token = node.id,
...@@ -1326,7 +1323,7 @@ pub const Compiler = struct {...@@ -1326,7 +1323,7 @@ pub const Compiler = struct {
13261323
1327 // This intCast can't fail because the limitedWriter above guarantees that1324 // This intCast can't fail because the limitedWriter above guarantees that
1328 // we will never write more than maxInt(u32) bytes.1325 // we will never write more than maxInt(u32) bytes.
1329 const data_size: u32 = @intCast(data_buffer.items.len);1326 const data_size: u32 = @intCast(data_buffer.written().len);
1330 var header = try self.resourceHeader(node.id, node.type, .{1327 var header = try self.resourceHeader(node.id, node.type, .{
1331 .data_size = data_size,1328 .data_size = data_size,
1332 });1329 });
...@@ -1337,7 +1334,7 @@ pub const Compiler = struct {...@@ -1337,7 +1334,7 @@ pub const Compiler = struct {
13371334
1338 try header.write(writer, self.errContext(node.id));1335 try header.write(writer, self.errContext(node.id));
13391336
1340 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);1337 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
1341 try writeResourceData(writer, &data_fbs, data_size);1338 try writeResourceData(writer, &data_fbs, data_size);
1342 }1339 }
13431340
...@@ -1405,12 +1402,11 @@ pub const Compiler = struct {...@@ -1405,12 +1402,11 @@ pub const Compiler = struct {
1405 };1402 };
14061403
1407 pub fn writeDialog(self: *Compiler, node: *Node.Dialog, writer: anytype) !void {1404 pub fn writeDialog(self: *Compiler, node: *Node.Dialog, writer: anytype) !void {
1408 var data_buffer = std.array_list.Managed(u8).init(self.allocator);1405 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1409 defer data_buffer.deinit();1406 defer data_buffer.deinit();
1410 // The header's data length field is a u32 so limit the resource's data size so that1407 // The header's data length field is a u32 so limit the resource's data size so that
1411 // we know we can always specify the real size.1408 // we know we can always specify the real size.
1412 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));1409 const data_writer = &data_buffer.writer;
1413 const data_writer = limited_writer.writer();
14141410
1415 const resource = ResourceType.fromString(.{1411 const resource = ResourceType.fromString(.{
1416 .slice = node.type.slice(self.source),1412 .slice = node.type.slice(self.source),
...@@ -1683,7 +1679,7 @@ pub const Compiler = struct {...@@ -1683,7 +1679,7 @@ pub const Compiler = struct {
1683 ) catch |err| switch (err) {1679 ) catch |err| switch (err) {
1684 // Dialog header and menu/class/title strings can never exceed u32 bytes1680 // Dialog header and menu/class/title strings can never exceed u32 bytes
1685 // on their own, so this error is unreachable.1681 // on their own, so this error is unreachable.
1686 error.NoSpaceLeft => unreachable,1682 error.WriteFailed => unreachable,
1687 else => |e| return e,1683 else => |e| return e,
1688 };1684 };
16891685
...@@ -1700,10 +1696,10 @@ pub const Compiler = struct {...@@ -1700,10 +1696,10 @@ pub const Compiler = struct {
1700 data_writer,1696 data_writer,
1701 resource,1697 resource,
1702 // We know the data_buffer len is limited to u32 max.1698 // We know the data_buffer len is limited to u32 max.
1703 @intCast(data_buffer.items.len),1699 @intCast(data_buffer.written().len),
1704 &controls_by_id,1700 &controls_by_id,
1705 ) catch |err| switch (err) {1701 ) catch |err| switch (err) {
1706 error.NoSpaceLeft => {1702 error.WriteFailed => {
1707 try self.addErrorDetails(.{1703 try self.addErrorDetails(.{
1708 .err = .resource_data_size_exceeds_max,1704 .err = .resource_data_size_exceeds_max,
1709 .token = node.id,1705 .token = node.id,
...@@ -1719,7 +1715,7 @@ pub const Compiler = struct {...@@ -1719,7 +1715,7 @@ pub const Compiler = struct {
1719 }1715 }
17201716
1721 // We know the data_buffer len is limited to u32 max.1717 // We know the data_buffer len is limited to u32 max.
1722 const data_size: u32 = @intCast(data_buffer.items.len);1718 const data_size: u32 = @intCast(data_buffer.written().len);
1723 var header = try self.resourceHeader(node.id, node.type, .{1719 var header = try self.resourceHeader(node.id, node.type, .{
1724 .data_size = data_size,1720 .data_size = data_size,
1725 });1721 });
...@@ -1730,7 +1726,7 @@ pub const Compiler = struct {...@@ -1730,7 +1726,7 @@ pub const Compiler = struct {
17301726
1731 try header.write(writer, self.errContext(node.id));1727 try header.write(writer, self.errContext(node.id));
17321728
1733 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);1729 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
1734 try writeResourceData(writer, &data_fbs, data_size);1730 try writeResourceData(writer, &data_fbs, data_size);
1735 }1731 }
17361732
...@@ -1821,7 +1817,7 @@ pub const Compiler = struct {...@@ -1821,7 +1817,7 @@ pub const Compiler = struct {
1821 .token = control.type,1817 .token = control.type,
1822 });1818 });
1823 }1819 }
1824 try data_writer.writeByteNTimes(0, num_padding);1820 try data_writer.splatByteAll(0, num_padding);
18251821
1826 const style = if (control.style) |style_expression|1822 const style = if (control.style) |style_expression|
1827 // Certain styles are implied by the control type1823 // Certain styles are implied by the control type
...@@ -1973,16 +1969,15 @@ pub const Compiler = struct {...@@ -1973,16 +1969,15 @@ pub const Compiler = struct {
1973 try NameOrOrdinal.writeEmpty(data_writer);1969 try NameOrOrdinal.writeEmpty(data_writer);
1974 }1970 }
19751971
1976 var extra_data_buf = std.array_list.Managed(u8).init(self.allocator);1972 var extra_data_buf: std.Io.Writer.Allocating = .init(self.allocator);
1977 defer extra_data_buf.deinit();1973 defer extra_data_buf.deinit();
1978 // The extra data byte length must be able to fit within a u16.1974 // The extra data byte length must be able to fit within a u16.
1979 var limited_extra_data_writer = limitedWriter(extra_data_buf.writer(), std.math.maxInt(u16));1975 const extra_data_writer = &extra_data_buf.writer;
1980 const extra_data_writer = limited_extra_data_writer.writer();
1981 for (control.extra_data) |data_expression| {1976 for (control.extra_data) |data_expression| {
1982 const data = try self.evaluateDataExpression(data_expression);1977 const data = try self.evaluateDataExpression(data_expression);
1983 defer data.deinit(self.allocator);1978 defer data.deinit(self.allocator);
1984 data.write(extra_data_writer) catch |err| switch (err) {1979 data.write(extra_data_writer) catch |err| switch (err) {
1985 error.NoSpaceLeft => {1980 error.WriteFailed => {
1986 try self.addErrorDetails(.{1981 try self.addErrorDetails(.{
1987 .err = .control_extra_data_size_exceeds_max,1982 .err = .control_extra_data_size_exceeds_max,
1988 .token = control.type,1983 .token = control.type,
...@@ -1998,15 +1993,15 @@ pub const Compiler = struct {...@@ -1998,15 +1993,15 @@ pub const Compiler = struct {
1998 };1993 };
1999 }1994 }
2000 // We know the extra_data_buf size fits within a u16.1995 // We know the extra_data_buf size fits within a u16.
2001 const extra_data_size: u16 = @intCast(extra_data_buf.items.len);1996 const extra_data_size: u16 = @intCast(extra_data_buf.written().len);
2002 try data_writer.writeInt(u16, extra_data_size, .little);1997 try data_writer.writeInt(u16, extra_data_size, .little);
2003 try data_writer.writeAll(extra_data_buf.items);1998 try data_writer.writeAll(extra_data_buf.written());
2004 }1999 }
20052000
2006 pub fn writeToolbar(self: *Compiler, node: *Node.Toolbar, writer: anytype) !void {2001 pub fn writeToolbar(self: *Compiler, node: *Node.Toolbar, writer: anytype) !void {
2007 var data_buffer = std.array_list.Managed(u8).init(self.allocator);2002 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2008 defer data_buffer.deinit();2003 defer data_buffer.deinit();
2009 const data_writer = data_buffer.writer();2004 const data_writer = &data_buffer.writer;
20102005
2011 const button_width = evaluateNumberExpression(node.button_width, self.source, self.input_code_pages);2006 const button_width = evaluateNumberExpression(node.button_width, self.source, self.input_code_pages);
2012 const button_height = evaluateNumberExpression(node.button_height, self.source, self.input_code_pages);2007 const button_height = evaluateNumberExpression(node.button_height, self.source, self.input_code_pages);
...@@ -2034,7 +2029,7 @@ pub const Compiler = struct {...@@ -2034,7 +2029,7 @@ pub const Compiler = struct {
2034 }2029 }
2035 }2030 }
20362031
2037 const data_size: u32 = @intCast(data_buffer.items.len);2032 const data_size: u32 = @intCast(data_buffer.written().len);
2038 var header = try self.resourceHeader(node.id, node.type, .{2033 var header = try self.resourceHeader(node.id, node.type, .{
2039 .data_size = data_size,2034 .data_size = data_size,
2040 });2035 });
...@@ -2044,7 +2039,7 @@ pub const Compiler = struct {...@@ -2044,7 +2039,7 @@ pub const Compiler = struct {
20442039
2045 try header.write(writer, self.errContext(node.id));2040 try header.write(writer, self.errContext(node.id));
20462041
2047 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);2042 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
2048 try writeResourceData(writer, &data_fbs, data_size);2043 try writeResourceData(writer, &data_fbs, data_size);
2049 }2044 }
20502045
...@@ -2082,12 +2077,11 @@ pub const Compiler = struct {...@@ -2082,12 +2077,11 @@ pub const Compiler = struct {
2082 }2077 }
20832078
2084 pub fn writeMenu(self: *Compiler, node: *Node.Menu, writer: anytype) !void {2079 pub fn writeMenu(self: *Compiler, node: *Node.Menu, writer: anytype) !void {
2085 var data_buffer = std.array_list.Managed(u8).init(self.allocator);2080 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2086 defer data_buffer.deinit();2081 defer data_buffer.deinit();
2087 // The header's data length field is a u32 so limit the resource's data size so that2082 // The header's data length field is a u32 so limit the resource's data size so that
2088 // we know we can always specify the real size.2083 // we know we can always specify the real size.
2089 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));2084 const data_writer = &data_buffer.writer;
2090 const data_writer = limited_writer.writer();
20912085
2092 const type_bytes = SourceBytes{2086 const type_bytes = SourceBytes{
2093 .slice = node.type.slice(self.source),2087 .slice = node.type.slice(self.source),
...@@ -2096,9 +2090,7 @@ pub const Compiler = struct {...@@ -2096,9 +2090,7 @@ pub const Compiler = struct {
2096 const resource = ResourceType.fromString(type_bytes);2090 const resource = ResourceType.fromString(type_bytes);
2097 std.debug.assert(resource == .menu or resource == .menuex);2091 std.debug.assert(resource == .menu or resource == .menuex);
20982092
2099 var adapted = data_writer.adaptToNewApi(&.{});2093 self.writeMenuData(node, data_writer, resource) catch |err| switch (err) {
2100
2101 self.writeMenuData(node, &adapted.new_interface, resource) catch |err| switch (err) {
2102 error.WriteFailed => {2094 error.WriteFailed => {
2103 return self.addErrorDetailsAndFail(.{2095 return self.addErrorDetailsAndFail(.{
2104 .err = .resource_data_size_exceeds_max,2096 .err = .resource_data_size_exceeds_max,
...@@ -2110,7 +2102,7 @@ pub const Compiler = struct {...@@ -2110,7 +2102,7 @@ pub const Compiler = struct {
21102102
2111 // This intCast can't fail because the limitedWriter above guarantees that2103 // This intCast can't fail because the limitedWriter above guarantees that
2112 // we will never write more than maxInt(u32) bytes.2104 // we will never write more than maxInt(u32) bytes.
2113 const data_size: u32 = @intCast(data_buffer.items.len);2105 const data_size: u32 = @intCast(data_buffer.written().len);
2114 var header = try self.resourceHeader(node.id, node.type, .{2106 var header = try self.resourceHeader(node.id, node.type, .{
2115 .data_size = data_size,2107 .data_size = data_size,
2116 });2108 });
...@@ -2121,7 +2113,7 @@ pub const Compiler = struct {...@@ -2121,7 +2113,7 @@ pub const Compiler = struct {
21212113
2122 try header.write(writer, self.errContext(node.id));2114 try header.write(writer, self.errContext(node.id));
21232115
2124 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);2116 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
2125 try writeResourceData(writer, &data_fbs, data_size);2117 try writeResourceData(writer, &data_fbs, data_size);
2126 }2118 }
21272119
...@@ -2265,12 +2257,11 @@ pub const Compiler = struct {...@@ -2265,12 +2257,11 @@ pub const Compiler = struct {
2265 }2257 }
22662258
2267 pub fn writeVersionInfo(self: *Compiler, node: *Node.VersionInfo, writer: anytype) !void {2259 pub fn writeVersionInfo(self: *Compiler, node: *Node.VersionInfo, writer: anytype) !void {
2268 var data_buffer = std.array_list.Managed(u8).init(self.allocator);2260 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2269 defer data_buffer.deinit();2261 defer data_buffer.deinit();
2270 // The node's length field (which is inclusive of the length of all of its children) is a u162262 // The node's length field (which is inclusive of the length of all of its children) is a u16
2271 // so limit the node's data size so that we know we can always specify the real size.2263 // so limit the node's data size so that we know we can always specify the real size.
2272 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u16));2264 const data_writer = &data_buffer.writer;
2273 const data_writer = limited_writer.writer();
22742265
2275 try data_writer.writeInt(u16, 0, .little); // placeholder size2266 try data_writer.writeInt(u16, 0, .little); // placeholder size
2276 try data_writer.writeInt(u16, res.FixedFileInfo.byte_len, .little);2267 try data_writer.writeInt(u16, res.FixedFileInfo.byte_len, .little);
...@@ -2354,8 +2345,7 @@ pub const Compiler = struct {...@@ -2354,8 +2345,7 @@ pub const Compiler = struct {
2354 try fixed_file_info.write(data_writer);2345 try fixed_file_info.write(data_writer);
23552346
2356 for (node.block_statements) |statement| {2347 for (node.block_statements) |statement| {
2357 var adapted = data_writer.adaptToNewApi(&.{});2348 self.writeVersionNode(statement, data_writer, &data_buffer) catch |err| switch (err) {
2358 self.writeVersionNode(statement, &adapted.new_interface, &data_buffer) catch |err| switch (err) {
2359 error.WriteFailed => {2349 error.WriteFailed => {
2360 try self.addErrorDetails(.{2350 try self.addErrorDetails(.{
2361 .err = .version_node_size_exceeds_max,2351 .err = .version_node_size_exceeds_max,
...@@ -2374,9 +2364,9 @@ pub const Compiler = struct {...@@ -2374,9 +2364,9 @@ pub const Compiler = struct {
23742364
2375 // We know that data_buffer.items.len is within the limits of a u16, since we2365 // We know that data_buffer.items.len is within the limits of a u16, since we
2376 // limited the writer to maxInt(u16)2366 // limited the writer to maxInt(u16)
2377 const data_size: u16 = @intCast(data_buffer.items.len);2367 const data_size: u16 = @intCast(data_buffer.written().len);
2378 // And now that we know the full size of this node (including its children), set its size2368 // And now that we know the full size of this node (including its children), set its size
2379 std.mem.writeInt(u16, data_buffer.items[0..2], data_size, .little);2369 std.mem.writeInt(u16, data_buffer.written()[0..2], data_size, .little);
23802370
2381 var header = try self.resourceHeader(node.id, node.versioninfo, .{2371 var header = try self.resourceHeader(node.id, node.versioninfo, .{
2382 .data_size = data_size,2372 .data_size = data_size,
...@@ -2387,22 +2377,22 @@ pub const Compiler = struct {...@@ -2387,22 +2377,22 @@ pub const Compiler = struct {
23872377
2388 try header.write(writer, self.errContext(node.id));2378 try header.write(writer, self.errContext(node.id));
23892379
2390 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);2380 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
2391 try writeResourceData(writer, &data_fbs, data_size);2381 try writeResourceData(writer, &data_fbs, data_size);
2392 }2382 }
23932383
2394 /// Expects writer to be a LimitedWriter limited to u16, meaning all writes to2384 /// Expects writer to be a LimitedWriter limited to u16, meaning all writes to
2395 /// the writer within this function could return error.NoSpaceLeft, and that buf.items.len2385 /// the writer within this function could return error.NoSpaceLeft, and that buf.items.len
2396 /// will never be able to exceed maxInt(u16).2386 /// will never be able to exceed maxInt(u16).
2397 pub fn writeVersionNode(self: *Compiler, node: *Node, writer: *std.Io.Writer, buf: *std.array_list.Managed(u8)) !void {2387 pub fn writeVersionNode(self: *Compiler, node: *Node, writer: *std.Io.Writer, buf: *std.Io.Writer.Allocating) !void {
2398 // We can assume that buf.items.len will never be able to exceed the limits of a u162388 // We can assume that buf.items.len will never be able to exceed the limits of a u16
2399 try writeDataPadding(writer, @as(u16, @intCast(buf.items.len)));2389 try writeDataPadding(writer, @as(u16, @intCast(buf.written().len)));
24002390
2401 const node_and_children_size_offset = buf.items.len;2391 const node_and_children_size_offset = buf.written().len;
2402 try writer.writeInt(u16, 0, .little); // placeholder for size2392 try writer.writeInt(u16, 0, .little); // placeholder for size
2403 const data_size_offset = buf.items.len;2393 const data_size_offset = buf.written().len;
2404 try writer.writeInt(u16, 0, .little); // placeholder for data size2394 try writer.writeInt(u16, 0, .little); // placeholder for data size
2405 const data_type_offset = buf.items.len;2395 const data_type_offset = buf.written().len;
2406 // Data type is string unless the node contains values that are numbers.2396 // Data type is string unless the node contains values that are numbers.
2407 try writer.writeInt(u16, res.VersionNode.type_string, .little);2397 try writer.writeInt(u16, res.VersionNode.type_string, .little);
24082398
...@@ -2432,7 +2422,7 @@ pub const Compiler = struct {...@@ -2432,7 +2422,7 @@ pub const Compiler = struct {
2432 // during parsing, so we can just do the correct thing here.2422 // during parsing, so we can just do the correct thing here.
2433 var values_size: usize = 0;2423 var values_size: usize = 0;
24342424
2435 try writeDataPadding(writer, @intCast(buf.items.len));2425 try writeDataPadding(writer, @intCast(buf.written().len));
24362426
2437 for (block_or_value.values, 0..) |value_value_node_uncasted, i| {2427 for (block_or_value.values, 0..) |value_value_node_uncasted, i| {
2438 const value_value_node = value_value_node_uncasted.cast(.block_value_value).?;2428 const value_value_node = value_value_node_uncasted.cast(.block_value_value).?;
...@@ -2471,11 +2461,11 @@ pub const Compiler = struct {...@@ -2471,11 +2461,11 @@ pub const Compiler = struct {
2471 }2461 }
2472 }2462 }
2473 }2463 }
2474 var data_size_slice = buf.items[data_size_offset..];2464 var data_size_slice = buf.written()[data_size_offset..];
2475 std.mem.writeInt(u16, data_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(values_size)), .little);2465 std.mem.writeInt(u16, data_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(values_size)), .little);
24762466
2477 if (has_number_value) {2467 if (has_number_value) {
2478 const data_type_slice = buf.items[data_type_offset..];2468 const data_type_slice = buf.written()[data_type_offset..];
2479 std.mem.writeInt(u16, data_type_slice[0..@sizeOf(u16)], res.VersionNode.type_binary, .little);2469 std.mem.writeInt(u16, data_type_slice[0..@sizeOf(u16)], res.VersionNode.type_binary, .little);
2480 }2470 }
24812471
...@@ -2489,8 +2479,8 @@ pub const Compiler = struct {...@@ -2489,8 +2479,8 @@ pub const Compiler = struct {
2489 else => unreachable,2479 else => unreachable,
2490 }2480 }
24912481
2492 const node_and_children_size = buf.items.len - node_and_children_size_offset;2482 const node_and_children_size = buf.written().len - node_and_children_size_offset;
2493 const node_and_children_size_slice = buf.items[node_and_children_size_offset..];2483 const node_and_children_size_slice = buf.written()[node_and_children_size_offset..];
2494 std.mem.writeInt(u16, node_and_children_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(node_and_children_size)), .little);2484 std.mem.writeInt(u16, node_and_children_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(node_and_children_size)), .little);
2495 }2485 }
24962486
...@@ -2973,54 +2963,6 @@ pub fn headerSlurpingReader(comptime size: usize, reader: anytype) HeaderSlurpin...@@ -2973,54 +2963,6 @@ pub fn headerSlurpingReader(comptime size: usize, reader: anytype) HeaderSlurpin
2973 return .{ .child_reader = reader };2963 return .{ .child_reader = reader };
2974}2964}
29752965
2976/// Sort of like std.io.LimitedReader, but a Writer.
2977/// Returns an error if writing the requested number of bytes
2978/// would ever exceed bytes_left, i.e. it does not always
2979/// write up to the limit and instead will error if the
2980/// limit would be breached if the entire slice was written.
2981pub fn LimitedWriter(comptime WriterType: type) type {
2982 return struct {
2983 inner_writer: WriterType,
2984 bytes_left: u64,
2985
2986 pub const Error = error{NoSpaceLeft} || WriterType.Error;
2987 pub const Writer = std.io.GenericWriter(*Self, Error, write);
2988
2989 const Self = @This();
2990
2991 pub fn write(self: *Self, bytes: []const u8) Error!usize {
2992 if (bytes.len > self.bytes_left) return error.NoSpaceLeft;
2993 const amt = try self.inner_writer.write(bytes);
2994 self.bytes_left -= amt;
2995 return amt;
2996 }
2997
2998 pub fn writer(self: *Self) Writer {
2999 return .{ .context = self };
3000 }
3001 };
3002}
3003
3004/// Returns an initialised `LimitedWriter`
3005/// `bytes_left` is a `u64` to be able to take 64 bit file offsets
3006pub fn limitedWriter(inner_writer: anytype, bytes_left: u64) LimitedWriter(@TypeOf(inner_writer)) {
3007 return .{ .inner_writer = inner_writer, .bytes_left = bytes_left };
3008}
3009
3010test "limitedWriter basic usage" {
3011 var buf: [4]u8 = undefined;
3012 var fbs = std.io.fixedBufferStream(&buf);
3013 var limited_stream = limitedWriter(fbs.writer(), 4);
3014 var writer = limited_stream.writer();
3015
3016 try std.testing.expectEqual(@as(usize, 3), try writer.write("123"));
3017 try std.testing.expectEqualSlices(u8, "123", buf[0..3]);
3018 try std.testing.expectError(error.NoSpaceLeft, writer.write("45"));
3019 try std.testing.expectEqual(@as(usize, 1), try writer.write("4"));
3020 try std.testing.expectEqualSlices(u8, "1234", buf[0..4]);
3021 try std.testing.expectError(error.NoSpaceLeft, writer.write("5"));
3022}
3023
3024pub const FontDir = struct {2966pub const FontDir = struct {
3025 fonts: std.ArrayListUnmanaged(Font) = .empty,2967 fonts: std.ArrayListUnmanaged(Font) = .empty,
3026 /// To keep track of which ids are set and where they were set from2968 /// To keep track of which ids are set and where they were set from
...@@ -3246,9 +3188,9 @@ pub const StringTable = struct {...@@ -3246,9 +3188,9 @@ pub const StringTable = struct {
3246 }3188 }
32473189
3248 pub fn writeResData(self: *Block, compiler: *Compiler, language: res.Language, block_id: u16, writer: anytype) !void {3190 pub fn writeResData(self: *Block, compiler: *Compiler, language: res.Language, block_id: u16, writer: anytype) !void {
3249 var data_buffer = std.array_list.Managed(u8).init(compiler.allocator);3191 var data_buffer: std.Io.Writer.Allocating = .init(compiler.allocator);
3250 defer data_buffer.deinit();3192 defer data_buffer.deinit();
3251 const data_writer = data_buffer.writer();3193 const data_writer = &data_buffer.writer;
32523194
3253 var i: u8 = 0;3195 var i: u8 = 0;
3254 var string_i: u8 = 0;3196 var string_i: u8 = 0;
...@@ -3307,7 +3249,7 @@ pub const StringTable = struct {...@@ -3307,7 +3249,7 @@ pub const StringTable = struct {
3307 // 16 * (131,070 + 2) = 2,097,152 which is well within the u32 max.3249 // 16 * (131,070 + 2) = 2,097,152 which is well within the u32 max.
3308 //3250 //
3309 // Note: The string literal maximum length is enforced by the lexer.3251 // Note: The string literal maximum length is enforced by the lexer.
3310 const data_size: u32 = @intCast(data_buffer.items.len);3252 const data_size: u32 = @intCast(data_buffer.written().len);
33113253
3312 const header = Compiler.ResourceHeader{3254 const header = Compiler.ResourceHeader{
3313 .name_value = .{ .ordinal = block_id },3255 .name_value = .{ .ordinal = block_id },
...@@ -3322,7 +3264,7 @@ pub const StringTable = struct {...@@ -3322,7 +3264,7 @@ pub const StringTable = struct {
3322 // we fully control and know are numbers, so they have a fixed size.3264 // we fully control and know are numbers, so they have a fixed size.
3323 try header.writeAssertNoOverflow(writer);3265 try header.writeAssertNoOverflow(writer);
33243266
3325 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);3267 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
3326 try Compiler.writeResourceData(writer, &data_fbs, data_size);3268 try Compiler.writeResourceData(writer, &data_fbs, data_size);
3327 }3269 }
3328 };3270 };
lib/compiler/resinator/errors.zig+6-8
...@@ -1102,11 +1102,10 @@ const CorrespondingLines = struct {...@@ -1102,11 +1102,10 @@ const CorrespondingLines = struct {
1102 corresponding_lines.buffered_reader = corresponding_lines.file.reader(&.{});1102 corresponding_lines.buffered_reader = corresponding_lines.file.reader(&.{});
1103 errdefer corresponding_lines.deinit();1103 errdefer corresponding_lines.deinit();
11041104
1105 var fbs = std.io.fixedBufferStream(&corresponding_lines.line_buf);1105 var writer: std.Io.Writer = .fixed(&corresponding_lines.line_buf);
1106 const writer = fbs.writer();
11071106
1108 try corresponding_lines.writeLineFromStreamVerbatim(1107 try corresponding_lines.writeLineFromStreamVerbatim(
1109 writer,1108 &writer,
1110 corresponding_lines.buffered_reader.interface.adaptToOldInterface(),1109 corresponding_lines.buffered_reader.interface.adaptToOldInterface(),
1111 corresponding_span.start_line,1110 corresponding_span.start_line,
1112 );1111 );
...@@ -1145,11 +1144,10 @@ const CorrespondingLines = struct {...@@ -1145,11 +1144,10 @@ const CorrespondingLines = struct {
1145 self.line_len = 0;1144 self.line_len = 0;
1146 self.visual_line_len = 0;1145 self.visual_line_len = 0;
11471146
1148 var fbs = std.io.fixedBufferStream(&self.line_buf);1147 var writer: std.Io.Writer = .fixed(&self.line_buf);
1149 const writer = fbs.writer();
11501148
1151 try self.writeLineFromStreamVerbatim(1149 try self.writeLineFromStreamVerbatim(
1152 writer,1150 &writer,
1153 self.buffered_reader.interface.adaptToOldInterface(),1151 self.buffered_reader.interface.adaptToOldInterface(),
1154 self.line_num,1152 self.line_num,
1155 );1153 );
...@@ -1164,7 +1162,7 @@ const CorrespondingLines = struct {...@@ -1164,7 +1162,7 @@ const CorrespondingLines = struct {
1164 return visual_line;1162 return visual_line;
1165 }1163 }
11661164
1167 fn writeLineFromStreamVerbatim(self: *CorrespondingLines, writer: anytype, input: anytype, line_num: usize) !void {1165 fn writeLineFromStreamVerbatim(self: *CorrespondingLines, writer: *std.Io.Writer, input: anytype, line_num: usize) !void {
1168 while (try readByteOrEof(input)) |byte| {1166 while (try readByteOrEof(input)) |byte| {
1169 switch (byte) {1167 switch (byte) {
1170 '\n', '\r' => {1168 '\n', '\r' => {
...@@ -1188,7 +1186,7 @@ const CorrespondingLines = struct {...@@ -1188,7 +1186,7 @@ const CorrespondingLines = struct {
1188 if (writer.writeByte(byte)) {1186 if (writer.writeByte(byte)) {
1189 self.line_len += 1;1187 self.line_len += 1;
1190 } else |err| switch (err) {1188 } else |err| switch (err) {
1191 error.NoSpaceLeft => {},1189 error.WriteFailed => {},
1192 else => |e| return e,1190 else => |e| return e,
1193 }1191 }
1194 }1192 }
lib/compiler/resinator/main.zig+56-46
...@@ -43,11 +43,11 @@ pub fn main() !void {...@@ -43,11 +43,11 @@ pub fn main() !void {
43 cli_args = args[3..];43 cli_args = args[3..];
44 }44 }
4545
46 var stdout_writer2 = std.fs.File.stdout().writer(&stdout_buffer);46 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
47 var error_handler: ErrorHandler = switch (zig_integration) {47 var error_handler: ErrorHandler = switch (zig_integration) {
48 true => .{48 true => .{
49 .server = .{49 .server = .{
50 .out = &stdout_writer2.interface,50 .out = &stdout_writer.interface,
51 .in = undefined, // won't be receiving messages51 .in = undefined, // won't be receiving messages
52 },52 },
53 },53 },
...@@ -83,18 +83,18 @@ pub fn main() !void {...@@ -83,18 +83,18 @@ pub fn main() !void {
83 defer options.deinit();83 defer options.deinit();
8484
85 if (options.print_help_and_exit) {85 if (options.print_help_and_exit) {
86 const stdout = std.fs.File.stdout();86 try cli.writeUsage(&stdout_writer.interface, "zig rc");
87 try cli.writeUsage(stdout.deprecatedWriter(), "zig rc");87 try stdout_writer.interface.flush();
88 return;88 return;
89 }89 }
9090
91 // Don't allow verbose when integrating with Zig via stdout91 // Don't allow verbose when integrating with Zig via stdout
92 options.verbose = false;92 options.verbose = false;
9393
94 const stdout_writer = std.fs.File.stdout().deprecatedWriter();
95 if (options.verbose) {94 if (options.verbose) {
96 try options.dumpVerbose(stdout_writer);95 try options.dumpVerbose(&stdout_writer.interface);
97 try stdout_writer.writeByte('\n');96 try stdout_writer.interface.writeByte('\n');
97 try stdout_writer.interface.flush();
98 }98 }
9999
100 var dependencies_list = std.array_list.Managed([]const u8).init(allocator);100 var dependencies_list = std.array_list.Managed([]const u8).init(allocator);
...@@ -115,7 +115,7 @@ pub fn main() !void {...@@ -115,7 +115,7 @@ pub fn main() !void {
115115
116 const full_input = full_input: {116 const full_input = full_input: {
117 if (options.input_format == .rc and options.preprocess != .no) {117 if (options.input_format == .rc and options.preprocess != .no) {
118 var preprocessed_buf = std.array_list.Managed(u8).init(allocator);118 var preprocessed_buf: std.Io.Writer.Allocating = .init(allocator);
119 errdefer preprocessed_buf.deinit();119 errdefer preprocessed_buf.deinit();
120120
121 // We're going to throw away everything except the final preprocessed output anyway,121 // We're going to throw away everything except the final preprocessed output anyway,
...@@ -139,14 +139,15 @@ pub fn main() !void {...@@ -139,14 +139,15 @@ pub fn main() !void {
139 });139 });
140140
141 if (options.verbose) {141 if (options.verbose) {
142 try stdout_writer.writeAll("Preprocessor: arocc (built-in)\n");142 try stdout_writer.interface.writeAll("Preprocessor: arocc (built-in)\n");
143 for (argv.items[0 .. argv.items.len - 1]) |arg| {143 for (argv.items[0 .. argv.items.len - 1]) |arg| {
144 try stdout_writer.print("{s} ", .{arg});144 try stdout_writer.interface.print("{s} ", .{arg});
145 }145 }
146 try stdout_writer.print("{s}\n\n", .{argv.items[argv.items.len - 1]});146 try stdout_writer.interface.print("{s}\n\n", .{argv.items[argv.items.len - 1]});
147 try stdout_writer.interface.flush();
147 }148 }
148149
149 preprocess.preprocess(&comp, preprocessed_buf.writer(), argv.items, maybe_dependencies_list) catch |err| switch (err) {150 preprocess.preprocess(&comp, &preprocessed_buf.writer, argv.items, maybe_dependencies_list) catch |err| switch (err) {
150 error.GeneratedSourceError => {151 error.GeneratedSourceError => {
151 try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug):", &comp);152 try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug):", &comp);
152 std.process.exit(1);153 std.process.exit(1);
...@@ -249,8 +250,9 @@ pub fn main() !void {...@@ -249,8 +250,9 @@ pub fn main() !void {
249 defer diagnostics.deinit();250 defer diagnostics.deinit();
250251
251 var output_buffer: [4096]u8 = undefined;252 var output_buffer: [4096]u8 = undefined;
252 var res_stream_writer = res_stream.source.writer(allocator).adaptToNewApi(&output_buffer);253 var res_stream_writer = res_stream.source.writer(allocator, &output_buffer);
253 const output_buffered_stream = &res_stream_writer.new_interface;254 defer res_stream_writer.deinit(&res_stream.source);
255 const output_buffered_stream = res_stream_writer.interface();
254256
255 compile(allocator, final_input, output_buffered_stream, .{257 compile(allocator, final_input, output_buffered_stream, .{
256 .cwd = std.fs.cwd(),258 .cwd = std.fs.cwd(),
...@@ -342,10 +344,10 @@ pub fn main() !void {...@@ -342,10 +344,10 @@ pub fn main() !void {
342 defer coff_stream.deinit(allocator);344 defer coff_stream.deinit(allocator);
343345
344 var coff_output_buffer: [4096]u8 = undefined;346 var coff_output_buffer: [4096]u8 = undefined;
345 var coff_output_buffered_stream = coff_stream.source.writer(allocator).adaptToNewApi(&coff_output_buffer);347 var coff_output_buffered_stream = coff_stream.source.writer(allocator, &coff_output_buffer);
346348
347 var cvtres_diagnostics: cvtres.Diagnostics = .{ .none = {} };349 var cvtres_diagnostics: cvtres.Diagnostics = .{ .none = {} };
348 cvtres.writeCoff(allocator, &coff_output_buffered_stream.new_interface, resources.list.items, options.coff_options, &cvtres_diagnostics) catch |err| {350 cvtres.writeCoff(allocator, coff_output_buffered_stream.interface(), resources.list.items, options.coff_options, &cvtres_diagnostics) catch |err| {
349 switch (err) {351 switch (err) {
350 error.DuplicateResource => {352 error.DuplicateResource => {
351 const duplicate_resource = resources.list.items[cvtres_diagnostics.duplicate_resource];353 const duplicate_resource = resources.list.items[cvtres_diagnostics.duplicate_resource];
...@@ -382,7 +384,7 @@ pub fn main() !void {...@@ -382,7 +384,7 @@ pub fn main() !void {
382 std.process.exit(1);384 std.process.exit(1);
383 };385 };
384386
385 try coff_output_buffered_stream.new_interface.flush();387 try coff_output_buffered_stream.interface().flush();
386}388}
387389
388const IoStream = struct {390const IoStream = struct {
...@@ -425,7 +427,7 @@ const IoStream = struct {...@@ -425,7 +427,7 @@ const IoStream = struct {
425 pub const Source = union(enum) {427 pub const Source = union(enum) {
426 file: std.fs.File,428 file: std.fs.File,
427 stdio: std.fs.File,429 stdio: std.fs.File,
428 memory: std.ArrayListUnmanaged(u8),430 memory: std.ArrayList(u8),
429 /// The source has been closed and any usage of the Source in this state is illegal (except deinit).431 /// The source has been closed and any usage of the Source in this state is illegal (except deinit).
430 closed: void,432 closed: void,
431433
...@@ -472,26 +474,34 @@ const IoStream = struct {...@@ -472,26 +474,34 @@ const IoStream = struct {
472 };474 };
473 }475 }
474476
475 pub const WriterContext = struct {477 pub const Writer = union(enum) {
476 self: *Source,478 file: std.fs.File.Writer,
477 allocator: std.mem.Allocator,479 allocating: std.Io.Writer.Allocating,
478 };480
479 pub const WriteError = std.mem.Allocator.Error || std.fs.File.WriteError;481 pub const Error = std.mem.Allocator.Error || std.fs.File.WriteError;
480 pub const Writer = std.io.GenericWriter(WriterContext, WriteError, write);482
481483 pub fn interface(this: *@This()) *std.Io.Writer {
482 pub fn write(ctx: WriterContext, bytes: []const u8) WriteError!usize {484 return switch (this.*) {
483 switch (ctx.self.*) {485 .file => |*fw| &fw.interface,
484 inline .file, .stdio => |file| return file.write(bytes),486 .allocating => |*a| &a.writer,
485 .memory => |*list| {487 };
486 try list.appendSlice(ctx.allocator, bytes);
487 return bytes.len;
488 },
489 .closed => unreachable,
490 }488 }
491 }
492489
493 pub fn writer(self: *Source, allocator: std.mem.Allocator) Writer {490 pub fn deinit(this: *@This(), source: *Source) void {
494 return .{ .context = .{ .self = self, .allocator = allocator } };491 switch (this.*) {
492 .file => {},
493 .allocating => |*a| source.memory = a.toArrayList(),
494 }
495 this.* = undefined;
496 }
497 };
498
499 pub fn writer(source: *Source, allocator: std.mem.Allocator, buffer: []u8) Writer {
500 return switch (source.*) {
501 .file, .stdio => |file| .{ .file = file.writer(buffer) },
502 .memory => |*list| .{ .allocating = .fromArrayList(allocator, list) },
503 .closed => unreachable,
504 };
495 }505 }
496 };506 };
497};507};
...@@ -721,7 +731,7 @@ fn cliDiagnosticsToErrorBundle(...@@ -721,7 +731,7 @@ fn cliDiagnosticsToErrorBundle(
721 });731 });
722732
723 var cur_err: ?ErrorBundle.ErrorMessage = null;733 var cur_err: ?ErrorBundle.ErrorMessage = null;
724 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;734 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
725 defer cur_notes.deinit(gpa);735 defer cur_notes.deinit(gpa);
726 for (diagnostics.errors.items) |err_details| {736 for (diagnostics.errors.items) |err_details| {
727 switch (err_details.type) {737 switch (err_details.type) {
...@@ -763,10 +773,10 @@ fn diagnosticsToErrorBundle(...@@ -763,10 +773,10 @@ fn diagnosticsToErrorBundle(
763 try bundle.init(gpa);773 try bundle.init(gpa);
764 errdefer bundle.deinit();774 errdefer bundle.deinit();
765775
766 var msg_buf: std.ArrayListUnmanaged(u8) = .empty;776 var msg_buf: std.Io.Writer.Allocating = .init(gpa);
767 defer msg_buf.deinit(gpa);777 defer msg_buf.deinit();
768 var cur_err: ?ErrorBundle.ErrorMessage = null;778 var cur_err: ?ErrorBundle.ErrorMessage = null;
769 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;779 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
770 defer cur_notes.deinit(gpa);780 defer cur_notes.deinit(gpa);
771 for (diagnostics.errors.items) |err_details| {781 for (diagnostics.errors.items) |err_details| {
772 switch (err_details.type) {782 switch (err_details.type) {
...@@ -789,7 +799,7 @@ fn diagnosticsToErrorBundle(...@@ -789,7 +799,7 @@ fn diagnosticsToErrorBundle(
789 const column = err_details.token.calculateColumn(source, 1, source_line_start) + 1;799 const column = err_details.token.calculateColumn(source, 1, source_line_start) + 1;
790800
791 msg_buf.clearRetainingCapacity();801 msg_buf.clearRetainingCapacity();
792 try err_details.render(msg_buf.writer(gpa), source, diagnostics.strings.items);802 try err_details.render(&msg_buf.writer, source, diagnostics.strings.items);
793803
794 const src_loc = src_loc: {804 const src_loc = src_loc: {
795 var src_loc: ErrorBundle.SourceLocation = .{805 var src_loc: ErrorBundle.SourceLocation = .{
...@@ -817,7 +827,7 @@ fn diagnosticsToErrorBundle(...@@ -817,7 +827,7 @@ fn diagnosticsToErrorBundle(
817 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);827 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);
818 }828 }
819 cur_err = .{829 cur_err = .{
820 .msg = try bundle.addString(msg_buf.items),830 .msg = try bundle.addString(msg_buf.written()),
821 .src_loc = src_loc,831 .src_loc = src_loc,
822 };832 };
823 cur_notes.clearRetainingCapacity();833 cur_notes.clearRetainingCapacity();
...@@ -825,7 +835,7 @@ fn diagnosticsToErrorBundle(...@@ -825,7 +835,7 @@ fn diagnosticsToErrorBundle(
825 .note => {835 .note => {
826 cur_err.?.notes_len += 1;836 cur_err.?.notes_len += 1;
827 try cur_notes.append(gpa, .{837 try cur_notes.append(gpa, .{
828 .msg = try bundle.addString(msg_buf.items),838 .msg = try bundle.addString(msg_buf.written()),
829 .src_loc = src_loc,839 .src_loc = src_loc,
830 });840 });
831 },841 },
...@@ -876,7 +886,7 @@ fn aroDiagnosticsToErrorBundle(...@@ -876,7 +886,7 @@ fn aroDiagnosticsToErrorBundle(
876 var msg_writer = MsgWriter.init(gpa);886 var msg_writer = MsgWriter.init(gpa);
877 defer msg_writer.deinit();887 defer msg_writer.deinit();
878 var cur_err: ?ErrorBundle.ErrorMessage = null;888 var cur_err: ?ErrorBundle.ErrorMessage = null;
879 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;889 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
880 defer cur_notes.deinit(gpa);890 defer cur_notes.deinit(gpa);
881 for (comp.diagnostics.list.items) |msg| {891 for (comp.diagnostics.list.items) |msg| {
882 switch (msg.kind) {892 switch (msg.kind) {
...@@ -971,11 +981,11 @@ const MsgWriter = struct {...@@ -971,11 +981,11 @@ const MsgWriter = struct {
971 }981 }
972982
973 pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void {983 pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void {
974 m.buf.writer().print(fmt, args) catch {};984 m.buf.print(fmt, args) catch {};
975 }985 }
976986
977 pub fn write(m: *MsgWriter, msg: []const u8) void {987 pub fn write(m: *MsgWriter, msg: []const u8) void {
978 m.buf.writer().writeAll(msg) catch {};988 m.buf.appendSlice(msg) catch {};
979 }989 }
980990
981 pub fn setColor(m: *MsgWriter, color: std.io.tty.Color) void {991 pub fn setColor(m: *MsgWriter, color: std.io.tty.Color) void {
lib/compiler/resinator/preprocess.zig+9-4
...@@ -18,12 +18,15 @@ pub fn preprocess(...@@ -18,12 +18,15 @@ pub fn preprocess(
18 var driver: aro.Driver = .{ .comp = comp, .aro_name = "arocc" };18 var driver: aro.Driver = .{ .comp = comp, .aro_name = "arocc" };
19 defer driver.deinit();19 defer driver.deinit();
2020
21 var macro_buf = std.array_list.Managed(u8).init(comp.gpa);21 var macro_buf: std.Io.Writer.Allocating = .init(comp.gpa);
22 defer macro_buf.deinit();22 defer macro_buf.deinit();
2323
24 _ = driver.parseArgs(std.io.null_writer, macro_buf.writer(), argv) catch |err| switch (err) {24 var trash: [64]u8 = undefined;
25 var discarding: std.Io.Writer.Discarding = .init(&trash);
26 _ = driver.parseArgs(&discarding.writer, &macro_buf.writer, argv) catch |err| switch (err) {
25 error.FatalError => return error.ArgError,27 error.FatalError => return error.ArgError,
26 error.OutOfMemory => |e| return e,28 error.OutOfMemory => |e| return e,
29 error.WriteFailed => return error.OutOfMemory,
27 };30 };
2831
29 if (hasAnyErrors(comp)) return error.ArgError;32 if (hasAnyErrors(comp)) return error.ArgError;
...@@ -33,7 +36,7 @@ pub fn preprocess(...@@ -33,7 +36,7 @@ pub fn preprocess(
33 error.FatalError => return error.GeneratedSourceError,36 error.FatalError => return error.GeneratedSourceError,
34 else => |e| return e,37 else => |e| return e,
35 };38 };
36 const user_macros = comp.addSourceFromBuffer("<command line>", macro_buf.items) catch |err| switch (err) {39 const user_macros = comp.addSourceFromBuffer("<command line>", macro_buf.written()) catch |err| switch (err) {
37 error.FatalError => return error.GeneratedSourceError,40 error.FatalError => return error.GeneratedSourceError,
38 else => |e| return e,41 else => |e| return e,
39 };42 };
...@@ -59,7 +62,9 @@ pub fn preprocess(...@@ -59,7 +62,9 @@ pub fn preprocess(
5962
60 if (hasAnyErrors(comp)) return error.PreprocessError;63 if (hasAnyErrors(comp)) return error.PreprocessError;
6164
62 try pp.prettyPrintTokens(writer, .result_only);65 pp.prettyPrintTokens(writer, .result_only) catch |err| switch (err) {
66 error.WriteFailed => return error.OutOfMemory,
67 };
6368
64 if (maybe_dependencies_list) |dependencies_list| {69 if (maybe_dependencies_list) |dependencies_list| {
65 for (comp.sources.values()) |comp_source| {70 for (comp.sources.values()) |comp_source| {