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
537537 var allocating: std.Io.Writer.Allocating = .init(comp.gpa);
538538 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 {
542549 if (system_defines_mode == .include_system_defines) {
543550 try buf.writeAll(
544551 \\#define __VERSION__ "Aro
......@@ -576,8 +583,6 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
576583 if (system_defines_mode == .include_system_defines) {
577584 try comp.generateSystemDefines(buf);
578585 }
579
580 return comp.addSourceFromBuffer("<builtin>", allocating.written());
581586}
582587
583588fn 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
520520 // - or / on its own is an error
521521 else => {
522522 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
523 var msg_writer = err_details.msg.writer(allocator);
524 try msg_writer.print("invalid option: {s}", .{arg.prefixSlice()});
523 try err_details.msg.print(allocator, "invalid option: {s}", .{arg.prefixSlice()});
525524 try diagnostics.append(err_details);
526525 arg_i += 1;
527526 continue :next_arg;
......@@ -532,8 +531,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
532531 const args_remaining = args.len - arg_i;
533532 if (args_remaining <= 2 and arg.looksLikeFilepath()) {
534533 var err_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i };
535 var msg_writer = err_details.msg.writer(allocator);
536 try msg_writer.writeAll("this argument was inferred to be a filepath, so argument parsing was terminated");
534 try err_details.msg.appendSlice(allocator, "this argument was inferred to be a filepath, so argument parsing was terminated");
537535 try diagnostics.append(err_details);
538536
539537 break;
......@@ -550,16 +548,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
550548 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":output-format")) {
551549 const value = arg.value(":output-format".len, arg_i, args) catch {
552550 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
553 var msg_writer = err_details.msg.writer(allocator);
554 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":output-format".len) });
551 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":output-format".len) });
555552 try diagnostics.append(err_details);
556553 arg_i += 1;
557554 break :next_arg;
558555 };
559556 output_format = std.meta.stringToEnum(Options.OutputFormat, value.slice) orelse blk: {
560557 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
561 var msg_writer = err_details.msg.writer(allocator);
562 try msg_writer.print("invalid output format setting: {s} ", .{value.slice});
558 try err_details.msg.print(allocator, "invalid output format setting: {s} ", .{value.slice});
563559 try diagnostics.append(err_details);
564560 break :blk output_format;
565561 };
......@@ -569,16 +565,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
569565 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":auto-includes")) {
570566 const value = arg.value(":auto-includes".len, arg_i, args) catch {
571567 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
572 var msg_writer = err_details.msg.writer(allocator);
573 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":auto-includes".len) });
568 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":auto-includes".len) });
574569 try diagnostics.append(err_details);
575570 arg_i += 1;
576571 break :next_arg;
577572 };
578573 options.auto_includes = std.meta.stringToEnum(Options.AutoIncludes, value.slice) orelse blk: {
579574 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
580 var msg_writer = err_details.msg.writer(allocator);
581 try msg_writer.print("invalid auto includes setting: {s} ", .{value.slice});
575 try err_details.msg.print(allocator, "invalid auto includes setting: {s} ", .{value.slice});
582576 try diagnostics.append(err_details);
583577 break :blk options.auto_includes;
584578 };
......@@ -587,16 +581,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
587581 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":input-format")) {
588582 const value = arg.value(":input-format".len, arg_i, args) catch {
589583 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
590 var msg_writer = err_details.msg.writer(allocator);
591 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":input-format".len) });
584 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":input-format".len) });
592585 try diagnostics.append(err_details);
593586 arg_i += 1;
594587 break :next_arg;
595588 };
596589 input_format = std.meta.stringToEnum(Options.InputFormat, value.slice) orelse blk: {
597590 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
598 var msg_writer = err_details.msg.writer(allocator);
599 try msg_writer.print("invalid input format setting: {s} ", .{value.slice});
591 try err_details.msg.print(allocator, "invalid input format setting: {s} ", .{value.slice});
600592 try diagnostics.append(err_details);
601593 break :blk input_format;
602594 };
......@@ -606,16 +598,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
606598 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile-fmt")) {
607599 const value = arg.value(":depfile-fmt".len, arg_i, args) catch {
608600 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
609 var msg_writer = err_details.msg.writer(allocator);
610 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile-fmt".len) });
601 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile-fmt".len) });
611602 try diagnostics.append(err_details);
612603 arg_i += 1;
613604 break :next_arg;
614605 };
615606 options.depfile_fmt = std.meta.stringToEnum(Options.DepfileFormat, value.slice) orelse blk: {
616607 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
617 var msg_writer = err_details.msg.writer(allocator);
618 try msg_writer.print("invalid depfile format setting: {s} ", .{value.slice});
608 try err_details.msg.print(allocator, "invalid depfile format setting: {s} ", .{value.slice});
619609 try diagnostics.append(err_details);
620610 break :blk options.depfile_fmt;
621611 };
......@@ -624,8 +614,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
624614 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile")) {
625615 const value = arg.value(":depfile".len, arg_i, args) catch {
626616 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
627 var msg_writer = err_details.msg.writer(allocator);
628 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile".len) });
617 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile".len) });
629618 try diagnostics.append(err_details);
630619 arg_i += 1;
631620 break :next_arg;
......@@ -643,8 +632,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
643632 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":target")) {
644633 const value = arg.value(":target".len, arg_i, args) catch {
645634 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
646 var msg_writer = err_details.msg.writer(allocator);
647 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":target".len) });
635 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":target".len) });
648636 try diagnostics.append(err_details);
649637 arg_i += 1;
650638 break :next_arg;
......@@ -655,8 +643,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
655643 const arch_str = target_it.first();
656644 const arch = cvtres.supported_targets.Arch.fromStringIgnoreCase(arch_str) orelse {
657645 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
658 var msg_writer = err_details.msg.writer(allocator);
659 try msg_writer.print("invalid or unsupported target architecture: {s}", .{arch_str});
646 try err_details.msg.print(allocator, "invalid or unsupported target architecture: {s}", .{arch_str});
660647 try diagnostics.append(err_details);
661648 arg_i += value.index_increment;
662649 continue :next_arg;
......@@ -680,13 +667,11 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
680667 .prefix_len = arg.prefixSlice().len,
681668 .value_offset = arg.name_offset + 3,
682669 } };
683 var msg_writer = err_details.msg.writer(allocator);
684 try msg_writer.print("missing value for {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
670 try err_details.msg.print(allocator, "missing value for {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
685671 try diagnostics.append(err_details);
686672 }
687673 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
688 var msg_writer = err_details.msg.writer(allocator);
689 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
674 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
690675 try diagnostics.append(err_details);
691676 arg_i += 1;
692677 continue :next_arg;
......@@ -695,16 +680,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
695680 else if (std.ascii.startsWithIgnoreCase(arg_name, "tn")) {
696681 const value = arg.value(2, arg_i, args) catch no_value: {
697682 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
698 var msg_writer = err_details.msg.writer(allocator);
699 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
683 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
700684 try diagnostics.append(err_details);
701685 // dummy zero-length slice starting where the value would have been
702686 const value_start = arg.name_offset + 2;
703687 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
704688 };
705689 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
706 var msg_writer = err_details.msg.writer(allocator);
707 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
690 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
708691 try diagnostics.append(err_details);
709692 arg_i += value.index_increment;
710693 continue :next_arg;
......@@ -716,16 +699,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
716699 {
717700 const value = arg.value(2, arg_i, args) catch no_value: {
718701 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
719 var msg_writer = err_details.msg.writer(allocator);
720 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
702 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
721703 try diagnostics.append(err_details);
722704 // dummy zero-length slice starting where the value would have been
723705 const value_start = arg.name_offset + 2;
724706 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
725707 };
726708 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
727 var msg_writer = err_details.msg.writer(allocator);
728 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
709 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
729710 try diagnostics.append(err_details);
730711 arg_i += value.index_increment;
731712 continue :next_arg;
......@@ -733,8 +714,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
733714 // Unsupported MUI options that do not need a value
734715 else if (std.ascii.startsWithIgnoreCase(arg_name, "g1")) {
735716 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);
737 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
717 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
738718 try diagnostics.append(err_details);
739719 arg.name_offset += 2;
740720 }
......@@ -747,15 +727,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
747727 std.ascii.startsWithIgnoreCase(arg_name, "ta"))
748728 {
749729 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);
751 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
730 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
752731 try diagnostics.append(err_details);
753732 arg.name_offset += 2;
754733 } else if (std.ascii.startsWithIgnoreCase(arg_name, "fo")) {
755734 const value = arg.value(2, arg_i, args) catch {
756735 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
757 var msg_writer = err_details.msg.writer(allocator);
758 try msg_writer.print("missing output path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
736 try err_details.msg.print(allocator, "missing output path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
759737 try diagnostics.append(err_details);
760738 arg_i += 1;
761739 break :next_arg;
......@@ -767,8 +745,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
767745 } else if (std.ascii.startsWithIgnoreCase(arg_name, "sl")) {
768746 const value = arg.value(2, arg_i, args) catch {
769747 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
770 var msg_writer = err_details.msg.writer(allocator);
771 try msg_writer.print("missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
748 try err_details.msg.print(allocator, "missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
772749 try diagnostics.append(err_details);
773750 arg_i += 1;
774751 break :next_arg;
......@@ -776,24 +753,20 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
776753 const percent_str = value.slice;
777754 const percent: u32 = parsePercent(percent_str) catch {
778755 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
779 var msg_writer = err_details.msg.writer(allocator);
780 try msg_writer.print("invalid percent format '{s}'", .{percent_str});
756 try err_details.msg.print(allocator, "invalid percent format '{s}'", .{percent_str});
781757 try diagnostics.append(err_details);
782758 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };
783 var note_writer = note_details.msg.writer(allocator);
784 try note_writer.writeAll("string length percent must be an integer between 1 and 100 (inclusive)");
759 try note_details.msg.appendSlice(allocator, "string length percent must be an integer between 1 and 100 (inclusive)");
785760 try diagnostics.append(note_details);
786761 arg_i += value.index_increment;
787762 continue :next_arg;
788763 };
789764 if (percent == 0 or percent > 100) {
790765 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
791 var msg_writer = err_details.msg.writer(allocator);
792 try msg_writer.print("percent out of range: {} (parsed from '{s}')", .{ percent, percent_str });
766 try err_details.msg.print(allocator, "percent out of range: {} (parsed from '{s}')", .{ percent, percent_str });
793767 try diagnostics.append(err_details);
794768 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };
795 var note_writer = note_details.msg.writer(allocator);
796 try note_writer.writeAll("string length percent must be an integer between 1 and 100 (inclusive)");
769 try note_details.msg.appendSlice(allocator, "string length percent must be an integer between 1 and 100 (inclusive)");
797770 try diagnostics.append(note_details);
798771 arg_i += value.index_increment;
799772 continue :next_arg;
......@@ -805,8 +778,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
805778 } else if (std.ascii.startsWithIgnoreCase(arg_name, "ln")) {
806779 const value = arg.value(2, arg_i, args) catch {
807780 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
808 var msg_writer = err_details.msg.writer(allocator);
809 try msg_writer.print("missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
781 try err_details.msg.print(allocator, "missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
810782 try diagnostics.append(err_details);
811783 arg_i += 1;
812784 break :next_arg;
......@@ -814,16 +786,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
814786 const tag = value.slice;
815787 options.default_language_id = lang.tagToInt(tag) catch {
816788 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
817 var msg_writer = err_details.msg.writer(allocator);
818 try msg_writer.print("invalid language tag: {s}", .{tag});
789 try err_details.msg.print(allocator, "invalid language tag: {s}", .{tag});
819790 try diagnostics.append(err_details);
820791 arg_i += value.index_increment;
821792 continue :next_arg;
822793 };
823794 if (options.default_language_id.? == lang.LOCALE_CUSTOM_UNSPECIFIED) {
824795 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);
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 });
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 });
827797 try diagnostics.append(err_details);
828798 }
829799 arg_i += value.index_increment;
......@@ -831,8 +801,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
831801 } else if (std.ascii.startsWithIgnoreCase(arg_name, "l")) {
832802 const value = arg.value(1, arg_i, args) catch {
833803 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
834 var msg_writer = err_details.msg.writer(allocator);
835 try msg_writer.print("missing language ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
804 try err_details.msg.print(allocator, "missing language ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
836805 try diagnostics.append(err_details);
837806 arg_i += 1;
838807 break :next_arg;
......@@ -840,8 +809,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
840809 const num_str = value.slice;
841810 options.default_language_id = lang.parseInt(num_str) catch {
842811 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
843 var msg_writer = err_details.msg.writer(allocator);
844 try msg_writer.print("invalid language ID: {s}", .{num_str});
812 try err_details.msg.print(allocator, "invalid language ID: {s}", .{num_str});
845813 try diagnostics.append(err_details);
846814 arg_i += value.index_increment;
847815 continue :next_arg;
......@@ -860,16 +828,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
860828 {
861829 const value = arg.value(1, arg_i, args) catch no_value: {
862830 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
863 var msg_writer = err_details.msg.writer(allocator);
864 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
831 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
865832 try diagnostics.append(err_details);
866833 // dummy zero-length slice starting where the value would have been
867834 const value_start = arg.name_offset + 1;
868835 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
869836 };
870837 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
871 var msg_writer = err_details.msg.writer(allocator);
872 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
838 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
873839 try diagnostics.append(err_details);
874840 arg_i += value.index_increment;
875841 continue :next_arg;
......@@ -882,16 +848,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
882848 {
883849 const value = arg.value(1, arg_i, args) catch no_value: {
884850 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
885 var msg_writer = err_details.msg.writer(allocator);
886 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
851 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
887852 try diagnostics.append(err_details);
888853 // dummy zero-length slice starting where the value would have been
889854 const value_start = arg.name_offset + 1;
890855 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
891856 };
892857 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
893 var msg_writer = err_details.msg.writer(allocator);
894 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
858 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
895859 try diagnostics.append(err_details);
896860 arg_i += value.index_increment;
897861 continue :next_arg;
......@@ -899,15 +863,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
899863 // 1 char unsupported LCX/LCE options that do not need a value
900864 else if (std.ascii.startsWithIgnoreCase(arg_name, "t")) {
901865 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);
903 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
866 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
904867 try diagnostics.append(err_details);
905868 arg.name_offset += 1;
906869 } else if (std.ascii.startsWithIgnoreCase(arg_name, "c")) {
907870 const value = arg.value(1, arg_i, args) catch {
908871 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
909 var msg_writer = err_details.msg.writer(allocator);
910 try msg_writer.print("missing code page ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
872 try err_details.msg.print(allocator, "missing code page ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
911873 try diagnostics.append(err_details);
912874 arg_i += 1;
913875 break :next_arg;
......@@ -915,8 +877,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
915877 const num_str = value.slice;
916878 const code_page_id = std.fmt.parseUnsigned(u16, num_str, 10) catch {
917879 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
918 var msg_writer = err_details.msg.writer(allocator);
919 try msg_writer.print("invalid code page ID: {s}", .{num_str});
880 try err_details.msg.print(allocator, "invalid code page ID: {s}", .{num_str});
920881 try diagnostics.append(err_details);
921882 arg_i += value.index_increment;
922883 continue :next_arg;
......@@ -924,16 +885,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
924885 options.default_code_page = code_pages.getByIdentifierEnsureSupported(code_page_id) catch |err| switch (err) {
925886 error.InvalidCodePage => {
926887 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
927 var msg_writer = err_details.msg.writer(allocator);
928 try msg_writer.print("invalid or unknown code page ID: {}", .{code_page_id});
888 try err_details.msg.print(allocator, "invalid or unknown code page ID: {}", .{code_page_id});
929889 try diagnostics.append(err_details);
930890 arg_i += value.index_increment;
931891 continue :next_arg;
932892 },
933893 error.UnsupportedCodePage => {
934894 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
935 var msg_writer = err_details.msg.writer(allocator);
936 try msg_writer.print("unsupported code page: {s} (id={})", .{
895 try err_details.msg.print(allocator, "unsupported code page: {s} (id={})", .{
937896 @tagName(code_pages.getByIdentifier(code_page_id) catch unreachable),
938897 code_page_id,
939898 });
......@@ -957,8 +916,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
957916 } else if (std.ascii.startsWithIgnoreCase(arg_name, "i")) {
958917 const value = arg.value(1, arg_i, args) catch {
959918 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
960 var msg_writer = err_details.msg.writer(allocator);
961 try msg_writer.print("missing include path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
919 try err_details.msg.print(allocator, "missing include path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
962920 try diagnostics.append(err_details);
963921 arg_i += 1;
964922 break :next_arg;
......@@ -986,15 +944,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
986944 // Undocumented option with unknown function
987945 // TODO: More investigation to figure out what it does (if anything)
988946 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);
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) });
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) });
991948 try diagnostics.append(err_details);
992949 arg.name_offset += 1;
993950 } else if (std.ascii.startsWithIgnoreCase(arg_name, "d")) {
994951 const value = arg.value(1, arg_i, args) catch {
995952 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
996 var msg_writer = err_details.msg.writer(allocator);
997 try msg_writer.print("missing symbol to define after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
953 try err_details.msg.print(allocator, "missing symbol to define after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
998954 try diagnostics.append(err_details);
999955 arg_i += 1;
1000956 break :next_arg;
......@@ -1009,8 +965,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1009965 try options.define(symbol, symbol_value);
1010966 } else {
1011967 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);
1013 try msg_writer.print("symbol \"{s}\" is not a valid identifier and therefore cannot be defined", .{symbol});
968 try err_details.msg.print(allocator, "symbol \"{s}\" is not a valid identifier and therefore cannot be defined", .{symbol});
1014969 try diagnostics.append(err_details);
1015970 }
1016971 arg_i += value.index_increment;
......@@ -1018,8 +973,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1018973 } else if (std.ascii.startsWithIgnoreCase(arg_name, "u")) {
1019974 const value = arg.value(1, arg_i, args) catch {
1020975 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
1021 var msg_writer = err_details.msg.writer(allocator);
1022 try msg_writer.print("missing symbol to undefine after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
976 try err_details.msg.print(allocator, "missing symbol to undefine after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
1023977 try diagnostics.append(err_details);
1024978 arg_i += 1;
1025979 break :next_arg;
......@@ -1029,16 +983,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1029983 try options.undefine(symbol);
1030984 } else {
1031985 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);
1033 try msg_writer.print("symbol \"{s}\" is not a valid identifier and therefore cannot be undefined", .{symbol});
986 try err_details.msg.print(allocator, "symbol \"{s}\" is not a valid identifier and therefore cannot be undefined", .{symbol});
1034987 try diagnostics.append(err_details);
1035988 }
1036989 arg_i += value.index_increment;
1037990 continue :next_arg;
1038991 } else {
1039992 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
1040 var msg_writer = err_details.msg.writer(allocator);
1041 try msg_writer.print("invalid option: {s}{s}", .{ arg.prefixSlice(), arg.name() });
993 try err_details.msg.print(allocator, "invalid option: {s}{s}", .{ arg.prefixSlice(), arg.name() });
1042994 try diagnostics.append(err_details);
1043995 arg_i += 1;
1044996 continue :next_arg;
......@@ -1055,16 +1007,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
10551007
10561008 if (positionals.len == 0) {
10571009 var err_details = Diagnostics.ErrorDetails{ .print_args = false, .arg_index = arg_i };
1058 var msg_writer = err_details.msg.writer(allocator);
1059 try msg_writer.writeAll("missing input filename");
1010 try err_details.msg.appendSlice(allocator, "missing input filename");
10601011 try diagnostics.append(err_details);
10611012
10621013 if (args.len > 0) {
10631014 const last_arg = args[args.len - 1];
10641015 if (arg_i > 0 and last_arg.len > 0 and last_arg[0] == '/' and isSupportedInputExtension(std.fs.path.extension(last_arg))) {
10651016 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i - 1 };
1066 var note_writer = note_details.msg.writer(allocator);
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");
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");
10681018 try diagnostics.append(note_details);
10691019 }
10701020 }
......@@ -1099,16 +1049,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
10991049 if (positionals.len > 1) {
11001050 if (output_filename != null) {
11011051 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i + 1 };
1102 var msg_writer = err_details.msg.writer(allocator);
1103 try msg_writer.writeAll("output filename already specified");
1052 try err_details.msg.appendSlice(allocator, "output filename already specified");
11041053 try diagnostics.append(err_details);
11051054 var note_details = Diagnostics.ErrorDetails{
11061055 .type = .note,
11071056 .arg_index = output_filename_context.arg.index,
11081057 .arg_span = output_filename_context.arg.value.argSpan(output_filename_context.arg.arg),
11091058 };
1110 var note_writer = note_details.msg.writer(allocator);
1111 try note_writer.writeAll("output filename previously specified here");
1059 try note_details.msg.appendSlice(allocator, "output filename previously specified here");
11121060 try diagnostics.append(note_details);
11131061 } else {
11141062 output_filename = positionals[1];
......@@ -1173,16 +1121,15 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
11731121 var print_output_format_source_note: bool = false;
11741122 if (options.depfile_path != null and (options.input_format == .res or options.output_format == .rcpp)) {
11751123 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);
11771124 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}'", .{
11791126 depfile_context.arg.prefixSlice(),
11801127 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),
11811128 @tagName(options.input_format),
11821129 });
11831130 print_input_format_source_note = true;
11841131 } 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}'", .{
11861133 depfile_context.arg.prefixSlice(),
11871134 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),
11881135 @tagName(options.output_format),
......@@ -1193,16 +1140,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
11931140 }
11941141 if (!isSupportedTransformation(options.input_format, options.output_format)) {
11951142 var err_details = Diagnostics.ErrorDetails{ .arg_index = input_filename_arg_i, .print_args = false };
1196 var msg_writer = err_details.msg.writer(allocator);
1197 try msg_writer.print("input format '{s}' cannot be converted to output format '{s}'", .{ @tagName(options.input_format), @tagName(options.output_format) });
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) });
11981144 try diagnostics.append(err_details);
11991145 print_input_format_source_note = true;
12001146 print_output_format_source_note = true;
12011147 }
12021148 if (options.preprocess == .only and options.output_format != .rcpp) {
12031149 var err_details = Diagnostics.ErrorDetails{ .arg_index = preprocess_only_context.index };
1204 var msg_writer = err_details.msg.writer(allocator);
1205 try msg_writer.print("the {s}{s} option cannot be used with output format '{s}'", .{
1150 try err_details.msg.print(allocator, "the {s}{s} option cannot be used with output format '{s}'", .{
12061151 preprocess_only_context.arg.prefixSlice(),
12071152 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),
12081153 @tagName(options.output_format),
......@@ -1214,8 +1159,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
12141159 switch (input_format_source) {
12151160 .inferred_from_input_filename => {
12161161 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };
1217 var msg_writer = err_details.msg.writer(allocator);
1218 try msg_writer.writeAll("the input format was inferred from the input filename");
1162 try err_details.msg.appendSlice(allocator, "the input format was inferred from the input filename");
12191163 try diagnostics.append(err_details);
12201164 },
12211165 .input_format_arg => {
......@@ -1224,8 +1168,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
12241168 .arg_index = input_format_context.index,
12251169 .arg_span = input_format_context.value.argSpan(input_format_context.arg),
12261170 };
1227 var msg_writer = err_details.msg.writer(allocator);
1228 try msg_writer.writeAll("the input format was specified here");
1171 try err_details.msg.appendSlice(allocator, "the input format was specified here");
12291172 try diagnostics.append(err_details);
12301173 },
12311174 }
......@@ -1234,11 +1177,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
12341177 switch (output_format_source) {
12351178 .inferred_from_input_filename, .unable_to_infer_from_input_filename => {
12361179 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };
1237 var msg_writer = err_details.msg.writer(allocator);
12381180 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");
12401182 } 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");
12421184 }
12431185 try diagnostics.append(err_details);
12441186 },
......@@ -1248,11 +1190,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
12481190 .arg => |ctx| .{ .type = .note, .arg_index = ctx.index, .arg_span = ctx.value.argSpan(ctx.arg) },
12491191 .unspecified => unreachable,
12501192 };
1251 var msg_writer = err_details.msg.writer(allocator);
12521193 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");
12541195 } 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");
12561197 }
12571198 try diagnostics.append(err_details);
12581199 },
......@@ -1262,14 +1203,12 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
12621203 .arg_index = output_format_context.index,
12631204 .arg_span = output_format_context.value.argSpan(output_format_context.arg),
12641205 };
1265 var msg_writer = err_details.msg.writer(allocator);
1266 try msg_writer.writeAll("the output format was specified here");
1206 try err_details.msg.appendSlice(allocator, "the output format was specified here");
12671207 try diagnostics.append(err_details);
12681208 },
12691209 .inferred_from_preprocess_only => {
12701210 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = preprocess_only_context.index };
1271 var msg_writer = err_details.msg.writer(allocator);
1272 try msg_writer.print("the output format was inferred from the usage of the {s}{s} option", .{
1211 try err_details.msg.print(allocator, "the output format was inferred from the usage of the {s}{s} option", .{
12731212 preprocess_only_context.arg.prefixSlice(),
12741213 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),
12751214 });
lib/compiler/resinator/compile.zig+56-114
......@@ -61,7 +61,7 @@ pub const CompileOptions = struct {
6161 warn_instead_of_error_on_invalid_code_page: bool = false,
6262};
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 {
6565 var lexer = lex.Lexer.init(source, .{
6666 .default_code_page = options.default_code_page,
6767 .source_mappings = options.source_mappings,
......@@ -194,7 +194,7 @@ pub const Compiler = struct {
194194 characteristics: u32 = 0,
195195 };
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 {
198198 try writeEmptyResource(writer);
199199 for (root.body) |node| {
200200 try self.writeNode(node, writer);
......@@ -236,7 +236,7 @@ pub const Compiler = struct {
236236 }
237237 }
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 {
240240 switch (node.id) {
241241 .root => unreachable, // writeRoot should be called directly instead
242242 .resource_external => try self.writeResourceExternal(@alignCast(@fieldParentPtr("base", node)), writer),
......@@ -479,7 +479,7 @@ pub const Compiler = struct {
479479 return buf.toOwnedSlice();
480480 }
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 {
483483 // Init header with data size zero for now, will need to fill it in later
484484 var header = try self.resourceHeader(node.id, node.type, .{});
485485 defer header.deinit(self.allocator);
......@@ -1226,33 +1226,31 @@ pub const Compiler = struct {
12261226 }
12271227
12281228 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);
12301230 defer data_buffer.deinit();
12311231 // The header's data length field is a u32 so limit the resource's data size so that
12321232 // we know we can always specify the real size.
1233 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));
1234 const data_writer = limited_writer.writer();
1233 const data_writer = &data_buffer.writer;
12351234
12361235 for (node.raw_data) |expression| {
12371236 const data = try self.evaluateDataExpression(expression);
12381237 defer data.deinit(self.allocator);
12391238 data.write(data_writer) catch |err| switch (err) {
1240 error.NoSpaceLeft => {
1239 error.WriteFailed => {
12411240 return self.addErrorDetailsAndFail(.{
12421241 .err = .resource_data_size_exceeds_max,
12431242 .token = node.id,
12441243 });
12451244 },
1246 else => |e| return e,
12471245 };
12481246 }
12491247
12501248 // This intCast can't fail because the limitedWriter above guarantees that
12511249 // 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);
12531251 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());
12561254 try writeResourceData(writer, &data_fbs, data_len);
12571255 }
12581256
......@@ -1306,16 +1304,15 @@ pub const Compiler = struct {
13061304 }
13071305
13081306 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);
13101308 defer data_buffer.deinit();
13111309
13121310 // The header's data length field is a u32 so limit the resource's data size so that
13131311 // we know we can always specify the real size.
1314 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));
1315 const data_writer = limited_writer.writer();
1312 const data_writer = &data_buffer.writer;
13161313
13171314 self.writeAcceleratorsData(node, data_writer) catch |err| switch (err) {
1318 error.NoSpaceLeft => {
1315 error.WriteFailed => {
13191316 return self.addErrorDetailsAndFail(.{
13201317 .err = .resource_data_size_exceeds_max,
13211318 .token = node.id,
......@@ -1326,7 +1323,7 @@ pub const Compiler = struct {
13261323
13271324 // This intCast can't fail because the limitedWriter above guarantees that
13281325 // 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);
13301327 var header = try self.resourceHeader(node.id, node.type, .{
13311328 .data_size = data_size,
13321329 });
......@@ -1337,7 +1334,7 @@ pub const Compiler = struct {
13371334
13381335 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());
13411338 try writeResourceData(writer, &data_fbs, data_size);
13421339 }
13431340
......@@ -1405,12 +1402,11 @@ pub const Compiler = struct {
14051402 };
14061403
14071404 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);
14091406 defer data_buffer.deinit();
14101407 // The header's data length field is a u32 so limit the resource's data size so that
14111408 // we know we can always specify the real size.
1412 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));
1413 const data_writer = limited_writer.writer();
1409 const data_writer = &data_buffer.writer;
14141410
14151411 const resource = ResourceType.fromString(.{
14161412 .slice = node.type.slice(self.source),
......@@ -1683,7 +1679,7 @@ pub const Compiler = struct {
16831679 ) catch |err| switch (err) {
16841680 // Dialog header and menu/class/title strings can never exceed u32 bytes
16851681 // on their own, so this error is unreachable.
1686 error.NoSpaceLeft => unreachable,
1682 error.WriteFailed => unreachable,
16871683 else => |e| return e,
16881684 };
16891685
......@@ -1700,10 +1696,10 @@ pub const Compiler = struct {
17001696 data_writer,
17011697 resource,
17021698 // We know the data_buffer len is limited to u32 max.
1703 @intCast(data_buffer.items.len),
1699 @intCast(data_buffer.written().len),
17041700 &controls_by_id,
17051701 ) catch |err| switch (err) {
1706 error.NoSpaceLeft => {
1702 error.WriteFailed => {
17071703 try self.addErrorDetails(.{
17081704 .err = .resource_data_size_exceeds_max,
17091705 .token = node.id,
......@@ -1719,7 +1715,7 @@ pub const Compiler = struct {
17191715 }
17201716
17211717 // 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);
17231719 var header = try self.resourceHeader(node.id, node.type, .{
17241720 .data_size = data_size,
17251721 });
......@@ -1730,7 +1726,7 @@ pub const Compiler = struct {
17301726
17311727 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());
17341730 try writeResourceData(writer, &data_fbs, data_size);
17351731 }
17361732
......@@ -1821,7 +1817,7 @@ pub const Compiler = struct {
18211817 .token = control.type,
18221818 });
18231819 }
1824 try data_writer.writeByteNTimes(0, num_padding);
1820 try data_writer.splatByteAll(0, num_padding);
18251821
18261822 const style = if (control.style) |style_expression|
18271823 // Certain styles are implied by the control type
......@@ -1973,16 +1969,15 @@ pub const Compiler = struct {
19731969 try NameOrOrdinal.writeEmpty(data_writer);
19741970 }
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);
19771973 defer extra_data_buf.deinit();
19781974 // 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));
1980 const extra_data_writer = limited_extra_data_writer.writer();
1975 const extra_data_writer = &extra_data_buf.writer;
19811976 for (control.extra_data) |data_expression| {
19821977 const data = try self.evaluateDataExpression(data_expression);
19831978 defer data.deinit(self.allocator);
19841979 data.write(extra_data_writer) catch |err| switch (err) {
1985 error.NoSpaceLeft => {
1980 error.WriteFailed => {
19861981 try self.addErrorDetails(.{
19871982 .err = .control_extra_data_size_exceeds_max,
19881983 .token = control.type,
......@@ -1998,15 +1993,15 @@ pub const Compiler = struct {
19981993 };
19991994 }
20001995 // 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);
20021997 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());
20041999 }
20052000
20062001 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);
20082003 defer data_buffer.deinit();
2009 const data_writer = data_buffer.writer();
2004 const data_writer = &data_buffer.writer;
20102005
20112006 const button_width = evaluateNumberExpression(node.button_width, self.source, self.input_code_pages);
20122007 const button_height = evaluateNumberExpression(node.button_height, self.source, self.input_code_pages);
......@@ -2034,7 +2029,7 @@ pub const Compiler = struct {
20342029 }
20352030 }
20362031
2037 const data_size: u32 = @intCast(data_buffer.items.len);
2032 const data_size: u32 = @intCast(data_buffer.written().len);
20382033 var header = try self.resourceHeader(node.id, node.type, .{
20392034 .data_size = data_size,
20402035 });
......@@ -2044,7 +2039,7 @@ pub const Compiler = struct {
20442039
20452040 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());
20482043 try writeResourceData(writer, &data_fbs, data_size);
20492044 }
20502045
......@@ -2082,12 +2077,11 @@ pub const Compiler = struct {
20822077 }
20832078
20842079 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);
20862081 defer data_buffer.deinit();
20872082 // The header's data length field is a u32 so limit the resource's data size so that
20882083 // we know we can always specify the real size.
2089 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));
2090 const data_writer = limited_writer.writer();
2084 const data_writer = &data_buffer.writer;
20912085
20922086 const type_bytes = SourceBytes{
20932087 .slice = node.type.slice(self.source),
......@@ -2096,9 +2090,7 @@ pub const Compiler = struct {
20962090 const resource = ResourceType.fromString(type_bytes);
20972091 std.debug.assert(resource == .menu or resource == .menuex);
20982092
2099 var adapted = data_writer.adaptToNewApi(&.{});
2100
2101 self.writeMenuData(node, &adapted.new_interface, resource) catch |err| switch (err) {
2093 self.writeMenuData(node, data_writer, resource) catch |err| switch (err) {
21022094 error.WriteFailed => {
21032095 return self.addErrorDetailsAndFail(.{
21042096 .err = .resource_data_size_exceeds_max,
......@@ -2110,7 +2102,7 @@ pub const Compiler = struct {
21102102
21112103 // This intCast can't fail because the limitedWriter above guarantees that
21122104 // 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);
21142106 var header = try self.resourceHeader(node.id, node.type, .{
21152107 .data_size = data_size,
21162108 });
......@@ -2121,7 +2113,7 @@ pub const Compiler = struct {
21212113
21222114 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());
21252117 try writeResourceData(writer, &data_fbs, data_size);
21262118 }
21272119
......@@ -2265,12 +2257,11 @@ pub const Compiler = struct {
22652257 }
22662258
22672259 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);
22692261 defer data_buffer.deinit();
22702262 // The node's length field (which is inclusive of the length of all of its children) is a u16
22712263 // 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));
2273 const data_writer = limited_writer.writer();
2264 const data_writer = &data_buffer.writer;
22742265
22752266 try data_writer.writeInt(u16, 0, .little); // placeholder size
22762267 try data_writer.writeInt(u16, res.FixedFileInfo.byte_len, .little);
......@@ -2354,8 +2345,7 @@ pub const Compiler = struct {
23542345 try fixed_file_info.write(data_writer);
23552346
23562347 for (node.block_statements) |statement| {
2357 var adapted = data_writer.adaptToNewApi(&.{});
2358 self.writeVersionNode(statement, &adapted.new_interface, &data_buffer) catch |err| switch (err) {
2348 self.writeVersionNode(statement, data_writer, &data_buffer) catch |err| switch (err) {
23592349 error.WriteFailed => {
23602350 try self.addErrorDetails(.{
23612351 .err = .version_node_size_exceeds_max,
......@@ -2374,9 +2364,9 @@ pub const Compiler = struct {
23742364
23752365 // We know that data_buffer.items.len is within the limits of a u16, since we
23762366 // 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);
23782368 // 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
23812371 var header = try self.resourceHeader(node.id, node.versioninfo, .{
23822372 .data_size = data_size,
......@@ -2387,22 +2377,22 @@ pub const Compiler = struct {
23872377
23882378 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());
23912381 try writeResourceData(writer, &data_fbs, data_size);
23922382 }
23932383
23942384 /// Expects writer to be a LimitedWriter limited to u16, meaning all writes to
23952385 /// the writer within this function could return error.NoSpaceLeft, and that buf.items.len
23962386 /// 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 {
23982388 // 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;
24022392 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;
24042394 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;
24062396 // Data type is string unless the node contains values that are numbers.
24072397 try writer.writeInt(u16, res.VersionNode.type_string, .little);
24082398
......@@ -2432,7 +2422,7 @@ pub const Compiler = struct {
24322422 // during parsing, so we can just do the correct thing here.
24332423 var values_size: usize = 0;
24342424
2435 try writeDataPadding(writer, @intCast(buf.items.len));
2425 try writeDataPadding(writer, @intCast(buf.written().len));
24362426
24372427 for (block_or_value.values, 0..) |value_value_node_uncasted, i| {
24382428 const value_value_node = value_value_node_uncasted.cast(.block_value_value).?;
......@@ -2471,11 +2461,11 @@ pub const Compiler = struct {
24712461 }
24722462 }
24732463 }
2474 var data_size_slice = buf.items[data_size_offset..];
2464 var data_size_slice = buf.written()[data_size_offset..];
24752465 std.mem.writeInt(u16, data_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(values_size)), .little);
24762466
24772467 if (has_number_value) {
2478 const data_type_slice = buf.items[data_type_offset..];
2468 const data_type_slice = buf.written()[data_type_offset..];
24792469 std.mem.writeInt(u16, data_type_slice[0..@sizeOf(u16)], res.VersionNode.type_binary, .little);
24802470 }
24812471
......@@ -2489,8 +2479,8 @@ pub const Compiler = struct {
24892479 else => unreachable,
24902480 }
24912481
2492 const node_and_children_size = buf.items.len - node_and_children_size_offset;
2493 const node_and_children_size_slice = buf.items[node_and_children_size_offset..];
2482 const node_and_children_size = buf.written().len - node_and_children_size_offset;
2483 const node_and_children_size_slice = buf.written()[node_and_children_size_offset..];
24942484 std.mem.writeInt(u16, node_and_children_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(node_and_children_size)), .little);
24952485 }
24962486
......@@ -2973,54 +2963,6 @@ pub fn headerSlurpingReader(comptime size: usize, reader: anytype) HeaderSlurpin
29732963 return .{ .child_reader = reader };
29742964}
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
30242966pub const FontDir = struct {
30252967 fonts: std.ArrayListUnmanaged(Font) = .empty,
30262968 /// To keep track of which ids are set and where they were set from
......@@ -3246,9 +3188,9 @@ pub const StringTable = struct {
32463188 }
32473189
32483190 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);
32503192 defer data_buffer.deinit();
3251 const data_writer = data_buffer.writer();
3193 const data_writer = &data_buffer.writer;
32523194
32533195 var i: u8 = 0;
32543196 var string_i: u8 = 0;
......@@ -3307,7 +3249,7 @@ pub const StringTable = struct {
33073249 // 16 * (131,070 + 2) = 2,097,152 which is well within the u32 max.
33083250 //
33093251 // 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
33123254 const header = Compiler.ResourceHeader{
33133255 .name_value = .{ .ordinal = block_id },
......@@ -3322,7 +3264,7 @@ pub const StringTable = struct {
33223264 // we fully control and know are numbers, so they have a fixed size.
33233265 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());
33263268 try Compiler.writeResourceData(writer, &data_fbs, data_size);
33273269 }
33283270 };
lib/compiler/resinator/errors.zig+6-8
......@@ -1102,11 +1102,10 @@ const CorrespondingLines = struct {
11021102 corresponding_lines.buffered_reader = corresponding_lines.file.reader(&.{});
11031103 errdefer corresponding_lines.deinit();
11041104
1105 var fbs = std.io.fixedBufferStream(&corresponding_lines.line_buf);
1106 const writer = fbs.writer();
1105 var writer: std.Io.Writer = .fixed(&corresponding_lines.line_buf);
11071106
11081107 try corresponding_lines.writeLineFromStreamVerbatim(
1109 writer,
1108 &writer,
11101109 corresponding_lines.buffered_reader.interface.adaptToOldInterface(),
11111110 corresponding_span.start_line,
11121111 );
......@@ -1145,11 +1144,10 @@ const CorrespondingLines = struct {
11451144 self.line_len = 0;
11461145 self.visual_line_len = 0;
11471146
1148 var fbs = std.io.fixedBufferStream(&self.line_buf);
1149 const writer = fbs.writer();
1147 var writer: std.Io.Writer = .fixed(&self.line_buf);
11501148
11511149 try self.writeLineFromStreamVerbatim(
1152 writer,
1150 &writer,
11531151 self.buffered_reader.interface.adaptToOldInterface(),
11541152 self.line_num,
11551153 );
......@@ -1164,7 +1162,7 @@ const CorrespondingLines = struct {
11641162 return visual_line;
11651163 }
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 {
11681166 while (try readByteOrEof(input)) |byte| {
11691167 switch (byte) {
11701168 '\n', '\r' => {
......@@ -1188,7 +1186,7 @@ const CorrespondingLines = struct {
11881186 if (writer.writeByte(byte)) {
11891187 self.line_len += 1;
11901188 } else |err| switch (err) {
1191 error.NoSpaceLeft => {},
1189 error.WriteFailed => {},
11921190 else => |e| return e,
11931191 }
11941192 }
lib/compiler/resinator/main.zig+56-46
......@@ -43,11 +43,11 @@ pub fn main() !void {
4343 cli_args = args[3..];
4444 }
4545
46 var stdout_writer2 = std.fs.File.stdout().writer(&stdout_buffer);
46 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
4747 var error_handler: ErrorHandler = switch (zig_integration) {
4848 true => .{
4949 .server = .{
50 .out = &stdout_writer2.interface,
50 .out = &stdout_writer.interface,
5151 .in = undefined, // won't be receiving messages
5252 },
5353 },
......@@ -83,18 +83,18 @@ pub fn main() !void {
8383 defer options.deinit();
8484
8585 if (options.print_help_and_exit) {
86 const stdout = std.fs.File.stdout();
87 try cli.writeUsage(stdout.deprecatedWriter(), "zig rc");
86 try cli.writeUsage(&stdout_writer.interface, "zig rc");
87 try stdout_writer.interface.flush();
8888 return;
8989 }
9090
9191 // Don't allow verbose when integrating with Zig via stdout
9292 options.verbose = false;
9393
94 const stdout_writer = std.fs.File.stdout().deprecatedWriter();
9594 if (options.verbose) {
96 try options.dumpVerbose(stdout_writer);
97 try stdout_writer.writeByte('\n');
95 try options.dumpVerbose(&stdout_writer.interface);
96 try stdout_writer.interface.writeByte('\n');
97 try stdout_writer.interface.flush();
9898 }
9999
100100 var dependencies_list = std.array_list.Managed([]const u8).init(allocator);
......@@ -115,7 +115,7 @@ pub fn main() !void {
115115
116116 const full_input = full_input: {
117117 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);
119119 errdefer preprocessed_buf.deinit();
120120
121121 // We're going to throw away everything except the final preprocessed output anyway,
......@@ -139,14 +139,15 @@ pub fn main() !void {
139139 });
140140
141141 if (options.verbose) {
142 try stdout_writer.writeAll("Preprocessor: arocc (built-in)\n");
142 try stdout_writer.interface.writeAll("Preprocessor: arocc (built-in)\n");
143143 for (argv.items[0 .. argv.items.len - 1]) |arg| {
144 try stdout_writer.print("{s} ", .{arg});
144 try stdout_writer.interface.print("{s} ", .{arg});
145145 }
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();
147148 }
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) {
150151 error.GeneratedSourceError => {
151152 try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug):", &comp);
152153 std.process.exit(1);
......@@ -249,8 +250,9 @@ pub fn main() !void {
249250 defer diagnostics.deinit();
250251
251252 var output_buffer: [4096]u8 = undefined;
252 var res_stream_writer = res_stream.source.writer(allocator).adaptToNewApi(&output_buffer);
253 const output_buffered_stream = &res_stream_writer.new_interface;
253 var res_stream_writer = res_stream.source.writer(allocator, &output_buffer);
254 defer res_stream_writer.deinit(&res_stream.source);
255 const output_buffered_stream = res_stream_writer.interface();
254256
255257 compile(allocator, final_input, output_buffered_stream, .{
256258 .cwd = std.fs.cwd(),
......@@ -342,10 +344,10 @@ pub fn main() !void {
342344 defer coff_stream.deinit(allocator);
343345
344346 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
347349 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| {
349351 switch (err) {
350352 error.DuplicateResource => {
351353 const duplicate_resource = resources.list.items[cvtres_diagnostics.duplicate_resource];
......@@ -382,7 +384,7 @@ pub fn main() !void {
382384 std.process.exit(1);
383385 };
384386
385 try coff_output_buffered_stream.new_interface.flush();
387 try coff_output_buffered_stream.interface().flush();
386388}
387389
388390const IoStream = struct {
......@@ -425,7 +427,7 @@ const IoStream = struct {
425427 pub const Source = union(enum) {
426428 file: std.fs.File,
427429 stdio: std.fs.File,
428 memory: std.ArrayListUnmanaged(u8),
430 memory: std.ArrayList(u8),
429431 /// The source has been closed and any usage of the Source in this state is illegal (except deinit).
430432 closed: void,
431433
......@@ -472,26 +474,34 @@ const IoStream = struct {
472474 };
473475 }
474476
475 pub const WriterContext = struct {
476 self: *Source,
477 allocator: std.mem.Allocator,
478 };
479 pub const WriteError = std.mem.Allocator.Error || std.fs.File.WriteError;
480 pub const Writer = std.io.GenericWriter(WriterContext, WriteError, write);
481
482 pub fn write(ctx: WriterContext, bytes: []const u8) WriteError!usize {
483 switch (ctx.self.*) {
484 inline .file, .stdio => |file| return file.write(bytes),
485 .memory => |*list| {
486 try list.appendSlice(ctx.allocator, bytes);
487 return bytes.len;
488 },
489 .closed => unreachable,
477 pub const Writer = union(enum) {
478 file: std.fs.File.Writer,
479 allocating: std.Io.Writer.Allocating,
480
481 pub const Error = std.mem.Allocator.Error || std.fs.File.WriteError;
482
483 pub fn interface(this: *@This()) *std.Io.Writer {
484 return switch (this.*) {
485 .file => |*fw| &fw.interface,
486 .allocating => |*a| &a.writer,
487 };
490488 }
491 }
492489
493 pub fn writer(self: *Source, allocator: std.mem.Allocator) Writer {
494 return .{ .context = .{ .self = self, .allocator = allocator } };
490 pub fn deinit(this: *@This(), source: *Source) void {
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 };
495505 }
496506 };
497507};
......@@ -721,7 +731,7 @@ fn cliDiagnosticsToErrorBundle(
721731 });
722732
723733 var cur_err: ?ErrorBundle.ErrorMessage = null;
724 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;
734 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
725735 defer cur_notes.deinit(gpa);
726736 for (diagnostics.errors.items) |err_details| {
727737 switch (err_details.type) {
......@@ -763,10 +773,10 @@ fn diagnosticsToErrorBundle(
763773 try bundle.init(gpa);
764774 errdefer bundle.deinit();
765775
766 var msg_buf: std.ArrayListUnmanaged(u8) = .empty;
767 defer msg_buf.deinit(gpa);
776 var msg_buf: std.Io.Writer.Allocating = .init(gpa);
777 defer msg_buf.deinit();
768778 var cur_err: ?ErrorBundle.ErrorMessage = null;
769 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;
779 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
770780 defer cur_notes.deinit(gpa);
771781 for (diagnostics.errors.items) |err_details| {
772782 switch (err_details.type) {
......@@ -789,7 +799,7 @@ fn diagnosticsToErrorBundle(
789799 const column = err_details.token.calculateColumn(source, 1, source_line_start) + 1;
790800
791801 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
794804 const src_loc = src_loc: {
795805 var src_loc: ErrorBundle.SourceLocation = .{
......@@ -817,7 +827,7 @@ fn diagnosticsToErrorBundle(
817827 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);
818828 }
819829 cur_err = .{
820 .msg = try bundle.addString(msg_buf.items),
830 .msg = try bundle.addString(msg_buf.written()),
821831 .src_loc = src_loc,
822832 };
823833 cur_notes.clearRetainingCapacity();
......@@ -825,7 +835,7 @@ fn diagnosticsToErrorBundle(
825835 .note => {
826836 cur_err.?.notes_len += 1;
827837 try cur_notes.append(gpa, .{
828 .msg = try bundle.addString(msg_buf.items),
838 .msg = try bundle.addString(msg_buf.written()),
829839 .src_loc = src_loc,
830840 });
831841 },
......@@ -876,7 +886,7 @@ fn aroDiagnosticsToErrorBundle(
876886 var msg_writer = MsgWriter.init(gpa);
877887 defer msg_writer.deinit();
878888 var cur_err: ?ErrorBundle.ErrorMessage = null;
879 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;
889 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
880890 defer cur_notes.deinit(gpa);
881891 for (comp.diagnostics.list.items) |msg| {
882892 switch (msg.kind) {
......@@ -971,11 +981,11 @@ const MsgWriter = struct {
971981 }
972982
973983 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 {};
975985 }
976986
977987 pub fn write(m: *MsgWriter, msg: []const u8) void {
978 m.buf.writer().writeAll(msg) catch {};
988 m.buf.appendSlice(msg) catch {};
979989 }
980990
981991 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(
1818 var driver: aro.Driver = .{ .comp = comp, .aro_name = "arocc" };
1919 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);
2222 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) {
2527 error.FatalError => return error.ArgError,
2628 error.OutOfMemory => |e| return e,
29 error.WriteFailed => return error.OutOfMemory,
2730 };
2831
2932 if (hasAnyErrors(comp)) return error.ArgError;
......@@ -33,7 +36,7 @@ pub fn preprocess(
3336 error.FatalError => return error.GeneratedSourceError,
3437 else => |e| return e,
3538 };
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) {
3740 error.FatalError => return error.GeneratedSourceError,
3841 else => |e| return e,
3942 };
......@@ -59,7 +62,9 @@ pub fn preprocess(
5962
6063 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
6469 if (maybe_dependencies_list) |dependencies_list| {
6570 for (comp.sources.values()) |comp_source| {