authorgravatar for lachlan@lakebythewoods.xyzLachlan Easton <lachlan@lakebythewoods.xyz> 2020-08-29 11:02:22+10:00
committergravatar for lachlan@lakebythewoods.xyzLachlan Easton <lachlan@lakebythewoods.xyz> 2020-08-29 13:35:00+10:00
loga72b9d403d036ac0da64ed826c535fff0c142e6a
tree7a9f45587e762bc92395f3a45a402f5595b907c3
parent3750cc06fda89c076da850a430d39d959ce45a99

Refactor zig fmt indentation. Remove indent from rendering code and have a stream handle automatic indentation


9 files changed, 1103 insertions(+), 907 deletions(-)

lib/std/io.zig+11-2
...@@ -169,6 +169,15 @@ pub const BitOutStream = BitWriter;...@@ -169,6 +169,15 @@ pub const BitOutStream = BitWriter;
169/// Deprecated: use `bitWriter`169/// Deprecated: use `bitWriter`
170pub const bitOutStream = bitWriter;170pub const bitOutStream = bitWriter;
171171
172pub const AutoIndentingStream = @import("io/auto_indenting_stream.zig").AutoIndentingStream;
173pub const autoIndentingStream = @import("io/auto_indenting_stream.zig").autoIndentingStream;
174
175pub const ChangeDetectionStream = @import("io/change_detection_stream.zig").ChangeDetectionStream;
176pub const changeDetectionStream = @import("io/change_detection_stream.zig").changeDetectionStream;
177
178pub const FindByteOutStream = @import("io/find_byte_out_stream.zig").FindByteOutStream;
179pub const findByteOutStream = @import("io/find_byte_out_stream.zig").findByteOutStream;
180
172pub const Packing = @import("io/serialization.zig").Packing;181pub const Packing = @import("io/serialization.zig").Packing;
173182
174pub const Serializer = @import("io/serialization.zig").Serializer;183pub const Serializer = @import("io/serialization.zig").Serializer;
...@@ -182,10 +191,10 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt...@@ -182,10 +191,10 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt
182pub const StreamSource = @import("io/stream_source.zig").StreamSource;191pub const StreamSource = @import("io/stream_source.zig").StreamSource;
183192
184/// A Writer that doesn't write to anything.193/// A Writer that doesn't write to anything.
185pub const null_writer = @as(NullWriter, .{ .context = {} });194pub var null_writer = @as(NullWriter, .{ .context = {} });
186195
187/// Deprecated: use `null_writer`196/// Deprecated: use `null_writer`
188pub const null_out_stream = null_writer;197pub var null_out_stream = null_writer;
189198
190const NullWriter = Writer(void, error{}, dummyWrite);199const NullWriter = Writer(void, error{}, dummyWrite);
191/// Deprecated: use NullWriter200/// Deprecated: use NullWriter
lib/std/io/auto_indenting_stream.zig created+135
...@@ -0,0 +1,135 @@
1const std = @import("../std.zig");
2const io = std.io;
3const mem = std.mem;
4const assert = std.debug.assert;
5
6pub fn AutoIndentingStream(comptime indent_delta: u8, comptime OutStreamType: type) type {
7 return struct {
8 const Self = @This();
9 pub const Error = OutStreamType.Error;
10 pub const OutStream = io.Writer(*Self, Error, write);
11
12 out_stream: *OutStreamType,
13 current_line_empty: bool = true,
14 indent_stack: [255]u8 = undefined,
15 indent_stack_top: u8 = 0,
16 indent_one_shot_count: u8 = 0, // automatically popped when applied
17 applied_indent: u8 = 0, // the most recently applied indent
18 indent_next_line: u8 = 0, // not used until the next line
19
20 pub fn init(out_stream: *OutStreamType) Self {
21 return Self{ .out_stream = out_stream };
22 }
23
24 pub fn writer(self: *Self) OutStream {
25 return .{ .context = self };
26 }
27
28 pub fn write(self: *Self, bytes: []const u8) Error!usize {
29 if (bytes.len == 0)
30 return @as(usize, 0);
31
32 try self.applyIndent();
33 return self.writeNoIndent(bytes);
34 }
35
36 fn writeNoIndent(self: *Self, bytes: []const u8) Error!usize {
37 try self.out_stream.outStream().writeAll(bytes);
38 if (bytes[bytes.len - 1] == '\n')
39 self.resetLine();
40 return bytes.len;
41 }
42
43 pub fn insertNewline(self: *Self) Error!void {
44 _ = try self.writeNoIndent("\n");
45 }
46
47 fn resetLine(self: *Self) void {
48 self.current_line_empty = true;
49 self.indent_next_line = 0;
50 }
51
52 /// Insert a newline unless the current line is blank
53 pub fn maybeInsertNewline(self: *Self) Error!void {
54 if (!self.current_line_empty)
55 try self.insertNewline();
56 }
57
58 /// Push default indentation
59 pub fn pushIndent(self: *Self) void {
60 // Doesn't actually write any indentation. Just primes the stream to be able to write the correct indentation if it needs to.
61 self.pushIndentN(indent_delta);
62 }
63
64 /// Push an indent of arbitrary width
65 pub fn pushIndentN(self: *Self, n: u8) void {
66 assert(self.indent_stack_top < std.math.maxInt(u8));
67 self.indent_stack[self.indent_stack_top] = n;
68 self.indent_stack_top += 1;
69 }
70
71 /// Push an indent that is automatically popped after being applied
72 pub fn pushIndentOneShot(self: *Self) void {
73 self.indent_one_shot_count += 1;
74 self.pushIndent();
75 }
76
77 /// Turns all one-shot indents into regular indents
78 /// Returns number of indents that must now be manually popped
79 pub fn lockOneShotIndent(self: *Self) u8 {
80 var locked_count = self.indent_one_shot_count;
81 self.indent_one_shot_count = 0;
82 return locked_count;
83 }
84
85 /// Push an indent that should not take effect until the next line
86 pub fn pushIndentNextLine(self: *Self) void {
87 self.indent_next_line += 1;
88 self.pushIndent();
89 }
90
91 pub fn popIndent(self: *Self) void {
92 assert(self.indent_stack_top != 0);
93 self.indent_stack_top -= 1;
94 self.indent_next_line = std.math.min(self.indent_stack_top, self.indent_next_line); // Tentative indent may have been popped before there was a newline
95 }
96
97 /// Writes ' ' bytes if the current line is empty
98 fn applyIndent(self: *Self) Error!void {
99 const current_indent = self.currentIndent();
100 if (self.current_line_empty and current_indent > 0) {
101 try self.out_stream.outStream().writeByteNTimes(' ', current_indent);
102 self.applied_indent = current_indent;
103 }
104
105 self.indent_stack_top -= self.indent_one_shot_count;
106 self.indent_one_shot_count = 0;
107 self.current_line_empty = false;
108 }
109
110 /// Checks to see if the most recent indentation exceeds the currently pushed indents
111 pub fn isLineOverIndented(self: *Self) bool {
112 if (self.current_line_empty) return false;
113 return self.applied_indent > self.currentIndent();
114 }
115
116 fn currentIndent(self: *Self) u8 {
117 var indent_current: u8 = 0;
118 if (self.indent_stack_top > 0) {
119 const stack_top = self.indent_stack_top - self.indent_next_line;
120 for (self.indent_stack[0..stack_top]) |indent| {
121 indent_current += indent;
122 }
123 }
124 return indent_current;
125 }
126 };
127}
128
129pub fn autoIndentingStream(
130 comptime indent_delta: u8,
131 underlying_stream: anytype,
132) AutoIndentingStream(indent_delta, @TypeOf(underlying_stream).Child) {
133 comptime assert(@typeInfo(@TypeOf(underlying_stream)) == .Pointer);
134 return AutoIndentingStream(indent_delta, @TypeOf(underlying_stream).Child).init(underlying_stream);
135}
lib/std/io/change_detection_stream.zig created+58
...@@ -0,0 +1,58 @@
1const std = @import("../std.zig");
2const io = std.io;
3const mem = std.mem;
4const assert = std.debug.assert;
5
6pub fn ChangeDetectionStream(comptime OutStreamType: type) type {
7 return struct {
8 const Self = @This();
9 pub const Error = OutStreamType.Error;
10 pub const OutStream = io.OutStream(*Self, Error, write);
11
12 anything_changed: bool = false,
13 out_stream: *OutStreamType,
14 source_index: usize,
15 source: []const u8,
16
17 pub fn init(source: []const u8, out_stream: *OutStreamType) Self {
18 return Self{
19 .out_stream = out_stream,
20 .source_index = 0,
21 .source = source,
22 };
23 }
24
25 pub fn outStream(self: *Self) OutStream {
26 return .{ .context = self };
27 }
28
29 fn write(self: *Self, bytes: []const u8) Error!usize {
30 if (!self.anything_changed) {
31 const end = self.source_index + bytes.len;
32 if (end > self.source.len) {
33 self.anything_changed = true;
34 } else {
35 const src_slice = self.source[self.source_index..end];
36 self.source_index += bytes.len;
37 if (!mem.eql(u8, bytes, src_slice)) {
38 self.anything_changed = true;
39 }
40 }
41 }
42
43 return self.out_stream.write(bytes);
44 }
45
46 pub fn changeDetected(self: *Self) bool {
47 return self.anything_changed or (self.source_index != self.source.len);
48 }
49 };
50}
51
52pub fn changeDetectionStream(
53 source: []const u8,
54 underlying_stream: anytype,
55) ChangeDetectionStream(@TypeOf(underlying_stream).Child) {
56 comptime assert(@typeInfo(@TypeOf(underlying_stream)) == .Pointer);
57 return ChangeDetectionStream(@TypeOf(underlying_stream).Child).init(source, underlying_stream);
58}
lib/std/io/find_byte_out_stream.zig created+44
...@@ -0,0 +1,44 @@
1const std = @import("../std.zig");
2const io = std.io;
3const assert = std.debug.assert;
4
5// An OutStream that returns whether the given character has been written to it.
6// The contents are not written to anything.
7pub fn FindByteOutStream(comptime OutStreamType: type) type {
8 return struct {
9 const Self = @This();
10 pub const Error = OutStreamType.Error;
11 pub const OutStream = io.OutStream(*Self, Error, write);
12
13 out_stream: *OutStreamType,
14 byte_found: bool,
15 byte: u8,
16
17 pub fn init(byte: u8, out_stream: *OutStreamType) Self {
18 return Self{
19 .out_stream = out_stream,
20 .byte = byte,
21 .byte_found = false,
22 };
23 }
24
25 pub fn outStream(self: *Self) OutStream {
26 return .{ .context = self };
27 }
28
29 fn write(self: *Self, bytes: []const u8) Error!usize {
30 if (!self.byte_found) {
31 self.byte_found = blk: {
32 for (bytes) |b|
33 if (b == self.byte) break :blk true;
34 break :blk false;
35 };
36 }
37 return self.out_stream.writer().write(bytes);
38 }
39 };
40}
41pub fn findByteOutStream(byte: u8, underlying_stream: anytype) FindByteOutStream(@TypeOf(underlying_stream).Child) {
42 comptime assert(@typeInfo(@TypeOf(underlying_stream)) == .Pointer);
43 return FindByteOutStream(@TypeOf(underlying_stream).Child).init(byte, underlying_stream);
44}
lib/std/io/writer.zig+4
...@@ -18,6 +18,10 @@ pub fn Writer(...@@ -18,6 +18,10 @@ pub fn Writer(
18 const Self = @This();18 const Self = @This();
19 pub const Error = WriteError;19 pub const Error = WriteError;
2020
21 pub fn writer(self: *const Self) Self {
22 return self.*;
23 }
24
21 pub fn write(self: Self, bytes: []const u8) Error!usize {25 pub fn write(self: Self, bytes: []const u8) Error!usize {
22 return writeFn(self.context, bytes);26 return writeFn(self.context, bytes);
23 }27 }
lib/std/zig/parser_test.zig+103-6
...@@ -615,6 +615,17 @@ test "zig fmt: infix operator and then multiline string literal" {...@@ -615,6 +615,17 @@ test "zig fmt: infix operator and then multiline string literal" {
615 );615 );
616}616}
617617
618test "zig fmt: infix operator and then multiline string literal" {
619 try testCanonical(
620 \\const x = "" ++
621 \\ \\ hi0
622 \\ \\ hi1
623 \\ \\ hi2
624 \\;
625 \\
626 );
627}
628
618test "zig fmt: C pointers" {629test "zig fmt: C pointers" {
619 try testCanonical(630 try testCanonical(
620 \\const Ptr = [*c]i32;631 \\const Ptr = [*c]i32;
...@@ -885,6 +896,28 @@ test "zig fmt: 2nd arg multiline string" {...@@ -885,6 +896,28 @@ test "zig fmt: 2nd arg multiline string" {
885 );896 );
886}897}
887898
899test "zig fmt: 2nd arg multiline string many args" {
900 try testCanonical(
901 \\comptime {
902 \\ cases.addAsm("hello world linux x86_64",
903 \\ \\.text
904 \\ , "Hello, world!\n", "Hello, world!\n");
905 \\}
906 \\
907 );
908}
909
910test "zig fmt: final arg multiline string" {
911 try testCanonical(
912 \\comptime {
913 \\ cases.addAsm("hello world linux x86_64", "Hello, world!\n",
914 \\ \\.text
915 \\ );
916 \\}
917 \\
918 );
919}
920
888test "zig fmt: if condition wraps" {921test "zig fmt: if condition wraps" {
889 try testTransform(922 try testTransform(
890 \\comptime {923 \\comptime {
...@@ -915,6 +948,11 @@ test "zig fmt: if condition wraps" {...@@ -915,6 +948,11 @@ test "zig fmt: if condition wraps" {
915 \\ var a = if (a) |*f| x: {948 \\ var a = if (a) |*f| x: {
916 \\ break :x &a.b;949 \\ break :x &a.b;
917 \\ } else |err| err;950 \\ } else |err| err;
951 \\ var a = if (cond and
952 \\ cond) |*f|
953 \\ x: {
954 \\ break :x &a.b;
955 \\ } else |err| err;
918 \\}956 \\}
919 ,957 ,
920 \\comptime {958 \\comptime {
...@@ -951,6 +989,35 @@ test "zig fmt: if condition wraps" {...@@ -951,6 +989,35 @@ test "zig fmt: if condition wraps" {
951 \\ var a = if (a) |*f| x: {989 \\ var a = if (a) |*f| x: {
952 \\ break :x &a.b;990 \\ break :x &a.b;
953 \\ } else |err| err;991 \\ } else |err| err;
992 \\ var a = if (cond and
993 \\ cond) |*f|
994 \\ x: {
995 \\ break :x &a.b;
996 \\ } else |err| err;
997 \\}
998 \\
999 );
1000}
1001
1002test "zig fmt: if condition has line break but must not wrap" {
1003 try testCanonical(
1004 \\comptime {
1005 \\ if (self.user_input_options.put(
1006 \\ name,
1007 \\ UserInputOption{
1008 \\ .name = name,
1009 \\ .used = false,
1010 \\ },
1011 \\ ) catch unreachable) |*prev_value| {
1012 \\ foo();
1013 \\ bar();
1014 \\ }
1015 \\ if (put(
1016 \\ a,
1017 \\ b,
1018 \\ )) {
1019 \\ foo();
1020 \\ }
954 \\}1021 \\}
955 \\1022 \\
956 );1023 );
...@@ -977,6 +1044,18 @@ test "zig fmt: if condition has line break but must not wrap" {...@@ -977,6 +1044,18 @@ test "zig fmt: if condition has line break but must not wrap" {
977 );1044 );
978}1045}
9791046
1047test "zig fmt: function call with multiline argument" {
1048 try testCanonical(
1049 \\comptime {
1050 \\ self.user_input_options.put(name, UserInputOption{
1051 \\ .name = name,
1052 \\ .used = false,
1053 \\ });
1054 \\}
1055 \\
1056 );
1057}
1058
980test "zig fmt: same-line doc comment on variable declaration" {1059test "zig fmt: same-line doc comment on variable declaration" {
981 try testTransform(1060 try testTransform(
982 \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space1061 \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
...@@ -1228,7 +1307,7 @@ test "zig fmt: array literal with hint" {...@@ -1228,7 +1307,7 @@ test "zig fmt: array literal with hint" {
1228 \\const a = []u8{1307 \\const a = []u8{
1229 \\ 1, 2,1308 \\ 1, 2,
1230 \\ 3, //1309 \\ 3, //
1231 \\ 4,1310 \\ 4,
1232 \\ 5, 6,1311 \\ 5, 6,
1233 \\ 7,1312 \\ 7,
1234 \\};1313 \\};
...@@ -1293,7 +1372,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {...@@ -1293,7 +1372,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {
1293 \\ \\ZIG_C_HEADER_FILES {}1372 \\ \\ZIG_C_HEADER_FILES {}
1294 \\ \\ZIG_DIA_GUIDS_LIB {}1373 \\ \\ZIG_DIA_GUIDS_LIB {}
1295 \\ \\1374 \\ \\
1296 \\ ,1375 \\ ,
1297 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),1376 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
1298 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),1377 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
1299 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),1378 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
...@@ -2885,20 +2964,20 @@ test "zig fmt: multiline string in array" {...@@ -2885,20 +2964,20 @@ test "zig fmt: multiline string in array" {
2885 try testCanonical(2964 try testCanonical(
2886 \\const Foo = [][]const u8{2965 \\const Foo = [][]const u8{
2887 \\ \\aaa2966 \\ \\aaa
2888 \\,2967 \\ ,
2889 \\ \\bbb2968 \\ \\bbb
2890 \\};2969 \\};
2891 \\2970 \\
2892 \\fn bar() void {2971 \\fn bar() void {
2893 \\ const Foo = [][]const u8{2972 \\ const Foo = [][]const u8{
2894 \\ \\aaa2973 \\ \\aaa
2895 \\ ,2974 \\ ,
2896 \\ \\bbb2975 \\ \\bbb
2897 \\ };2976 \\ };
2898 \\ const Bar = [][]const u8{ // comment here2977 \\ const Bar = [][]const u8{ // comment here
2899 \\ \\aaa2978 \\ \\aaa
2900 \\ \\2979 \\ \\
2901 \\ , // and another comment can go here2980 \\ , // and another comment can go here
2902 \\ \\bbb2981 \\ \\bbb
2903 \\ };2982 \\ };
2904 \\}2983 \\}
...@@ -3214,6 +3293,23 @@ test "zig fmt: C var args" {...@@ -3214,6 +3293,23 @@ test "zig fmt: C var args" {
3214 );3293 );
3215}3294}
32163295
3296test "zig fmt: Only indent multiline string literals in function calls" {
3297 try testCanonical(
3298 \\test "zig fmt:" {
3299 \\ try testTransform(
3300 \\ \\const X = struct {
3301 \\ \\ foo: i32, bar: i8 };
3302 \\ ,
3303 \\ \\const X = struct {
3304 \\ \\ foo: i32, bar: i8
3305 \\ \\};
3306 \\ \\
3307 \\ );
3308 \\}
3309 \\
3310 );
3311}
3312
3217const std = @import("std");3313const std = @import("std");
3218const mem = std.mem;3314const mem = std.mem;
3219const warn = std.debug.warn;3315const warn = std.debug.warn;
...@@ -3256,7 +3352,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b...@@ -3256,7 +3352,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
3256 var buffer = std.ArrayList(u8).init(allocator);3352 var buffer = std.ArrayList(u8).init(allocator);
3257 errdefer buffer.deinit();3353 errdefer buffer.deinit();
32583354
3259 anything_changed.* = try std.zig.render(allocator, buffer.outStream(), tree);3355 const outStream = buffer.outStream();
3356 anything_changed.* = try std.zig.render(allocator, &outStream, tree);
3260 return buffer.toOwnedSlice();3357 return buffer.toOwnedSlice();
3261}3358}
3262fn testTransform(source: []const u8, expected_source: []const u8) !void {3359fn testTransform(source: []const u8, expected_source: []const u8) !void {
lib/std/zig/render.zig+742-894
...@@ -6,6 +6,7 @@...@@ -6,6 +6,7 @@
6const std = @import("../std.zig");6const std = @import("../std.zig");
7const assert = std.debug.assert;7const assert = std.debug.assert;
8const mem = std.mem;8const mem = std.mem;
9const meta = std.meta;
9const ast = std.zig.ast;10const ast = std.zig.ast;
10const Token = std.zig.Token;11const Token = std.zig.Token;
1112
...@@ -17,74 +18,37 @@ pub const Error = error{...@@ -17,74 +18,37 @@ pub const Error = error{
17};18};
1819
19/// Returns whether anything changed20/// Returns whether anything changed
20pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (@TypeOf(stream).Error || Error)!bool {21pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (meta.Child(@TypeOf(stream)).Error || Error)!bool {
21 // cannot render an invalid tree22 // cannot render an invalid tree
22 std.debug.assert(tree.errors.len == 0);23 std.debug.assert(tree.errors.len == 0);
2324
24 // make a passthrough stream that checks whether something changed25 var s = stream.*;
25 const MyStream = struct {26 var change_detection_stream = std.io.changeDetectionStream(tree.source, &s);
26 const MyStream = @This();27 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &change_detection_stream);
27 const StreamError = @TypeOf(stream).Error;
28
29 child_stream: @TypeOf(stream),
30 anything_changed: bool,
31 source_index: usize,
32 source: []const u8,
33
34 fn write(self: *MyStream, bytes: []const u8) StreamError!usize {
35 if (!self.anything_changed) {
36 const end = self.source_index + bytes.len;
37 if (end > self.source.len) {
38 self.anything_changed = true;
39 } else {
40 const src_slice = self.source[self.source_index..end];
41 self.source_index += bytes.len;
42 if (!mem.eql(u8, bytes, src_slice)) {
43 self.anything_changed = true;
44 }
45 }
46 }
47
48 return self.child_stream.write(bytes);
49 }
50 };
51 var my_stream = MyStream{
52 .child_stream = stream,
53 .anything_changed = false,
54 .source_index = 0,
55 .source = tree.source,
56 };
57 const my_stream_stream: std.io.Writer(*MyStream, MyStream.StreamError, MyStream.write) = .{
58 .context = &my_stream,
59 };
6028
61 try renderRoot(allocator, my_stream_stream, tree);29 try renderRoot(allocator, &auto_indenting_stream, tree);
6230
63 if (my_stream.source_index != my_stream.source.len) {31 return change_detection_stream.changeDetected();
64 my_stream.anything_changed = true;
65 }
66
67 return my_stream.anything_changed;
68}32}
6933
70fn renderRoot(34fn renderRoot(
71 allocator: *mem.Allocator,35 allocator: *mem.Allocator,
72 stream: anytype,36 stream: anytype,
73 tree: *ast.Tree,37 tree: *ast.Tree,
74) (@TypeOf(stream).Error || Error)!void {38) (@TypeOf(stream.*).Error || Error)!void {
39
75 // render all the line comments at the beginning of the file40 // render all the line comments at the beginning of the file
76 for (tree.token_ids) |token_id, i| {41 for (tree.token_ids) |token_id, i| {
77 if (token_id != .LineComment) break;42 if (token_id != .LineComment) break;
78 const token_loc = tree.token_locs[i];43 const token_loc = tree.token_locs[i];
79 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});44 try stream.writer().print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
80 const next_token = tree.token_locs[i + 1];45 const next_token = tree.token_locs[i + 1];
81 const loc = tree.tokenLocationLoc(token_loc.end, next_token);46 const loc = tree.tokenLocationLoc(token_loc.end, next_token);
82 if (loc.line >= 2) {47 if (loc.line >= 2) {
83 try stream.writeByte('\n');48 try stream.insertNewline();
84 }49 }
85 }50 }
8651
87 var start_col: usize = 0;
88 var decl_i: ast.NodeIndex = 0;52 var decl_i: ast.NodeIndex = 0;
89 const root_decls = tree.root_node.decls();53 const root_decls = tree.root_node.decls();
9054
...@@ -189,23 +153,22 @@ fn renderRoot(...@@ -189,23 +153,22 @@ fn renderRoot(
189 try copyFixingWhitespace(stream, tree.source[start..end]);153 try copyFixingWhitespace(stream, tree.source[start..end]);
190 }154 }
191155
192 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);156 try renderTopLevelDecl(allocator, stream, tree, decl);
193 decl_i += 1;157 decl_i += 1;
194 if (decl_i >= root_decls.len) return;158 if (decl_i >= root_decls.len) return;
195 try renderExtraNewline(tree, stream, &start_col, root_decls[decl_i]);159 try renderExtraNewline(tree, stream, root_decls[decl_i]);
196 }160 }
197}161}
198162
199fn renderExtraNewline(tree: *ast.Tree, stream: anytype, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {163fn renderExtraNewline(tree: *ast.Tree, stream: anytype, node: *ast.Node) @TypeOf(stream.*).Error!void {
200 return renderExtraNewlineToken(tree, stream, start_col, node.firstToken());164 return renderExtraNewlineToken(tree, stream, node.firstToken());
201}165}
202166
203fn renderExtraNewlineToken(167fn renderExtraNewlineToken(
204 tree: *ast.Tree,168 tree: *ast.Tree,
205 stream: anytype,169 stream: anytype,
206 start_col: *usize,
207 first_token: ast.TokenIndex,170 first_token: ast.TokenIndex,
208) @TypeOf(stream).Error!void {171) @TypeOf(stream.*).Error!void {
209 var prev_token = first_token;172 var prev_token = first_token;
210 if (prev_token == 0) return;173 if (prev_token == 0) return;
211 var newline_threshold: usize = 2;174 var newline_threshold: usize = 2;
...@@ -218,28 +181,27 @@ fn renderExtraNewlineToken(...@@ -218,28 +181,27 @@ fn renderExtraNewlineToken(
218 const prev_token_end = tree.token_locs[prev_token - 1].end;181 const prev_token_end = tree.token_locs[prev_token - 1].end;
219 const loc = tree.tokenLocation(prev_token_end, first_token);182 const loc = tree.tokenLocation(prev_token_end, first_token);
220 if (loc.line >= newline_threshold) {183 if (loc.line >= newline_threshold) {
221 try stream.writeByte('\n');184 try stream.insertNewline();
222 start_col.* = 0;
223 }185 }
224}186}
225187
226fn renderTopLevelDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Error || Error)!void {188fn renderTopLevelDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, decl: *ast.Node) (@TypeOf(stream.*).Error || Error)!void {
227 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Newline);189 try renderContainerDecl(allocator, stream, tree, decl, .Newline);
228}190}
229191
230fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Error || Error)!void {192fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, decl: *ast.Node, space: Space) (@TypeOf(stream.*).Error || Error)!void {
231 switch (decl.tag) {193 switch (decl.tag) {
232 .FnProto => {194 .FnProto => {
233 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);195 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
234196
235 try renderDocComments(tree, stream, fn_proto, fn_proto.getTrailer("doc_comments"), indent, start_col);197 try renderDocComments(tree, stream, fn_proto, fn_proto.getTrailer("doc_comments"));
236198
237 if (fn_proto.getTrailer("body_node")) |body_node| {199 if (fn_proto.getTrailer("body_node")) |body_node| {
238 try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);200 try renderExpression(allocator, stream, tree, decl, .Space);
239 try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);201 try renderExpression(allocator, stream, tree, body_node, space);
240 } else {202 } else {
241 try renderExpression(allocator, stream, tree, indent, start_col, decl, .None);203 try renderExpression(allocator, stream, tree, decl, .None);
242 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, start_col, space);204 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), space);
243 }205 }
244 },206 },
245207
...@@ -247,35 +209,35 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr...@@ -247,35 +209,35 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
247 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);209 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
248210
249 if (use_decl.visib_token) |visib_token| {211 if (use_decl.visib_token) |visib_token| {
250 try renderToken(tree, stream, visib_token, indent, start_col, .Space); // pub212 try renderToken(tree, stream, visib_token, .Space); // pub
251 }213 }
252 try renderToken(tree, stream, use_decl.use_token, indent, start_col, .Space); // usingnamespace214 try renderToken(tree, stream, use_decl.use_token, .Space); // usingnamespace
253 try renderExpression(allocator, stream, tree, indent, start_col, use_decl.expr, .None);215 try renderExpression(allocator, stream, tree, use_decl.expr, .None);
254 try renderToken(tree, stream, use_decl.semicolon_token, indent, start_col, space); // ;216 try renderToken(tree, stream, use_decl.semicolon_token, space); // ;
255 },217 },
256218
257 .VarDecl => {219 .VarDecl => {
258 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);220 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
259221
260 try renderDocComments(tree, stream, var_decl, var_decl.getTrailer("doc_comments"), indent, start_col);222 try renderDocComments(tree, stream, var_decl, var_decl.getTrailer("doc_comments"));
261 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);223 try renderVarDecl(allocator, stream, tree, var_decl);
262 },224 },
263225
264 .TestDecl => {226 .TestDecl => {
265 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);227 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
266228
267 try renderDocComments(tree, stream, test_decl, test_decl.doc_comments, indent, start_col);229 try renderDocComments(tree, stream, test_decl, test_decl.doc_comments);
268 try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);230 try renderToken(tree, stream, test_decl.test_token, .Space);
269 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);231 try renderExpression(allocator, stream, tree, test_decl.name, .Space);
270 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space);232 try renderExpression(allocator, stream, tree, test_decl.body_node, space);
271 },233 },
272234
273 .ContainerField => {235 .ContainerField => {
274 const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);236 const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
275237
276 try renderDocComments(tree, stream, field, field.doc_comments, indent, start_col);238 try renderDocComments(tree, stream, field, field.doc_comments);
277 if (field.comptime_token) |t| {239 if (field.comptime_token) |t| {
278 try renderToken(tree, stream, t, indent, start_col, .Space); // comptime240 try renderToken(tree, stream, t, .Space); // comptime
279 }241 }
280242
281 const src_has_trailing_comma = blk: {243 const src_has_trailing_comma = blk: {
...@@ -288,68 +250,67 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr...@@ -288,68 +250,67 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
288 const last_token_space: Space = if (src_has_trailing_comma) .None else space;250 const last_token_space: Space = if (src_has_trailing_comma) .None else space;
289251
290 if (field.type_expr == null and field.value_expr == null) {252 if (field.type_expr == null and field.value_expr == null) {
291 try renderToken(tree, stream, field.name_token, indent, start_col, last_token_space); // name253 try renderToken(tree, stream, field.name_token, last_token_space); // name
292 } else if (field.type_expr != null and field.value_expr == null) {254 } else if (field.type_expr != null and field.value_expr == null) {
293 try renderToken(tree, stream, field.name_token, indent, start_col, .None); // name255 try renderToken(tree, stream, field.name_token, .None); // name
294 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // :256 try renderToken(tree, stream, tree.nextToken(field.name_token), .Space); // :
295257
296 if (field.align_expr) |align_value_expr| {258 if (field.align_expr) |align_value_expr| {
297 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type259 try renderExpression(allocator, stream, tree, field.type_expr.?, .Space); // type
298 const lparen_token = tree.prevToken(align_value_expr.firstToken());260 const lparen_token = tree.prevToken(align_value_expr.firstToken());
299 const align_kw = tree.prevToken(lparen_token);261 const align_kw = tree.prevToken(lparen_token);
300 const rparen_token = tree.nextToken(align_value_expr.lastToken());262 const rparen_token = tree.nextToken(align_value_expr.lastToken());
301 try renderToken(tree, stream, align_kw, indent, start_col, .None); // align263 try renderToken(tree, stream, align_kw, .None); // align
302 try renderToken(tree, stream, lparen_token, indent, start_col, .None); // (264 try renderToken(tree, stream, lparen_token, .None); // (
303 try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment265 try renderExpression(allocator, stream, tree, align_value_expr, .None); // alignment
304 try renderToken(tree, stream, rparen_token, indent, start_col, last_token_space); // )266 try renderToken(tree, stream, rparen_token, last_token_space); // )
305 } else {267 } else {
306 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, last_token_space); // type268 try renderExpression(allocator, stream, tree, field.type_expr.?, last_token_space); // type
307 }269 }
308 } else if (field.type_expr == null and field.value_expr != null) {270 } else if (field.type_expr == null and field.value_expr != null) {
309 try renderToken(tree, stream, field.name_token, indent, start_col, .Space); // name271 try renderToken(tree, stream, field.name_token, .Space); // name
310 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // =272 try renderToken(tree, stream, tree.nextToken(field.name_token), .Space); // =
311 try renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, last_token_space); // value273 try renderExpression(allocator, stream, tree, field.value_expr.?, last_token_space); // value
312 } else {274 } else {
313 try renderToken(tree, stream, field.name_token, indent, start_col, .None); // name275 try renderToken(tree, stream, field.name_token, .None); // name
314 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // :276 try renderToken(tree, stream, tree.nextToken(field.name_token), .Space); // :
315277
316 if (field.align_expr) |align_value_expr| {278 if (field.align_expr) |align_value_expr| {
317 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type279 try renderExpression(allocator, stream, tree, field.type_expr.?, .Space); // type
318 const lparen_token = tree.prevToken(align_value_expr.firstToken());280 const lparen_token = tree.prevToken(align_value_expr.firstToken());
319 const align_kw = tree.prevToken(lparen_token);281 const align_kw = tree.prevToken(lparen_token);
320 const rparen_token = tree.nextToken(align_value_expr.lastToken());282 const rparen_token = tree.nextToken(align_value_expr.lastToken());
321 try renderToken(tree, stream, align_kw, indent, start_col, .None); // align283 try renderToken(tree, stream, align_kw, .None); // align
322 try renderToken(tree, stream, lparen_token, indent, start_col, .None); // (284 try renderToken(tree, stream, lparen_token, .None); // (
323 try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment285 try renderExpression(allocator, stream, tree, align_value_expr, .None); // alignment
324 try renderToken(tree, stream, rparen_token, indent, start_col, .Space); // )286 try renderToken(tree, stream, rparen_token, .Space); // )
325 } else {287 } else {
326 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type288 try renderExpression(allocator, stream, tree, field.type_expr.?, .Space); // type
327 }289 }
328 try renderToken(tree, stream, tree.prevToken(field.value_expr.?.firstToken()), indent, start_col, .Space); // =290 try renderToken(tree, stream, tree.prevToken(field.value_expr.?.firstToken()), .Space); // =
329 try renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, last_token_space); // value291 try renderExpression(allocator, stream, tree, field.value_expr.?, last_token_space); // value
330 }292 }
331293
332 if (src_has_trailing_comma) {294 if (src_has_trailing_comma) {
333 const comma = tree.nextToken(field.lastToken());295 const comma = tree.nextToken(field.lastToken());
334 try renderToken(tree, stream, comma, indent, start_col, space);296 try renderToken(tree, stream, comma, space);
335 }297 }
336 },298 },
337299
338 .Comptime => {300 .Comptime => {
339 assert(!decl.requireSemiColon());301 assert(!decl.requireSemiColon());
340 try renderExpression(allocator, stream, tree, indent, start_col, decl, space);302 try renderExpression(allocator, stream, tree, decl, space);
341 },303 },
342304
343 .DocComment => {305 .DocComment => {
344 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);306 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);
345 const kind = tree.token_ids[comment.first_line];307 const kind = tree.token_ids[comment.first_line];
346 try renderToken(tree, stream, comment.first_line, indent, start_col, .Newline);308 try renderToken(tree, stream, comment.first_line, .Newline);
347 var tok_i = comment.first_line + 1;309 var tok_i = comment.first_line + 1;
348 while (true) : (tok_i += 1) {310 while (true) : (tok_i += 1) {
349 const tok_id = tree.token_ids[tok_i];311 const tok_id = tree.token_ids[tok_i];
350 if (tok_id == kind) {312 if (tok_id == kind) {
351 try stream.writeByteNTimes(' ', indent);313 try renderToken(tree, stream, tok_i, .Newline);
352 try renderToken(tree, stream, tok_i, indent, start_col, .Newline);
353 } else if (tok_id == .LineComment) {314 } else if (tok_id == .LineComment) {
354 continue;315 continue;
355 } else {316 } else {
...@@ -365,11 +326,9 @@ fn renderExpression(...@@ -365,11 +326,9 @@ fn renderExpression(
365 allocator: *mem.Allocator,326 allocator: *mem.Allocator,
366 stream: anytype,327 stream: anytype,
367 tree: *ast.Tree,328 tree: *ast.Tree,
368 indent: usize,
369 start_col: *usize,
370 base: *ast.Node,329 base: *ast.Node,
371 space: Space,330 space: Space,
372) (@TypeOf(stream).Error || Error)!void {331) (@TypeOf(stream.*).Error || Error)!void {
373 switch (base.tag) {332 switch (base.tag) {
374 .Identifier,333 .Identifier,
375 .IntegerLiteral,334 .IntegerLiteral,
...@@ -383,18 +342,18 @@ fn renderExpression(...@@ -383,18 +342,18 @@ fn renderExpression(
383 .UndefinedLiteral,342 .UndefinedLiteral,
384 => {343 => {
385 const casted_node = base.cast(ast.Node.OneToken).?;344 const casted_node = base.cast(ast.Node.OneToken).?;
386 return renderToken(tree, stream, casted_node.token, indent, start_col, space);345 return renderToken(tree, stream, casted_node.token, space);
387 },346 },
388347
389 .AnyType => {348 .AnyType => {
390 const any_type = base.castTag(.AnyType).?;349 const any_type = base.castTag(.AnyType).?;
391 if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {350 if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {
392 // TODO remove in next release cycle351 // TODO remove in next release cycle
393 try stream.writeAll("anytype");352 try stream.writer().writeAll("anytype");
394 if (space == .Comma) try stream.writeAll(",\n");353 if (space == .Comma) try stream.writer().writeAll(",\n");
395 return;354 return;
396 }355 }
397 return renderToken(tree, stream, any_type.token, indent, start_col, space);356 return renderToken(tree, stream, any_type.token, space);
398 },357 },
399358
400 .Block, .LabeledBlock => {359 .Block, .LabeledBlock => {
...@@ -424,65 +383,65 @@ fn renderExpression(...@@ -424,65 +383,65 @@ fn renderExpression(
424 };383 };
425384
426 if (block.label) |label| {385 if (block.label) |label| {
427 try renderToken(tree, stream, label, indent, start_col, Space.None);386 try renderToken(tree, stream, label, Space.None);
428 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);387 try renderToken(tree, stream, tree.nextToken(label), Space.Space);
429 }388 }
430389
431 if (block.statements.len == 0) {390 if (block.statements.len == 0) {
432 try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None);391 stream.pushIndentNextLine();
433 return renderToken(tree, stream, block.rbrace, indent, start_col, space);392 defer stream.popIndent();
393 try renderToken(tree, stream, block.lbrace, Space.None);
434 } else {394 } else {
435 const block_indent = indent + indent_delta;395 stream.pushIndentNextLine();
436 try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);396 defer stream.popIndent();
397
398 try renderToken(tree, stream, block.lbrace, Space.Newline);
437399
438 for (block.statements) |statement, i| {400 for (block.statements) |statement, i| {
439 try stream.writeByteNTimes(' ', block_indent);401 try renderStatement(allocator, stream, tree, statement);
440 try renderStatement(allocator, stream, tree, block_indent, start_col, statement);
441402
442 if (i + 1 < block.statements.len) {403 if (i + 1 < block.statements.len) {
443 try renderExtraNewline(tree, stream, start_col, block.statements[i + 1]);404 try renderExtraNewline(tree, stream, block.statements[i + 1]);
444 }405 }
445 }406 }
446
447 try stream.writeByteNTimes(' ', indent);
448 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
449 }407 }
408 return renderToken(tree, stream, block.rbrace, space);
450 },409 },
451410
452 .Defer => {411 .Defer => {
453 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);412 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
454413
455 try renderToken(tree, stream, defer_node.defer_token, indent, start_col, Space.Space);414 try renderToken(tree, stream, defer_node.defer_token, Space.Space);
456 if (defer_node.payload) |payload| {415 if (defer_node.payload) |payload| {
457 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);416 try renderExpression(allocator, stream, tree, payload, Space.Space);
458 }417 }
459 return renderExpression(allocator, stream, tree, indent, start_col, defer_node.expr, space);418 return renderExpression(allocator, stream, tree, defer_node.expr, space);
460 },419 },
461 .Comptime => {420 .Comptime => {
462 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);421 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
463422
464 try renderToken(tree, stream, comptime_node.comptime_token, indent, start_col, Space.Space);423 try renderToken(tree, stream, comptime_node.comptime_token, Space.Space);
465 return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);424 return renderExpression(allocator, stream, tree, comptime_node.expr, space);
466 },425 },
467 .Nosuspend => {426 .Nosuspend => {
468 const nosuspend_node = @fieldParentPtr(ast.Node.Nosuspend, "base", base);427 const nosuspend_node = @fieldParentPtr(ast.Node.Nosuspend, "base", base);
469 if (mem.eql(u8, tree.tokenSlice(nosuspend_node.nosuspend_token), "noasync")) {428 if (mem.eql(u8, tree.tokenSlice(nosuspend_node.nosuspend_token), "noasync")) {
470 // TODO: remove this429 // TODO: remove this
471 try stream.writeAll("nosuspend ");430 try stream.writer().writeAll("nosuspend ");
472 } else {431 } else {
473 try renderToken(tree, stream, nosuspend_node.nosuspend_token, indent, start_col, Space.Space);432 try renderToken(tree, stream, nosuspend_node.nosuspend_token, Space.Space);
474 }433 }
475 return renderExpression(allocator, stream, tree, indent, start_col, nosuspend_node.expr, space);434 return renderExpression(allocator, stream, tree, nosuspend_node.expr, space);
476 },435 },
477436
478 .Suspend => {437 .Suspend => {
479 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);438 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
480439
481 if (suspend_node.body) |body| {440 if (suspend_node.body) |body| {
482 try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);441 try renderToken(tree, stream, suspend_node.suspend_token, Space.Space);
483 return renderExpression(allocator, stream, tree, indent, start_col, body, space);442 return renderExpression(allocator, stream, tree, body, space);
484 } else {443 } else {
485 return renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, space);444 return renderToken(tree, stream, suspend_node.suspend_token, space);
486 }445 }
487 },446 },
488447
...@@ -490,26 +449,21 @@ fn renderExpression(...@@ -490,26 +449,21 @@ fn renderExpression(
490 const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base);449 const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base);
491450
492 const op_space = Space.Space;451 const op_space = Space.Space;
493 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);452 try renderExpression(allocator, stream, tree, infix_op_node.lhs, op_space);
494453
495 const after_op_space = blk: {454 const after_op_space = blk: {
496 const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));455 const same_line = tree.tokensOnSameLine(infix_op_node.op_token, tree.nextToken(infix_op_node.op_token));
497 break :blk if (loc.line == 0) op_space else Space.Newline;456 break :blk if (same_line) op_space else Space.Newline;
498 };457 };
499458
500 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);459 try renderToken(tree, stream, infix_op_node.op_token, after_op_space);
501 if (after_op_space == Space.Newline and
502 tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine)
503 {
504 try stream.writeByteNTimes(' ', indent + indent_delta);
505 start_col.* = indent + indent_delta;
506 }
507460
508 if (infix_op_node.payload) |payload| {461 if (infix_op_node.payload) |payload| {
509 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);462 try renderExpression(allocator, stream, tree, payload, Space.Space);
510 }463 }
511464
512 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);465 stream.pushIndentOneShot();
466 return renderExpression(allocator, stream, tree, infix_op_node.rhs, space);
513 },467 },
514468
515 .Add,469 .Add,
...@@ -561,22 +515,16 @@ fn renderExpression(...@@ -561,22 +515,16 @@ fn renderExpression(
561 .Period, .ErrorUnion, .Range => Space.None,515 .Period, .ErrorUnion, .Range => Space.None,
562 else => Space.Space,516 else => Space.Space,
563 };517 };
564 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);518 try renderExpression(allocator, stream, tree, infix_op_node.lhs, op_space);
565519
566 const after_op_space = blk: {520 const after_op_space = blk: {
567 const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));521 const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
568 break :blk if (loc.line == 0) op_space else Space.Newline;522 break :blk if (loc.line == 0) op_space else Space.Newline;
569 };523 };
570524
571 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);525 try renderToken(tree, stream, infix_op_node.op_token, after_op_space);
572 if (after_op_space == Space.Newline and526 stream.pushIndentOneShot();
573 tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine)527 return renderExpression(allocator, stream, tree, infix_op_node.rhs, space);
574 {
575 try stream.writeByteNTimes(' ', indent + indent_delta);
576 start_col.* = indent + indent_delta;
577 }
578
579 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
580 },528 },
581529
582 .BitNot,530 .BitNot,
...@@ -587,8 +535,8 @@ fn renderExpression(...@@ -587,8 +535,8 @@ fn renderExpression(
587 .AddressOf,535 .AddressOf,
588 => {536 => {
589 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);537 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
590 try renderToken(tree, stream, casted_node.op_token, indent, start_col, Space.None);538 try renderToken(tree, stream, casted_node.op_token, Space.None);
591 return renderExpression(allocator, stream, tree, indent, start_col, casted_node.rhs, space);539 return renderExpression(allocator, stream, tree, casted_node.rhs, space);
592 },540 },
593541
594 .Try,542 .Try,
...@@ -596,8 +544,8 @@ fn renderExpression(...@@ -596,8 +544,8 @@ fn renderExpression(
596 .Await,544 .Await,
597 => {545 => {
598 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);546 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
599 try renderToken(tree, stream, casted_node.op_token, indent, start_col, Space.Space);547 try renderToken(tree, stream, casted_node.op_token, Space.Space);
600 return renderExpression(allocator, stream, tree, indent, start_col, casted_node.rhs, space);548 return renderExpression(allocator, stream, tree, casted_node.rhs, space);
601 },549 },
602550
603 .ArrayType => {551 .ArrayType => {
...@@ -606,8 +554,6 @@ fn renderExpression(...@@ -606,8 +554,6 @@ fn renderExpression(
606 allocator,554 allocator,
607 stream,555 stream,
608 tree,556 tree,
609 indent,
610 start_col,
611 array_type.op_token,557 array_type.op_token,
612 array_type.rhs,558 array_type.rhs,
613 array_type.len_expr,559 array_type.len_expr,
...@@ -621,8 +567,6 @@ fn renderExpression(...@@ -621,8 +567,6 @@ fn renderExpression(
621 allocator,567 allocator,
622 stream,568 stream,
623 tree,569 tree,
624 indent,
625 start_col,
626 array_type.op_token,570 array_type.op_token,
627 array_type.rhs,571 array_type.rhs,
628 array_type.len_expr,572 array_type.len_expr,
...@@ -635,111 +579,111 @@ fn renderExpression(...@@ -635,111 +579,111 @@ fn renderExpression(
635 const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);579 const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
636 const op_tok_id = tree.token_ids[ptr_type.op_token];580 const op_tok_id = tree.token_ids[ptr_type.op_token];
637 switch (op_tok_id) {581 switch (op_tok_id) {
638 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),582 .Asterisk, .AsteriskAsterisk => try stream.writer().writeByte('*'),
639 .LBracket => if (tree.token_ids[ptr_type.op_token + 2] == .Identifier)583 .LBracket => if (tree.token_ids[ptr_type.op_token + 2] == .Identifier)
640 try stream.writeAll("[*c")584 try stream.writer().writeAll("[*c")
641 else585 else
642 try stream.writeAll("[*"),586 try stream.writer().writeAll("[*"),
643 else => unreachable,587 else => unreachable,
644 }588 }
645 if (ptr_type.ptr_info.sentinel) |sentinel| {589 if (ptr_type.ptr_info.sentinel) |sentinel| {
646 const colon_token = tree.prevToken(sentinel.firstToken());590 const colon_token = tree.prevToken(sentinel.firstToken());
647 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :591 try renderToken(tree, stream, colon_token, Space.None); // :
648 const sentinel_space = switch (op_tok_id) {592 const sentinel_space = switch (op_tok_id) {
649 .LBracket => Space.None,593 .LBracket => Space.None,
650 else => Space.Space,594 else => Space.Space,
651 };595 };
652 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, sentinel_space);596 try renderExpression(allocator, stream, tree, sentinel, sentinel_space);
653 }597 }
654 switch (op_tok_id) {598 switch (op_tok_id) {
655 .Asterisk, .AsteriskAsterisk => {},599 .Asterisk, .AsteriskAsterisk => {},
656 .LBracket => try stream.writeByte(']'),600 .LBracket => try stream.writer().writeByte(']'),
657 else => unreachable,601 else => unreachable,
658 }602 }
659 if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {603 if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {
660 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero604 try renderToken(tree, stream, allowzero_token, Space.Space); // allowzero
661 }605 }
662 if (ptr_type.ptr_info.align_info) |align_info| {606 if (ptr_type.ptr_info.align_info) |align_info| {
663 const lparen_token = tree.prevToken(align_info.node.firstToken());607 const lparen_token = tree.prevToken(align_info.node.firstToken());
664 const align_token = tree.prevToken(lparen_token);608 const align_token = tree.prevToken(lparen_token);
665609
666 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align610 try renderToken(tree, stream, align_token, Space.None); // align
667 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (611 try renderToken(tree, stream, lparen_token, Space.None); // (
668612
669 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);613 try renderExpression(allocator, stream, tree, align_info.node, Space.None);
670614
671 if (align_info.bit_range) |bit_range| {615 if (align_info.bit_range) |bit_range| {
672 const colon1 = tree.prevToken(bit_range.start.firstToken());616 const colon1 = tree.prevToken(bit_range.start.firstToken());
673 const colon2 = tree.prevToken(bit_range.end.firstToken());617 const colon2 = tree.prevToken(bit_range.end.firstToken());
674618
675 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :619 try renderToken(tree, stream, colon1, Space.None); // :
676 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);620 try renderExpression(allocator, stream, tree, bit_range.start, Space.None);
677 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :621 try renderToken(tree, stream, colon2, Space.None); // :
678 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);622 try renderExpression(allocator, stream, tree, bit_range.end, Space.None);
679623
680 const rparen_token = tree.nextToken(bit_range.end.lastToken());624 const rparen_token = tree.nextToken(bit_range.end.lastToken());
681 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )625 try renderToken(tree, stream, rparen_token, Space.Space); // )
682 } else {626 } else {
683 const rparen_token = tree.nextToken(align_info.node.lastToken());627 const rparen_token = tree.nextToken(align_info.node.lastToken());
684 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )628 try renderToken(tree, stream, rparen_token, Space.Space); // )
685 }629 }
686 }630 }
687 if (ptr_type.ptr_info.const_token) |const_token| {631 if (ptr_type.ptr_info.const_token) |const_token| {
688 try renderToken(tree, stream, const_token, indent, start_col, Space.Space); // const632 try renderToken(tree, stream, const_token, Space.Space); // const
689 }633 }
690 if (ptr_type.ptr_info.volatile_token) |volatile_token| {634 if (ptr_type.ptr_info.volatile_token) |volatile_token| {
691 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile635 try renderToken(tree, stream, volatile_token, Space.Space); // volatile
692 }636 }
693 return renderExpression(allocator, stream, tree, indent, start_col, ptr_type.rhs, space);637 return renderExpression(allocator, stream, tree, ptr_type.rhs, space);
694 },638 },
695639
696 .SliceType => {640 .SliceType => {
697 const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);641 const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
698 try renderToken(tree, stream, slice_type.op_token, indent, start_col, Space.None); // [642 try renderToken(tree, stream, slice_type.op_token, Space.None); // [
699 if (slice_type.ptr_info.sentinel) |sentinel| {643 if (slice_type.ptr_info.sentinel) |sentinel| {
700 const colon_token = tree.prevToken(sentinel.firstToken());644 const colon_token = tree.prevToken(sentinel.firstToken());
701 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :645 try renderToken(tree, stream, colon_token, Space.None); // :
702 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);646 try renderExpression(allocator, stream, tree, sentinel, Space.None);
703 try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), indent, start_col, Space.None); // ]647 try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), Space.None); // ]
704 } else {648 } else {
705 try renderToken(tree, stream, tree.nextToken(slice_type.op_token), indent, start_col, Space.None); // ]649 try renderToken(tree, stream, tree.nextToken(slice_type.op_token), Space.None); // ]
706 }650 }
707651
708 if (slice_type.ptr_info.allowzero_token) |allowzero_token| {652 if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
709 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero653 try renderToken(tree, stream, allowzero_token, Space.Space); // allowzero
710 }654 }
711 if (slice_type.ptr_info.align_info) |align_info| {655 if (slice_type.ptr_info.align_info) |align_info| {
712 const lparen_token = tree.prevToken(align_info.node.firstToken());656 const lparen_token = tree.prevToken(align_info.node.firstToken());
713 const align_token = tree.prevToken(lparen_token);657 const align_token = tree.prevToken(lparen_token);
714658
715 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align659 try renderToken(tree, stream, align_token, Space.None); // align
716 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (660 try renderToken(tree, stream, lparen_token, Space.None); // (
717661
718 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);662 try renderExpression(allocator, stream, tree, align_info.node, Space.None);
719663
720 if (align_info.bit_range) |bit_range| {664 if (align_info.bit_range) |bit_range| {
721 const colon1 = tree.prevToken(bit_range.start.firstToken());665 const colon1 = tree.prevToken(bit_range.start.firstToken());
722 const colon2 = tree.prevToken(bit_range.end.firstToken());666 const colon2 = tree.prevToken(bit_range.end.firstToken());
723667
724 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :668 try renderToken(tree, stream, colon1, Space.None); // :
725 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);669 try renderExpression(allocator, stream, tree, bit_range.start, Space.None);
726 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :670 try renderToken(tree, stream, colon2, Space.None); // :
727 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);671 try renderExpression(allocator, stream, tree, bit_range.end, Space.None);
728672
729 const rparen_token = tree.nextToken(bit_range.end.lastToken());673 const rparen_token = tree.nextToken(bit_range.end.lastToken());
730 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )674 try renderToken(tree, stream, rparen_token, Space.Space); // )
731 } else {675 } else {
732 const rparen_token = tree.nextToken(align_info.node.lastToken());676 const rparen_token = tree.nextToken(align_info.node.lastToken());
733 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )677 try renderToken(tree, stream, rparen_token, Space.Space); // )
734 }678 }
735 }679 }
736 if (slice_type.ptr_info.const_token) |const_token| {680 if (slice_type.ptr_info.const_token) |const_token| {
737 try renderToken(tree, stream, const_token, indent, start_col, Space.Space);681 try renderToken(tree, stream, const_token, Space.Space);
738 }682 }
739 if (slice_type.ptr_info.volatile_token) |volatile_token| {683 if (slice_type.ptr_info.volatile_token) |volatile_token| {
740 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space);684 try renderToken(tree, stream, volatile_token, Space.Space);
741 }685 }
742 return renderExpression(allocator, stream, tree, indent, start_col, slice_type.rhs, space);686 return renderExpression(allocator, stream, tree, slice_type.rhs, space);
743 },687 },
744688
745 .ArrayInitializer, .ArrayInitializerDot => {689 .ArrayInitializer, .ArrayInitializerDot => {
...@@ -768,27 +712,33 @@ fn renderExpression(...@@ -768,27 +712,33 @@ fn renderExpression(
768712
769 if (exprs.len == 0) {713 if (exprs.len == 0) {
770 switch (lhs) {714 switch (lhs) {
771 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),715 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
772 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),716 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
717 }
718
719 {
720 stream.pushIndent();
721 defer stream.popIndent();
722 try renderToken(tree, stream, lbrace, Space.None);
773 }723 }
774 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
775 return renderToken(tree, stream, rtoken, indent, start_col, space);
776 }
777724
778 if (exprs.len == 1 and tree.token_ids[exprs[0].lastToken() + 1] == .RBrace) {725 return renderToken(tree, stream, rtoken, space);
726 }
727 if (exprs.len == 1 and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
779 const expr = exprs[0];728 const expr = exprs[0];
729
780 switch (lhs) {730 switch (lhs) {
781 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),731 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
782 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),732 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
783 }733 }
784 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);734 try renderToken(tree, stream, lbrace, Space.None);
785 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);735 try renderExpression(allocator, stream, tree, expr, Space.None);
786 return renderToken(tree, stream, rtoken, indent, start_col, space);736 return renderToken(tree, stream, rtoken, space);
787 }737 }
788738
789 switch (lhs) {739 switch (lhs) {
790 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),740 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
791 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),741 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
792 }742 }
793743
794 // scan to find row size744 // scan to find row size
...@@ -832,77 +782,68 @@ fn renderExpression(...@@ -832,77 +782,68 @@ fn renderExpression(
832782
833 // Null stream for counting the printed length of each expression783 // Null stream for counting the printed length of each expression
834 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);784 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
785 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &counting_stream);
835786
836 for (exprs) |expr, i| {787 for (exprs) |expr, i| {
837 counting_stream.bytes_written = 0;788 counting_stream.bytes_written = 0;
838 var dummy_col: usize = 0;789 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
839 try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr, Space.None);
840 const width = @intCast(usize, counting_stream.bytes_written);790 const width = @intCast(usize, counting_stream.bytes_written);
841 const col = i % row_size;791 const col = i % row_size;
842 column_widths[col] = std.math.max(column_widths[col], width);792 column_widths[col] = std.math.max(column_widths[col], width);
843 expr_widths[i] = width;793 expr_widths[i] = width;
844 }794 }
845795
846 var new_indent = indent + indent_delta;796 {
797 stream.pushIndentNextLine();
798 defer stream.popIndent();
799 try renderToken(tree, stream, lbrace, Space.Newline);
847800
848 if (tree.token_ids[tree.nextToken(lbrace)] != .MultilineStringLiteralLine) {801 var col: usize = 1;
849 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);802 for (exprs) |expr, i| {
850 try stream.writeByteNTimes(' ', new_indent);803 if (i + 1 < exprs.len) {
851 } else {804 const next_expr = exprs[i + 1];
852 new_indent -= indent_delta;805 try renderExpression(allocator, stream, tree, expr, Space.None);
853 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.None);
854 }
855806
856 var col: usize = 1;807 const comma = tree.nextToken(expr.*.lastToken());
857 for (exprs) |expr, i| {
858 if (i + 1 < exprs.len) {
859 const next_expr = exprs[i + 1];
860 try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.None);
861808
862 const comma = tree.nextToken(expr.lastToken());809 if (col != row_size) {
810 try renderToken(tree, stream, comma, Space.Space); // ,
863811
864 if (col != row_size) {812 const padding = column_widths[i % row_size] - expr_widths[i];
865 try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // ,813 try stream.writer().writeByteNTimes(' ', padding);
866814
867 const padding = column_widths[i % row_size] - expr_widths[i];815 col += 1;
868 try stream.writeByteNTimes(' ', padding);816 continue;
817 }
818 col = 1;
869819
870 col += 1;820 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
871 continue;821 try renderToken(tree, stream, comma, Space.Newline); // ,
872 }822 } else {
873 col = 1;823 try renderToken(tree, stream, comma, Space.None); // ,
824 }
874825
875 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {826 try renderExtraNewline(tree, stream, next_expr);
876 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
877 } else {827 } else {
878 try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // ,828 try renderExpression(allocator, stream, tree, expr, Space.Comma); // ,
879 }
880
881 try renderExtraNewline(tree, stream, start_col, next_expr);
882 if (next_expr.tag != .MultilineStringLiteral) {
883 try stream.writeByteNTimes(' ', new_indent);
884 }829 }
885 } else {
886 try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // ,
887 }830 }
888 }831 }
889 if (exprs[exprs.len - 1].tag != .MultilineStringLiteral) {832 return renderToken(tree, stream, rtoken, space);
890 try stream.writeByteNTimes(' ', indent);
891 }
892 return renderToken(tree, stream, rtoken, indent, start_col, space);
893 } else {833 } else {
894 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);834 try renderToken(tree, stream, lbrace, Space.Space);
895 for (exprs) |expr, i| {835 for (exprs) |expr, i| {
896 if (i + 1 < exprs.len) {836 if (i + 1 < exprs.len) {
897 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);837 const next_expr = exprs[i + 1];
898 const comma = tree.nextToken(expr.lastToken());838 try renderExpression(allocator, stream, tree, expr, Space.None);
899 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,839 const comma = tree.nextToken(expr.*.lastToken());
840 try renderToken(tree, stream, comma, Space.Space); // ,
900 } else {841 } else {
901 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.Space);842 try renderExpression(allocator, stream, tree, expr, Space.Space);
902 }843 }
903 }844 }
904845
905 return renderToken(tree, stream, rtoken, indent, start_col, space);846 return renderToken(tree, stream, rtoken, space);
906 }847 }
907 },848 },
908849
...@@ -932,11 +873,17 @@ fn renderExpression(...@@ -932,11 +873,17 @@ fn renderExpression(
932873
933 if (field_inits.len == 0) {874 if (field_inits.len == 0) {
934 switch (lhs) {875 switch (lhs) {
935 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),876 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
936 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),877 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
937 }878 }
938 try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None);879
939 return renderToken(tree, stream, rtoken, indent, start_col, space);880 {
881 stream.pushIndentNextLine();
882 defer stream.popIndent();
883 try renderToken(tree, stream, lbrace, Space.None);
884 }
885
886 return renderToken(tree, stream, rtoken, space);
940 }887 }
941888
942 const src_has_trailing_comma = blk: {889 const src_has_trailing_comma = blk: {
...@@ -952,9 +899,10 @@ fn renderExpression(...@@ -952,9 +899,10 @@ fn renderExpression(
952 const expr_outputs_one_line = blk: {899 const expr_outputs_one_line = blk: {
953 // render field expressions until a LF is found900 // render field expressions until a LF is found
954 for (field_inits) |field_init| {901 for (field_inits) |field_init| {
955 var find_stream = FindByteOutStream.init('\n');902 var find_stream = std.io.findByteOutStream('\n', &std.io.null_out_stream);
956 var dummy_col: usize = 0;903 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &find_stream);
957 try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init, Space.None);904
905 try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None);
958 if (find_stream.byte_found) break :blk false;906 if (find_stream.byte_found) break :blk false;
959 }907 }
960 break :blk true;908 break :blk true;
...@@ -967,7 +915,6 @@ fn renderExpression(...@@ -967,7 +915,6 @@ fn renderExpression(
967 .StructInitializer,915 .StructInitializer,
968 .StructInitializerDot,916 .StructInitializerDot,
969 => break :blk,917 => break :blk,
970
971 else => {},918 else => {},
972 }919 }
973920
...@@ -977,76 +924,78 @@ fn renderExpression(...@@ -977,76 +924,78 @@ fn renderExpression(
977 }924 }
978925
979 switch (lhs) {926 switch (lhs) {
980 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),927 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
981 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),928 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
982 }929 }
983 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);930 try renderToken(tree, stream, lbrace, Space.Space);
984 try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space);931 try renderExpression(allocator, stream, tree, &field_init.base, Space.Space);
985 return renderToken(tree, stream, rtoken, indent, start_col, space);932 return renderToken(tree, stream, rtoken, space);
986 }933 }
987934
988 if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {935 if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
989 // render all on one line, no trailing comma936 // render all on one line, no trailing comma
990 switch (lhs) {937 switch (lhs) {
991 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),938 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
992 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),939 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
993 }940 }
994 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);941 try renderToken(tree, stream, lbrace, Space.Space);
995942
996 for (field_inits) |field_init, i| {943 for (field_inits) |field_init, i| {
997 if (i + 1 < field_inits.len) {944 if (i + 1 < field_inits.len) {
998 try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.None);945 try renderExpression(allocator, stream, tree, field_init, Space.None);
999946
1000 const comma = tree.nextToken(field_init.lastToken());947 const comma = tree.nextToken(field_init.lastToken());
1001 try renderToken(tree, stream, comma, indent, start_col, Space.Space);948 try renderToken(tree, stream, comma, Space.Space);
1002 } else {949 } else {
1003 try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.Space);950 try renderExpression(allocator, stream, tree, field_init, Space.Space);
1004 }951 }
1005 }952 }
1006953
1007 return renderToken(tree, stream, rtoken, indent, start_col, space);954 return renderToken(tree, stream, rtoken, space);
1008 }955 }
1009956
1010 const new_indent = indent + indent_delta;957 {
958 switch (lhs) {
959 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
960 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
961 }
1011962
1012 switch (lhs) {963 stream.pushIndentNextLine();
1013 .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None),964 defer stream.popIndent();
1014 .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None),
1015 }
1016 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
1017965
1018 for (field_inits) |field_init, i| {966 try renderToken(tree, stream, lbrace, Space.Newline);
1019 try stream.writeByteNTimes(' ', new_indent);
1020967
1021 if (i + 1 < field_inits.len) {968 for (field_inits) |field_init, i| {
1022 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.None);969 if (i + 1 < field_inits.len) {
970 const next_field_init = field_inits[i + 1];
971 try renderExpression(allocator, stream, tree, field_init, Space.None);
1023972
1024 const comma = tree.nextToken(field_init.lastToken());973 const comma = tree.nextToken(field_init.lastToken());
1025 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline);974 try renderToken(tree, stream, comma, Space.Newline);
1026975
1027 try renderExtraNewline(tree, stream, start_col, field_inits[i + 1]);976 try renderExtraNewline(tree, stream, next_field_init);
1028 } else {977 } else {
1029 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.Comma);978 try renderExpression(allocator, stream, tree, field_init, Space.Comma);
979 }
1030 }980 }
1031 }981 }
1032982
1033 try stream.writeByteNTimes(' ', indent);983 return renderToken(tree, stream, rtoken, space);
1034 return renderToken(tree, stream, rtoken, indent, start_col, space);
1035 },984 },
1036985
1037 .Call => {986 .Call => {
1038 const call = @fieldParentPtr(ast.Node.Call, "base", base);987 const call = @fieldParentPtr(ast.Node.Call, "base", base);
1039 if (call.async_token) |async_token| {988 if (call.async_token) |async_token| {
1040 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);989 try renderToken(tree, stream, async_token, Space.Space);
1041 }990 }
1042991
1043 try renderExpression(allocator, stream, tree, indent, start_col, call.lhs, Space.None);992 try renderExpression(allocator, stream, tree, call.lhs, Space.None);
1044993
1045 const lparen = tree.nextToken(call.lhs.lastToken());994 const lparen = tree.nextToken(call.lhs.lastToken());
1046995
1047 if (call.params_len == 0) {996 if (call.params_len == 0) {
1048 try renderToken(tree, stream, lparen, indent, start_col, Space.None);997 try renderToken(tree, stream, lparen, Space.None);
1049 return renderToken(tree, stream, call.rtoken, indent, start_col, space);998 return renderToken(tree, stream, call.rtoken, space);
1050 }999 }
10511000
1052 const src_has_trailing_comma = blk: {1001 const src_has_trailing_comma = blk: {
...@@ -1055,43 +1004,41 @@ fn renderExpression(...@@ -1055,43 +1004,41 @@ fn renderExpression(
1055 };1004 };
10561005
1057 if (src_has_trailing_comma) {1006 if (src_has_trailing_comma) {
1058 const new_indent = indent + indent_delta;1007 try renderToken(tree, stream, lparen, Space.Newline);
1059 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
10601008
1061 const params = call.params();1009 const params = call.params();
1062 for (params) |param_node, i| {1010 for (params) |param_node, i| {
1063 const param_node_new_indent = if (param_node.tag == .MultilineStringLiteral) blk: {1011 stream.pushIndent();
1064 break :blk indent;1012 defer stream.popIndent();
1065 } else blk: {
1066 try stream.writeByteNTimes(' ', new_indent);
1067 break :blk new_indent;
1068 };
10691013
1070 if (i + 1 < params.len) {1014 if (i + 1 < params.len) {
1071 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);1015 const next_node = params[i + 1];
1016 try renderExpression(allocator, stream, tree, param_node, Space.None);
1072 const comma = tree.nextToken(param_node.lastToken());1017 const comma = tree.nextToken(param_node.lastToken());
1073 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,1018 try renderToken(tree, stream, comma, Space.Newline); // ,
1074 try renderExtraNewline(tree, stream, start_col, params[i + 1]);1019 try renderExtraNewline(tree, stream, next_node);
1075 } else {1020 } else {
1076 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);1021 try renderExpression(allocator, stream, tree, param_node, Space.Comma);
1077 try stream.writeByteNTimes(' ', indent);
1078 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
1079 }1022 }
1080 }1023 }
1024 return renderToken(tree, stream, call.rtoken, space);
1081 }1025 }
10821026
1083 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1027 try renderToken(tree, stream, lparen, Space.None); // (
10841028
1085 const params = call.params();1029 const params = call.params();
1086 for (params) |param_node, i| {1030 for (params) |param_node, i| {
1087 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);1031 if (param_node.*.tag == .MultilineStringLiteral) stream.pushIndentOneShot();
1032
1033 try renderExpression(allocator, stream, tree, param_node, Space.None);
10881034
1089 if (i + 1 < params.len) {1035 if (i + 1 < params.len) {
1036 const next_param = params[i + 1];
1090 const comma = tree.nextToken(param_node.lastToken());1037 const comma = tree.nextToken(param_node.lastToken());
1091 try renderToken(tree, stream, comma, indent, start_col, Space.Space);1038 try renderToken(tree, stream, comma, Space.Space);
1092 }1039 }
1093 }1040 }
1094 return renderToken(tree, stream, call.rtoken, indent, start_col, space);1041 return renderToken(tree, stream, call.rtoken, space);
1095 },1042 },
10961043
1097 .ArrayAccess => {1044 .ArrayAccess => {
...@@ -1100,26 +1047,25 @@ fn renderExpression(...@@ -1100,26 +1047,25 @@ fn renderExpression(
1100 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());1047 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
1101 const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());1048 const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());
11021049
1103 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);1050 try renderExpression(allocator, stream, tree, suffix_op.lhs, Space.None);
1104 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [1051 try renderToken(tree, stream, lbracket, Space.None); // [
11051052
1106 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;1053 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
1107 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;1054 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
1108 const new_indent = if (ends_with_comment) indent + indent_delta else indent;1055 {
1109 const new_space = if (ends_with_comment) Space.Newline else Space.None;1056 const new_space = if (ends_with_comment) Space.Newline else Space.None;
1110 try renderExpression(allocator, stream, tree, new_indent, start_col, suffix_op.index_expr, new_space);1057
1111 if (starts_with_comment) {1058 stream.pushIndent();
1112 try stream.writeByte('\n');1059 defer stream.popIndent();
1113 }1060 try renderExpression(allocator, stream, tree, suffix_op.index_expr, new_space);
1114 if (ends_with_comment or starts_with_comment) {
1115 try stream.writeByteNTimes(' ', indent);
1116 }1061 }
1117 return renderToken(tree, stream, rbracket, indent, start_col, space); // ]1062 if (starts_with_comment) try stream.maybeInsertNewline();
1063 return renderToken(tree, stream, rbracket, space); // ]
1118 },1064 },
1065
1119 .Slice => {1066 .Slice => {
1120 const suffix_op = base.castTag(.Slice).?;1067 const suffix_op = base.castTag(.Slice).?;
11211068 try renderExpression(allocator, stream, tree, suffix_op.lhs, Space.None);
1122 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
11231069
1124 const lbracket = tree.prevToken(suffix_op.start.firstToken());1070 const lbracket = tree.prevToken(suffix_op.start.firstToken());
1125 const dotdot = tree.nextToken(suffix_op.start.lastToken());1071 const dotdot = tree.nextToken(suffix_op.start.lastToken());
...@@ -1129,32 +1075,33 @@ fn renderExpression(...@@ -1129,32 +1075,33 @@ fn renderExpression(
1129 const after_start_space = if (after_start_space_bool) Space.Space else Space.None;1075 const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
1130 const after_op_space = if (suffix_op.end != null) after_start_space else Space.None;1076 const after_op_space = if (suffix_op.end != null) after_start_space else Space.None;
11311077
1132 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [1078 try renderToken(tree, stream, lbracket, Space.None); // [
1133 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.start, after_start_space);1079 try renderExpression(allocator, stream, tree, suffix_op.start, after_start_space);
1134 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..1080 try renderToken(tree, stream, dotdot, after_op_space); // ..
1135 if (suffix_op.end) |end| {1081 if (suffix_op.end) |end| {
1136 const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;1082 const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;
1137 try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);1083 try renderExpression(allocator, stream, tree, end, after_end_space);
1138 }1084 }
1139 if (suffix_op.sentinel) |sentinel| {1085 if (suffix_op.sentinel) |sentinel| {
1140 const colon = tree.prevToken(sentinel.firstToken());1086 const colon = tree.prevToken(sentinel.firstToken());
1141 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :1087 try renderToken(tree, stream, colon, Space.None); // :
1142 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);1088 try renderExpression(allocator, stream, tree, sentinel, Space.None);
1143 }1089 }
1144 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]1090 return renderToken(tree, stream, suffix_op.rtoken, space); // ]
1145 },1091 },
1092
1146 .Deref => {1093 .Deref => {
1147 const suffix_op = base.castTag(.Deref).?;1094 const suffix_op = base.castTag(.Deref).?;
11481095
1149 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);1096 try renderExpression(allocator, stream, tree, suffix_op.lhs, Space.None);
1150 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*1097 return renderToken(tree, stream, suffix_op.rtoken, space); // .*
1151 },1098 },
1152 .UnwrapOptional => {1099 .UnwrapOptional => {
1153 const suffix_op = base.castTag(.UnwrapOptional).?;1100 const suffix_op = base.castTag(.UnwrapOptional).?;
11541101
1155 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);1102 try renderExpression(allocator, stream, tree, suffix_op.lhs, Space.None);
1156 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .1103 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), Space.None); // .
1157 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?1104 return renderToken(tree, stream, suffix_op.rtoken, space); // ?
1158 },1105 },
11591106
1160 .Break => {1107 .Break => {
...@@ -1163,145 +1110,152 @@ fn renderExpression(...@@ -1163,145 +1110,152 @@ fn renderExpression(
1163 const maybe_label = flow_expr.getLabel();1110 const maybe_label = flow_expr.getLabel();
11641111
1165 if (maybe_label == null and maybe_rhs == null) {1112 if (maybe_label == null and maybe_rhs == null) {
1166 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // break1113 return renderToken(tree, stream, flow_expr.ltoken, space); // break
1167 }1114 }
11681115
1169 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // break1116 try renderToken(tree, stream, flow_expr.ltoken, Space.Space); // break
1170 if (maybe_label) |label| {1117 if (maybe_label) |label| {
1171 const colon = tree.nextToken(flow_expr.ltoken);1118 const colon = tree.nextToken(flow_expr.ltoken);
1172 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :1119 try renderToken(tree, stream, colon, Space.None); // :
11731120
1174 if (maybe_rhs == null) {1121 if (maybe_rhs == null) {
1175 return renderToken(tree, stream, label, indent, start_col, space); // label1122 return renderToken(tree, stream, label, space); // label
1176 }1123 }
1177 try renderToken(tree, stream, label, indent, start_col, Space.Space); // label1124 try renderToken(tree, stream, label, Space.Space); // label
1178 }1125 }
1179 return renderExpression(allocator, stream, tree, indent, start_col, maybe_rhs.?, space);1126 return renderExpression(allocator, stream, tree, maybe_rhs.?, space);
1180 },1127 },
11811128
1182 .Continue => {1129 .Continue => {
1183 const flow_expr = base.castTag(.Continue).?;1130 const flow_expr = base.castTag(.Continue).?;
1184 if (flow_expr.getLabel()) |label| {1131 if (flow_expr.getLabel()) |label| {
1185 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // continue1132 try renderToken(tree, stream, flow_expr.ltoken, Space.Space); // continue
1186 const colon = tree.nextToken(flow_expr.ltoken);1133 const colon = tree.nextToken(flow_expr.ltoken);
1187 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :1134 try renderToken(tree, stream, colon, Space.None); // :
1188 return renderToken(tree, stream, label, indent, start_col, space); // label1135 return renderToken(tree, stream, label, space); // label
1189 } else {1136 } else {
1190 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // continue1137 return renderToken(tree, stream, flow_expr.ltoken, space); // continue
1191 }1138 }
1192 },1139 },
11931140
1194 .Return => {1141 .Return => {
1195 const flow_expr = base.castTag(.Return).?;1142 const flow_expr = base.castTag(.Return).?;
1196 if (flow_expr.getRHS()) |rhs| {1143 if (flow_expr.getRHS()) |rhs| {
1197 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space);1144 try renderToken(tree, stream, flow_expr.ltoken, Space.Space);
1198 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);1145 return renderExpression(allocator, stream, tree, rhs, space);
1199 } else {1146 } else {
1200 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space);1147 return renderToken(tree, stream, flow_expr.ltoken, space);
1201 }1148 }
1202 },1149 },
12031150
1204 .Payload => {1151 .Payload => {
1205 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);1152 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
12061153
1207 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);1154 try renderToken(tree, stream, payload.lpipe, Space.None);
1208 try renderExpression(allocator, stream, tree, indent, start_col, payload.error_symbol, Space.None);1155 try renderExpression(allocator, stream, tree, payload.error_symbol, Space.None);
1209 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);1156 return renderToken(tree, stream, payload.rpipe, space);
1210 },1157 },
12111158
1212 .PointerPayload => {1159 .PointerPayload => {
1213 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);1160 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
12141161
1215 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);1162 try renderToken(tree, stream, payload.lpipe, Space.None);
1216 if (payload.ptr_token) |ptr_token| {1163 if (payload.ptr_token) |ptr_token| {
1217 try renderToken(tree, stream, ptr_token, indent, start_col, Space.None);1164 try renderToken(tree, stream, ptr_token, Space.None);
1218 }1165 }
1219 try renderExpression(allocator, stream, tree, indent, start_col, payload.value_symbol, Space.None);1166 try renderExpression(allocator, stream, tree, payload.value_symbol, Space.None);
1220 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);1167 return renderToken(tree, stream, payload.rpipe, space);
1221 },1168 },
12221169
1223 .PointerIndexPayload => {1170 .PointerIndexPayload => {
1224 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);1171 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
12251172
1226 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);1173 try renderToken(tree, stream, payload.lpipe, Space.None);
1227 if (payload.ptr_token) |ptr_token| {1174 if (payload.ptr_token) |ptr_token| {
1228 try renderToken(tree, stream, ptr_token, indent, start_col, Space.None);1175 try renderToken(tree, stream, ptr_token, Space.None);
1229 }1176 }
1230 try renderExpression(allocator, stream, tree, indent, start_col, payload.value_symbol, Space.None);1177 try renderExpression(allocator, stream, tree, payload.value_symbol, Space.None);
12311178
1232 if (payload.index_symbol) |index_symbol| {1179 if (payload.index_symbol) |index_symbol| {
1233 const comma = tree.nextToken(payload.value_symbol.lastToken());1180 const comma = tree.nextToken(payload.value_symbol.lastToken());
12341181
1235 try renderToken(tree, stream, comma, indent, start_col, Space.Space);1182 try renderToken(tree, stream, comma, Space.Space);
1236 try renderExpression(allocator, stream, tree, indent, start_col, index_symbol, Space.None);1183 try renderExpression(allocator, stream, tree, index_symbol, Space.None);
1237 }1184 }
12381185
1239 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);1186 return renderToken(tree, stream, payload.rpipe, space);
1240 },1187 },
12411188
1242 .GroupedExpression => {1189 .GroupedExpression => {
1243 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);1190 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
12441191
1245 try renderToken(tree, stream, grouped_expr.lparen, indent, start_col, Space.None);1192 try renderToken(tree, stream, grouped_expr.lparen, Space.None);
1246 try renderExpression(allocator, stream, tree, indent, start_col, grouped_expr.expr, Space.None);1193 {
1247 return renderToken(tree, stream, grouped_expr.rparen, indent, start_col, space);1194 stream.pushIndentOneShot();
1195 try renderExpression(allocator, stream, tree, grouped_expr.expr, Space.None);
1196 }
1197 return renderToken(tree, stream, grouped_expr.rparen, space);
1248 },1198 },
12491199
1250 .FieldInitializer => {1200 .FieldInitializer => {
1251 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);1201 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
12521202
1253 try renderToken(tree, stream, field_init.period_token, indent, start_col, Space.None); // .1203 try renderToken(tree, stream, field_init.period_token, Space.None); // .
1254 try renderToken(tree, stream, field_init.name_token, indent, start_col, Space.Space); // name1204 try renderToken(tree, stream, field_init.name_token, Space.Space); // name
1255 try renderToken(tree, stream, tree.nextToken(field_init.name_token), indent, start_col, Space.Space); // =1205 try renderToken(tree, stream, tree.nextToken(field_init.name_token), Space.Space); // =
1256 return renderExpression(allocator, stream, tree, indent, start_col, field_init.expr, space);1206 return renderExpression(allocator, stream, tree, field_init.expr, space);
1257 },1207 },
12581208
1259 .ContainerDecl => {1209 .ContainerDecl => {
1260 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);1210 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
12611211
1262 if (container_decl.layout_token) |layout_token| {1212 if (container_decl.layout_token) |layout_token| {
1263 try renderToken(tree, stream, layout_token, indent, start_col, Space.Space);1213 try renderToken(tree, stream, layout_token, Space.Space);
1264 }1214 }
12651215
1266 switch (container_decl.init_arg_expr) {1216 switch (container_decl.init_arg_expr) {
1267 .None => {1217 .None => {
1268 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.Space); // union1218 try renderToken(tree, stream, container_decl.kind_token, Space.Space); // union
1269 },1219 },
1270 .Enum => |enum_tag_type| {1220 .Enum => |enum_tag_type| {
1271 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union1221 try renderToken(tree, stream, container_decl.kind_token, Space.None); // union
12721222
1273 const lparen = tree.nextToken(container_decl.kind_token);1223 const lparen = tree.nextToken(container_decl.kind_token);
1274 const enum_token = tree.nextToken(lparen);1224 const enum_token = tree.nextToken(lparen);
12751225
1276 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1226 try renderToken(tree, stream, lparen, Space.None); // (
1277 try renderToken(tree, stream, enum_token, indent, start_col, Space.None); // enum1227 try renderToken(tree, stream, enum_token, Space.None); // enum
12781228
1279 if (enum_tag_type) |expr| {1229 if (enum_tag_type) |expr| {
1280 try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.None); // (1230 try renderToken(tree, stream, tree.nextToken(enum_token), Space.None); // (
1281 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);1231 try renderExpression(allocator, stream, tree, expr, Space.None);
12821232
1283 const rparen = tree.nextToken(expr.lastToken());1233 const rparen = tree.nextToken(expr.lastToken());
1284 try renderToken(tree, stream, rparen, indent, start_col, Space.None); // )1234 try renderToken(tree, stream, rparen, Space.None); // )
1285 try renderToken(tree, stream, tree.nextToken(rparen), indent, start_col, Space.Space); // )1235 try renderToken(tree, stream, tree.nextToken(rparen), Space.Space); // )
1286 } else {1236 } else {
1287 try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.Space); // )1237 try renderToken(tree, stream, tree.nextToken(enum_token), Space.Space); // )
1288 }1238 }
1289 },1239 },
1290 .Type => |type_expr| {1240 .Type => |type_expr| {
1291 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union1241 try renderToken(tree, stream, container_decl.kind_token, Space.None); // union
12921242
1293 const lparen = tree.nextToken(container_decl.kind_token);1243 const lparen = tree.nextToken(container_decl.kind_token);
1294 const rparen = tree.nextToken(type_expr.lastToken());1244 const rparen = tree.nextToken(type_expr.lastToken());
12951245
1296 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1246 try renderToken(tree, stream, lparen, Space.None); // (
1297 try renderExpression(allocator, stream, tree, indent, start_col, type_expr, Space.None);1247 try renderExpression(allocator, stream, tree, type_expr, Space.None);
1298 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1248 try renderToken(tree, stream, rparen, Space.Space); // )
1299 },1249 },
1300 }1250 }
13011251
1302 if (container_decl.fields_and_decls_len == 0) {1252 if (container_decl.fields_and_decls_len == 0) {
1303 try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // {1253 {
1304 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }1254 stream.pushIndentNextLine();
1255 defer stream.popIndent();
1256 try renderToken(tree, stream, container_decl.lbrace_token, Space.None); // {
1257 }
1258 return renderToken(tree, stream, container_decl.rbrace_token, space); // }
1305 }1259 }
13061260
1307 const src_has_trailing_comma = blk: {1261 const src_has_trailing_comma = blk: {
...@@ -1332,43 +1286,39 @@ fn renderExpression(...@@ -1332,43 +1286,39 @@ fn renderExpression(
13321286
1333 if (src_has_trailing_comma or !src_has_only_fields) {1287 if (src_has_trailing_comma or !src_has_only_fields) {
1334 // One declaration per line1288 // One declaration per line
1335 const new_indent = indent + indent_delta;1289 stream.pushIndentNextLine();
1336 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // {1290 defer stream.popIndent();
1291 try renderToken(tree, stream, container_decl.lbrace_token, .Newline); // {
13371292
1338 for (fields_and_decls) |decl, i| {1293 for (fields_and_decls) |decl, i| {
1339 try stream.writeByteNTimes(' ', new_indent);1294 try renderContainerDecl(allocator, stream, tree, decl, .Newline);
1340 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, .Newline);
13411295
1342 if (i + 1 < fields_and_decls.len) {1296 if (i + 1 < fields_and_decls.len) {
1343 try renderExtraNewline(tree, stream, start_col, fields_and_decls[i + 1]);1297 try renderExtraNewline(tree, stream, fields_and_decls[i + 1]);
1344 }1298 }
1345 }1299 }
1346
1347 try stream.writeByteNTimes(' ', indent);
1348 } else if (src_has_newline) {1300 } else if (src_has_newline) {
1349 // All the declarations on the same line, but place the items on1301 // All the declarations on the same line, but place the items on
1350 // their own line1302 // their own line
1351 try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Newline); // {1303 try renderToken(tree, stream, container_decl.lbrace_token, .Newline); // {
13521304
1353 const new_indent = indent + indent_delta;1305 stream.pushIndent();
1354 try stream.writeByteNTimes(' ', new_indent);1306 defer stream.popIndent();
13551307
1356 for (fields_and_decls) |decl, i| {1308 for (fields_and_decls) |decl, i| {
1357 const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space;1309 const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space;
1358 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, space_after_decl);1310 try renderContainerDecl(allocator, stream, tree, decl, space_after_decl);
1359 }1311 }
1360
1361 try stream.writeByteNTimes(' ', indent);
1362 } else {1312 } else {
1363 // All the declarations on the same line1313 // All the declarations on the same line
1364 try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // {1314 try renderToken(tree, stream, container_decl.lbrace_token, .Space); // {
13651315
1366 for (fields_and_decls) |decl| {1316 for (fields_and_decls) |decl| {
1367 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Space);1317 try renderContainerDecl(allocator, stream, tree, decl, .Space);
1368 }1318 }
1369 }1319 }
13701320
1371 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }1321 return renderToken(tree, stream, container_decl.rbrace_token, space); // }
1372 },1322 },
13731323
1374 .ErrorSetDecl => {1324 .ErrorSetDecl => {
...@@ -1377,9 +1327,9 @@ fn renderExpression(...@@ -1377,9 +1327,9 @@ fn renderExpression(
1377 const lbrace = tree.nextToken(err_set_decl.error_token);1327 const lbrace = tree.nextToken(err_set_decl.error_token);
13781328
1379 if (err_set_decl.decls_len == 0) {1329 if (err_set_decl.decls_len == 0) {
1380 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);1330 try renderToken(tree, stream, err_set_decl.error_token, Space.None);
1381 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);1331 try renderToken(tree, stream, lbrace, Space.None);
1382 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);1332 return renderToken(tree, stream, err_set_decl.rbrace_token, space);
1383 }1333 }
13841334
1385 if (err_set_decl.decls_len == 1) blk: {1335 if (err_set_decl.decls_len == 1) blk: {
...@@ -1393,13 +1343,13 @@ fn renderExpression(...@@ -1393,13 +1343,13 @@ fn renderExpression(
1393 break :blk;1343 break :blk;
1394 }1344 }
13951345
1396 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error1346 try renderToken(tree, stream, err_set_decl.error_token, Space.None); // error
1397 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {1347 try renderToken(tree, stream, lbrace, Space.None); // {
1398 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);1348 try renderExpression(allocator, stream, tree, node, Space.None);
1399 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }1349 return renderToken(tree, stream, err_set_decl.rbrace_token, space); // }
1400 }1350 }
14011351
1402 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error1352 try renderToken(tree, stream, err_set_decl.error_token, Space.None); // error
14031353
1404 const src_has_trailing_comma = blk: {1354 const src_has_trailing_comma = blk: {
1405 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);1355 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
...@@ -1407,78 +1357,72 @@ fn renderExpression(...@@ -1407,78 +1357,72 @@ fn renderExpression(
1407 };1357 };
14081358
1409 if (src_has_trailing_comma) {1359 if (src_has_trailing_comma) {
1410 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {1360 {
1411 const new_indent = indent + indent_delta;1361 stream.pushIndent();
14121362 defer stream.popIndent();
1413 const decls = err_set_decl.decls();1363
1414 for (decls) |node, i| {1364 try renderToken(tree, stream, lbrace, Space.Newline); // {
1415 try stream.writeByteNTimes(' ', new_indent);1365 const decls = err_set_decl.decls();
14161366 for (decls) |node, i| {
1417 if (i + 1 < decls.len) {1367 if (i + 1 < decls.len) {
1418 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);1368 try renderExpression(allocator, stream, tree, node, Space.None);
1419 try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // ,1369 try renderToken(tree, stream, tree.nextToken(node.lastToken()), Space.Newline); // ,
14201370
1421 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);1371 try renderExtraNewline(tree, stream, decls[i + 1]);
1422 } else {1372 } else {
1423 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);1373 try renderExpression(allocator, stream, tree, node, Space.Comma);
1374 }
1424 }1375 }
1425 }1376 }
14261377
1427 try stream.writeByteNTimes(' ', indent);1378 return renderToken(tree, stream, err_set_decl.rbrace_token, space); // }
1428 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }
1429 } else {1379 } else {
1430 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {1380 try renderToken(tree, stream, lbrace, Space.Space); // {
14311381
1432 const decls = err_set_decl.decls();1382 const decls = err_set_decl.decls();
1433 for (decls) |node, i| {1383 for (decls) |node, i| {
1434 if (i + 1 < decls.len) {1384 if (i + 1 < decls.len) {
1435 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);1385 try renderExpression(allocator, stream, tree, node, Space.None);
14361386
1437 const comma_token = tree.nextToken(node.lastToken());1387 const comma_token = tree.nextToken(node.lastToken());
1438 assert(tree.token_ids[comma_token] == .Comma);1388 assert(tree.token_ids[comma_token] == .Comma);
1439 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1389 try renderToken(tree, stream, comma_token, Space.Space); // ,
1440 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);1390 try renderExtraNewline(tree, stream, decls[i + 1]);
1441 } else {1391 } else {
1442 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);1392 try renderExpression(allocator, stream, tree, node, Space.Space);
1443 }1393 }
1444 }1394 }
14451395
1446 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }1396 return renderToken(tree, stream, err_set_decl.rbrace_token, space); // }
1447 }1397 }
1448 },1398 },
14491399
1450 .ErrorTag => {1400 .ErrorTag => {
1451 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);1401 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
14521402
1453 try renderDocComments(tree, stream, tag, tag.doc_comments, indent, start_col);1403 try renderDocComments(tree, stream, tag, tag.doc_comments);
1454 return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name1404 return renderToken(tree, stream, tag.name_token, space); // name
1455 },1405 },
14561406
1457 .MultilineStringLiteral => {1407 .MultilineStringLiteral => {
1458 // TODO: Don't indent in this function, but let the caller indent.
1459 // If this has been implemented, a lot of hacky solutions in i.e. ArrayInit and FunctionCall can be removed
1460 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);1408 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
14611409
1462 var skip_first_indent = true;1410 {
1463 if (tree.token_ids[multiline_str_literal.firstToken() - 1] != .LineComment) {1411 const locked_indents = stream.lockOneShotIndent();
1464 try stream.print("\n", .{});1412 defer {
1465 skip_first_indent = false;1413 var i: u8 = 0;
1466 }1414 while (i < locked_indents) : (i += 1) stream.popIndent();
1467
1468 for (multiline_str_literal.lines()) |t| {
1469 if (!skip_first_indent) {
1470 try stream.writeByteNTimes(' ', indent + indent_delta);
1471 }1415 }
1472 try renderToken(tree, stream, t, indent, start_col, Space.None);1416 try stream.maybeInsertNewline();
1473 skip_first_indent = false;1417
1418 for (multiline_str_literal.lines()) |t| try renderToken(tree, stream, t, Space.None);
1474 }1419 }
1475 try stream.writeByteNTimes(' ', indent);
1476 },1420 },
14771421
1478 .BuiltinCall => {1422 .BuiltinCall => {
1479 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);1423 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
14801424
1481 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name1425 try renderToken(tree, stream, builtin_call.builtin_token, Space.None); // @name
14821426
1483 const src_params_trailing_comma = blk: {1427 const src_params_trailing_comma = blk: {
1484 if (builtin_call.params_len < 2) break :blk false;1428 if (builtin_call.params_len < 2) break :blk false;
...@@ -1490,31 +1434,30 @@ fn renderExpression(...@@ -1490,31 +1434,30 @@ fn renderExpression(
1490 const lparen = tree.nextToken(builtin_call.builtin_token);1434 const lparen = tree.nextToken(builtin_call.builtin_token);
14911435
1492 if (!src_params_trailing_comma) {1436 if (!src_params_trailing_comma) {
1493 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1437 try renderToken(tree, stream, lparen, Space.None); // (
14941438
1495 // render all on one line, no trailing comma1439 // render all on one line, no trailing comma
1496 const params = builtin_call.params();1440 const params = builtin_call.params();
1497 for (params) |param_node, i| {1441 for (params) |param_node, i| {
1498 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);1442 try renderExpression(allocator, stream, tree, param_node, Space.None);
14991443
1500 if (i + 1 < params.len) {1444 if (i + 1 < params.len) {
1501 const comma_token = tree.nextToken(param_node.lastToken());1445 const comma_token = tree.nextToken(param_node.lastToken());
1502 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1446 try renderToken(tree, stream, comma_token, Space.Space); // ,
1503 }1447 }
1504 }1448 }
1505 } else {1449 } else {
1506 // one param per line1450 // one param per line
1507 const new_indent = indent + indent_delta;1451 stream.pushIndent();
1508 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (1452 defer stream.popIndent();
1453 try renderToken(tree, stream, lparen, Space.Newline); // (
15091454
1510 for (builtin_call.params()) |param_node| {1455 for (builtin_call.params()) |param_node| {
1511 try stream.writeByteNTimes(' ', new_indent);1456 try renderExpression(allocator, stream, tree, param_node, Space.Comma);
1512 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);
1513 }1457 }
1514 try stream.writeByteNTimes(' ', indent);
1515 }1458 }
15161459
1517 return renderToken(tree, stream, builtin_call.rparen_token, indent, start_col, space); // )1460 return renderToken(tree, stream, builtin_call.rparen_token, space); // )
1518 },1461 },
15191462
1520 .FnProto => {1463 .FnProto => {
...@@ -1524,24 +1467,24 @@ fn renderExpression(...@@ -1524,24 +1467,24 @@ fn renderExpression(
1524 const visib_token = tree.token_ids[visib_token_index];1467 const visib_token = tree.token_ids[visib_token_index];
1525 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);1468 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
15261469
1527 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub1470 try renderToken(tree, stream, visib_token_index, Space.Space); // pub
1528 }1471 }
15291472
1530 if (fn_proto.getTrailer("extern_export_inline_token")) |extern_export_inline_token| {1473 if (fn_proto.getTrailer("extern_export_inline_token")) |extern_export_inline_token| {
1531 if (fn_proto.getTrailer("is_extern_prototype") == null)1474 if (fn_proto.getTrailer("is_extern_prototype") == null)
1532 try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline1475 try renderToken(tree, stream, extern_export_inline_token, Space.Space); // extern/export/inline
1533 }1476 }
15341477
1535 if (fn_proto.getTrailer("lib_name")) |lib_name| {1478 if (fn_proto.getTrailer("lib_name")) |lib_name| {
1536 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);1479 try renderExpression(allocator, stream, tree, lib_name, Space.Space);
1537 }1480 }
15381481
1539 const lparen = if (fn_proto.getTrailer("name_token")) |name_token| blk: {1482 const lparen = if (fn_proto.getTrailer("name_token")) |name_token| blk: {
1540 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn1483 try renderToken(tree, stream, fn_proto.fn_token, Space.Space); // fn
1541 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name1484 try renderToken(tree, stream, name_token, Space.None); // name
1542 break :blk tree.nextToken(name_token);1485 break :blk tree.nextToken(name_token);
1543 } else blk: {1486 } else blk: {
1544 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn1487 try renderToken(tree, stream, fn_proto.fn_token, Space.Space); // fn
1545 break :blk tree.nextToken(fn_proto.fn_token);1488 break :blk tree.nextToken(fn_proto.fn_token);
1546 };1489 };
1547 assert(tree.token_ids[lparen] == .LParen);1490 assert(tree.token_ids[lparen] == .LParen);
...@@ -1568,47 +1511,45 @@ fn renderExpression(...@@ -1568,47 +1511,45 @@ fn renderExpression(
1568 };1511 };
15691512
1570 if (!src_params_trailing_comma) {1513 if (!src_params_trailing_comma) {
1571 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1514 try renderToken(tree, stream, lparen, Space.None); // (
15721515
1573 // render all on one line, no trailing comma1516 // render all on one line, no trailing comma
1574 for (fn_proto.params()) |param_decl, i| {1517 for (fn_proto.params()) |param_decl, i| {
1575 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);1518 try renderParamDecl(allocator, stream, tree, param_decl, Space.None);
15761519
1577 if (i + 1 < fn_proto.params_len or fn_proto.getTrailer("var_args_token") != null) {1520 if (i + 1 < fn_proto.params_len or fn_proto.getTrailer("var_args_token") != null) {
1578 const comma = tree.nextToken(param_decl.lastToken());1521 const comma = tree.nextToken(param_decl.lastToken());
1579 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,1522 try renderToken(tree, stream, comma, Space.Space); // ,
1580 }1523 }
1581 }1524 }
1582 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {1525 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1583 try renderToken(tree, stream, var_args_token, indent, start_col, Space.None);1526 try renderToken(tree, stream, var_args_token, Space.None);
1584 }1527 }
1585 } else {1528 } else {
1586 // one param per line1529 // one param per line
1587 const new_indent = indent + indent_delta;1530 stream.pushIndent();
1588 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (1531 defer stream.popIndent();
1532 try renderToken(tree, stream, lparen, Space.Newline); // (
15891533
1590 for (fn_proto.params()) |param_decl| {1534 for (fn_proto.params()) |param_decl| {
1591 try stream.writeByteNTimes(' ', new_indent);1535 try renderParamDecl(allocator, stream, tree, param_decl, Space.Comma);
1592 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
1593 }1536 }
1594 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {1537 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1595 try stream.writeByteNTimes(' ', new_indent);1538 try renderToken(tree, stream, var_args_token, Space.Comma);
1596 try renderToken(tree, stream, var_args_token, new_indent, start_col, Space.Comma);
1597 }1539 }
1598 try stream.writeByteNTimes(' ', indent);
1599 }1540 }
16001541
1601 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1542 try renderToken(tree, stream, rparen, Space.Space); // )
16021543
1603 if (fn_proto.getTrailer("align_expr")) |align_expr| {1544 if (fn_proto.getTrailer("align_expr")) |align_expr| {
1604 const align_rparen = tree.nextToken(align_expr.lastToken());1545 const align_rparen = tree.nextToken(align_expr.lastToken());
1605 const align_lparen = tree.prevToken(align_expr.firstToken());1546 const align_lparen = tree.prevToken(align_expr.firstToken());
1606 const align_kw = tree.prevToken(align_lparen);1547 const align_kw = tree.prevToken(align_lparen);
16071548
1608 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align1549 try renderToken(tree, stream, align_kw, Space.None); // align
1609 try renderToken(tree, stream, align_lparen, indent, start_col, Space.None); // (1550 try renderToken(tree, stream, align_lparen, Space.None); // (
1610 try renderExpression(allocator, stream, tree, indent, start_col, align_expr, Space.None);1551 try renderExpression(allocator, stream, tree, align_expr, Space.None);
1611 try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )1552 try renderToken(tree, stream, align_rparen, Space.Space); // )
1612 }1553 }
16131554
1614 if (fn_proto.getTrailer("section_expr")) |section_expr| {1555 if (fn_proto.getTrailer("section_expr")) |section_expr| {
...@@ -1616,10 +1557,10 @@ fn renderExpression(...@@ -1616,10 +1557,10 @@ fn renderExpression(
1616 const section_lparen = tree.prevToken(section_expr.firstToken());1557 const section_lparen = tree.prevToken(section_expr.firstToken());
1617 const section_kw = tree.prevToken(section_lparen);1558 const section_kw = tree.prevToken(section_lparen);
16181559
1619 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // section1560 try renderToken(tree, stream, section_kw, Space.None); // section
1620 try renderToken(tree, stream, section_lparen, indent, start_col, Space.None); // (1561 try renderToken(tree, stream, section_lparen, Space.None); // (
1621 try renderExpression(allocator, stream, tree, indent, start_col, section_expr, Space.None);1562 try renderExpression(allocator, stream, tree, section_expr, Space.None);
1622 try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )1563 try renderToken(tree, stream, section_rparen, Space.Space); // )
1623 }1564 }
16241565
1625 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {1566 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
...@@ -1627,23 +1568,23 @@ fn renderExpression(...@@ -1627,23 +1568,23 @@ fn renderExpression(
1627 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());1568 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
1628 const callconv_kw = tree.prevToken(callconv_lparen);1569 const callconv_kw = tree.prevToken(callconv_lparen);
16291570
1630 try renderToken(tree, stream, callconv_kw, indent, start_col, Space.None); // callconv1571 try renderToken(tree, stream, callconv_kw, Space.None); // callconv
1631 try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (1572 try renderToken(tree, stream, callconv_lparen, Space.None); // (
1632 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);1573 try renderExpression(allocator, stream, tree, callconv_expr, Space.None);
1633 try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )1574 try renderToken(tree, stream, callconv_rparen, Space.Space); // )
1634 } else if (fn_proto.getTrailer("is_extern_prototype") != null) {1575 } else if (fn_proto.getTrailer("is_extern_prototype") != null) {
1635 try stream.writeAll("callconv(.C) ");1576 try stream.writer().writeAll("callconv(.C) ");
1636 } else if (fn_proto.getTrailer("is_async") != null) {1577 } else if (fn_proto.getTrailer("is_async") != null) {
1637 try stream.writeAll("callconv(.Async) ");1578 try stream.writer().writeAll("callconv(.Async) ");
1638 }1579 }
16391580
1640 switch (fn_proto.return_type) {1581 switch (fn_proto.return_type) {
1641 .Explicit => |node| {1582 .Explicit => |node| {
1642 return renderExpression(allocator, stream, tree, indent, start_col, node, space);1583 return renderExpression(allocator, stream, tree, node, space);
1643 },1584 },
1644 .InferErrorSet => |node| {1585 .InferErrorSet => |node| {
1645 try renderToken(tree, stream, tree.prevToken(node.firstToken()), indent, start_col, Space.None); // !1586 try renderToken(tree, stream, tree.prevToken(node.firstToken()), Space.None); // !
1646 return renderExpression(allocator, stream, tree, indent, start_col, node, space);1587 return renderExpression(allocator, stream, tree, node, space);
1647 },1588 },
1648 .Invalid => unreachable,1589 .Invalid => unreachable,
1649 }1590 }
...@@ -1653,11 +1594,11 @@ fn renderExpression(...@@ -1653,11 +1594,11 @@ fn renderExpression(
1653 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);1594 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
16541595
1655 if (anyframe_type.result) |result| {1596 if (anyframe_type.result) |result| {
1656 try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe1597 try renderToken(tree, stream, anyframe_type.anyframe_token, Space.None); // anyframe
1657 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->1598 try renderToken(tree, stream, result.arrow_token, Space.None); // ->
1658 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);1599 return renderExpression(allocator, stream, tree, result.return_type, space);
1659 } else {1600 } else {
1660 return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe1601 return renderToken(tree, stream, anyframe_type.anyframe_token, space); // anyframe
1661 }1602 }
1662 },1603 },
16631604
...@@ -1666,38 +1607,38 @@ fn renderExpression(...@@ -1666,38 +1607,38 @@ fn renderExpression(
1666 .Switch => {1607 .Switch => {
1667 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);1608 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
16681609
1669 try renderToken(tree, stream, switch_node.switch_token, indent, start_col, Space.Space); // switch1610 try renderToken(tree, stream, switch_node.switch_token, Space.Space); // switch
1670 try renderToken(tree, stream, tree.nextToken(switch_node.switch_token), indent, start_col, Space.None); // (1611 try renderToken(tree, stream, tree.nextToken(switch_node.switch_token), Space.None); // (
16711612
1672 const rparen = tree.nextToken(switch_node.expr.lastToken());1613 const rparen = tree.nextToken(switch_node.expr.lastToken());
1673 const lbrace = tree.nextToken(rparen);1614 const lbrace = tree.nextToken(rparen);
16741615
1675 if (switch_node.cases_len == 0) {1616 if (switch_node.cases_len == 0) {
1676 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);1617 try renderExpression(allocator, stream, tree, switch_node.expr, Space.None);
1677 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1618 try renderToken(tree, stream, rparen, Space.Space); // )
1678 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {1619 try renderToken(tree, stream, lbrace, Space.None); // {
1679 return renderToken(tree, stream, switch_node.rbrace, indent, start_col, space); // }1620 return renderToken(tree, stream, switch_node.rbrace, space); // }
1680 }1621 }
16811622
1682 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);1623 try renderExpression(allocator, stream, tree, switch_node.expr, Space.None);
16831624 try renderToken(tree, stream, rparen, Space.Space); // )
1684 const new_indent = indent + indent_delta;
16851625
1686 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1626 {
1687 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {1627 stream.pushIndentNextLine();
1628 defer stream.popIndent();
1629 try renderToken(tree, stream, lbrace, Space.Newline); // {
16881630
1689 const cases = switch_node.cases();1631 const cases = switch_node.cases();
1690 for (cases) |node, i| {1632 for (cases) |node, i| {
1691 try stream.writeByteNTimes(' ', new_indent);1633 try renderExpression(allocator, stream, tree, node, Space.Comma);
1692 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
16931634
1694 if (i + 1 < cases.len) {1635 if (i + 1 < cases.len) {
1695 try renderExtraNewline(tree, stream, start_col, cases[i + 1]);1636 try renderExtraNewline(tree, stream, cases[i + 1]);
1637 }
1696 }1638 }
1697 }1639 }
16981640
1699 try stream.writeByteNTimes(' ', indent);1641 return renderToken(tree, stream, switch_node.rbrace, space); // }
1700 return renderToken(tree, stream, switch_node.rbrace, indent, start_col, space); // }
1701 },1642 },
17021643
1703 .SwitchCase => {1644 .SwitchCase => {
...@@ -1714,43 +1655,41 @@ fn renderExpression(...@@ -1714,43 +1655,41 @@ fn renderExpression(
1714 const items = switch_case.items();1655 const items = switch_case.items();
1715 for (items) |node, i| {1656 for (items) |node, i| {
1716 if (i + 1 < items.len) {1657 if (i + 1 < items.len) {
1717 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);1658 try renderExpression(allocator, stream, tree, node, Space.None);
17181659
1719 const comma_token = tree.nextToken(node.lastToken());1660 const comma_token = tree.nextToken(node.lastToken());
1720 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1661 try renderToken(tree, stream, comma_token, Space.Space); // ,
1721 try renderExtraNewline(tree, stream, start_col, items[i + 1]);1662 try renderExtraNewline(tree, stream, items[i + 1]);
1722 } else {1663 } else {
1723 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);1664 try renderExpression(allocator, stream, tree, node, Space.Space);
1724 }1665 }
1725 }1666 }
1726 } else {1667 } else {
1727 const items = switch_case.items();1668 const items = switch_case.items();
1728 for (items) |node, i| {1669 for (items) |node, i| {
1729 if (i + 1 < items.len) {1670 if (i + 1 < items.len) {
1730 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);1671 try renderExpression(allocator, stream, tree, node, Space.None);
17311672
1732 const comma_token = tree.nextToken(node.lastToken());1673 const comma_token = tree.nextToken(node.lastToken());
1733 try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // ,1674 try renderToken(tree, stream, comma_token, Space.Newline); // ,
1734 try renderExtraNewline(tree, stream, start_col, items[i + 1]);1675 try renderExtraNewline(tree, stream, items[i + 1]);
1735 try stream.writeByteNTimes(' ', indent);
1736 } else {1676 } else {
1737 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Comma);1677 try renderExpression(allocator, stream, tree, node, Space.Comma);
1738 try stream.writeByteNTimes(' ', indent);
1739 }1678 }
1740 }1679 }
1741 }1680 }
17421681
1743 try renderToken(tree, stream, switch_case.arrow_token, indent, start_col, Space.Space); // =>1682 try renderToken(tree, stream, switch_case.arrow_token, Space.Space); // =>
17441683
1745 if (switch_case.payload) |payload| {1684 if (switch_case.payload) |payload| {
1746 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);1685 try renderExpression(allocator, stream, tree, payload, Space.Space);
1747 }1686 }
17481687
1749 return renderExpression(allocator, stream, tree, indent, start_col, switch_case.expr, space);1688 return renderExpression(allocator, stream, tree, switch_case.expr, space);
1750 },1689 },
1751 .SwitchElse => {1690 .SwitchElse => {
1752 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);1691 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
1753 return renderToken(tree, stream, switch_else.token, indent, start_col, space);1692 return renderToken(tree, stream, switch_else.token, space);
1754 },1693 },
1755 .Else => {1694 .Else => {
1756 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);1695 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
...@@ -1759,37 +1698,37 @@ fn renderExpression(...@@ -1759,37 +1698,37 @@ fn renderExpression(
1759 const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken());1698 const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken());
17601699
1761 const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline;1700 const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline;
1762 try renderToken(tree, stream, else_node.else_token, indent, start_col, after_else_space);1701 try renderToken(tree, stream, else_node.else_token, after_else_space);
17631702
1764 if (else_node.payload) |payload| {1703 if (else_node.payload) |payload| {
1765 const payload_space = if (same_line) Space.Space else Space.Newline;1704 const payload_space = if (same_line) Space.Space else Space.Newline;
1766 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);1705 try renderExpression(allocator, stream, tree, payload, payload_space);
1767 }1706 }
17681707
1769 if (same_line) {1708 if (same_line) {
1770 return renderExpression(allocator, stream, tree, indent, start_col, else_node.body, space);1709 return renderExpression(allocator, stream, tree, else_node.body, space);
1710 } else {
1711 stream.pushIndent();
1712 defer stream.popIndent();
1713 return renderExpression(allocator, stream, tree, else_node.body, space);
1771 }1714 }
1772
1773 try stream.writeByteNTimes(' ', indent + indent_delta);
1774 start_col.* = indent + indent_delta;
1775 return renderExpression(allocator, stream, tree, indent, start_col, else_node.body, space);
1776 },1715 },
17771716
1778 .While => {1717 .While => {
1779 const while_node = @fieldParentPtr(ast.Node.While, "base", base);1718 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
17801719
1781 if (while_node.label) |label| {1720 if (while_node.label) |label| {
1782 try renderToken(tree, stream, label, indent, start_col, Space.None); // label1721 try renderToken(tree, stream, label, Space.None); // label
1783 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); // :1722 try renderToken(tree, stream, tree.nextToken(label), Space.Space); // :
1784 }1723 }
17851724
1786 if (while_node.inline_token) |inline_token| {1725 if (while_node.inline_token) |inline_token| {
1787 try renderToken(tree, stream, inline_token, indent, start_col, Space.Space); // inline1726 try renderToken(tree, stream, inline_token, Space.Space); // inline
1788 }1727 }
17891728
1790 try renderToken(tree, stream, while_node.while_token, indent, start_col, Space.Space); // while1729 try renderToken(tree, stream, while_node.while_token, Space.Space); // while
1791 try renderToken(tree, stream, tree.nextToken(while_node.while_token), indent, start_col, Space.None); // (1730 try renderToken(tree, stream, tree.nextToken(while_node.while_token), Space.None); // (
1792 try renderExpression(allocator, stream, tree, indent, start_col, while_node.condition, Space.None);1731 try renderExpression(allocator, stream, tree, while_node.condition, Space.None);
17931732
1794 const cond_rparen = tree.nextToken(while_node.condition.lastToken());1733 const cond_rparen = tree.nextToken(while_node.condition.lastToken());
17951734
...@@ -1811,12 +1750,12 @@ fn renderExpression(...@@ -1811,12 +1750,12 @@ fn renderExpression(
18111750
1812 {1751 {
1813 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;1752 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;
1814 try renderToken(tree, stream, cond_rparen, indent, start_col, rparen_space); // )1753 try renderToken(tree, stream, cond_rparen, rparen_space); // )
1815 }1754 }
18161755
1817 if (while_node.payload) |payload| {1756 if (while_node.payload) |payload| {
1818 const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;1757 const payload_space = Space.Space; //if (while_node.continue_expr != null) Space.Space else block_start_space;
1819 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);1758 try renderExpression(allocator, stream, tree, payload, payload_space);
1820 }1759 }
18211760
1822 if (while_node.continue_expr) |continue_expr| {1761 if (while_node.continue_expr) |continue_expr| {
...@@ -1824,29 +1763,22 @@ fn renderExpression(...@@ -1824,29 +1763,22 @@ fn renderExpression(
1824 const lparen = tree.prevToken(continue_expr.firstToken());1763 const lparen = tree.prevToken(continue_expr.firstToken());
1825 const colon = tree.prevToken(lparen);1764 const colon = tree.prevToken(lparen);
18261765
1827 try renderToken(tree, stream, colon, indent, start_col, Space.Space); // :1766 try renderToken(tree, stream, colon, Space.Space); // :
1828 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1767 try renderToken(tree, stream, lparen, Space.None); // (
18291768
1830 try renderExpression(allocator, stream, tree, indent, start_col, continue_expr, Space.None);1769 try renderExpression(allocator, stream, tree, continue_expr, Space.None);
18311770
1832 try renderToken(tree, stream, rparen, indent, start_col, block_start_space); // )1771 try renderToken(tree, stream, rparen, block_start_space); // )
1833 }1772 }
18341773
1835 var new_indent = indent;1774 {
1836 if (block_start_space == Space.Newline) {1775 if (!body_is_block) stream.pushIndent();
1837 new_indent += indent_delta;1776 defer if (!body_is_block) stream.popIndent();
1838 try stream.writeByteNTimes(' ', new_indent);1777 try renderExpression(allocator, stream, tree, while_node.body, after_body_space);
1839 start_col.* = new_indent;
1840 }1778 }
18411779
1842 try renderExpression(allocator, stream, tree, indent, start_col, while_node.body, after_body_space);
1843
1844 if (while_node.@"else") |@"else"| {1780 if (while_node.@"else") |@"else"| {
1845 if (after_body_space == Space.Newline) {1781 return renderExpression(allocator, stream, tree, &@"else".base, space);
1846 try stream.writeByteNTimes(' ', indent);
1847 start_col.* = indent;
1848 }
1849 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);
1850 }1782 }
1851 },1783 },
18521784
...@@ -1854,17 +1786,17 @@ fn renderExpression(...@@ -1854,17 +1786,17 @@ fn renderExpression(
1854 const for_node = @fieldParentPtr(ast.Node.For, "base", base);1786 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
18551787
1856 if (for_node.label) |label| {1788 if (for_node.label) |label| {
1857 try renderToken(tree, stream, label, indent, start_col, Space.None); // label1789 try renderToken(tree, stream, label, Space.None); // label
1858 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); // :1790 try renderToken(tree, stream, tree.nextToken(label), Space.Space); // :
1859 }1791 }
18601792
1861 if (for_node.inline_token) |inline_token| {1793 if (for_node.inline_token) |inline_token| {
1862 try renderToken(tree, stream, inline_token, indent, start_col, Space.Space); // inline1794 try renderToken(tree, stream, inline_token, Space.Space); // inline
1863 }1795 }
18641796
1865 try renderToken(tree, stream, for_node.for_token, indent, start_col, Space.Space); // for1797 try renderToken(tree, stream, for_node.for_token, Space.Space); // for
1866 try renderToken(tree, stream, tree.nextToken(for_node.for_token), indent, start_col, Space.None); // (1798 try renderToken(tree, stream, tree.nextToken(for_node.for_token), Space.None); // (
1867 try renderExpression(allocator, stream, tree, indent, start_col, for_node.array_expr, Space.None);1799 try renderExpression(allocator, stream, tree, for_node.array_expr, Space.None);
18681800
1869 const rparen = tree.nextToken(for_node.array_expr.lastToken());1801 const rparen = tree.nextToken(for_node.array_expr.lastToken());
18701802
...@@ -1872,10 +1804,10 @@ fn renderExpression(...@@ -1872,10 +1804,10 @@ fn renderExpression(
1872 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());1804 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
1873 const body_on_same_line = body_is_block or src_one_line_to_body;1805 const body_on_same_line = body_is_block or src_one_line_to_body;
18741806
1875 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1807 try renderToken(tree, stream, rparen, Space.Space); // )
18761808
1877 const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;1809 const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;
1878 try renderExpression(allocator, stream, tree, indent, start_col, for_node.payload, space_after_payload); // |x|1810 try renderExpression(allocator, stream, tree, for_node.payload, space_after_payload); // |x|
18791811
1880 const space_after_body = blk: {1812 const space_after_body = blk: {
1881 if (for_node.@"else") |@"else"| {1813 if (for_node.@"else") |@"else"| {
...@@ -1890,13 +1822,14 @@ fn renderExpression(...@@ -1890,13 +1822,14 @@ fn renderExpression(
1890 }1822 }
1891 };1823 };
18921824
1893 const body_indent = if (body_on_same_line) indent else indent + indent_delta;1825 {
1894 if (!body_on_same_line) try stream.writeByteNTimes(' ', body_indent);1826 if (!body_on_same_line) stream.pushIndent();
1895 try renderExpression(allocator, stream, tree, body_indent, start_col, for_node.body, space_after_body); // { body }1827 defer if (!body_on_same_line) stream.popIndent();
1828 try renderExpression(allocator, stream, tree, for_node.body, space_after_body); // { body }
1829 }
18961830
1897 if (for_node.@"else") |@"else"| {1831 if (for_node.@"else") |@"else"| {
1898 if (space_after_body == Space.Newline) try stream.writeByteNTimes(' ', indent);1832 return renderExpression(allocator, stream, tree, &@"else".base, space); // else
1899 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space); // else
1900 }1833 }
1901 },1834 },
19021835
...@@ -1906,29 +1839,29 @@ fn renderExpression(...@@ -1906,29 +1839,29 @@ fn renderExpression(
1906 const lparen = tree.nextToken(if_node.if_token);1839 const lparen = tree.nextToken(if_node.if_token);
1907 const rparen = tree.nextToken(if_node.condition.lastToken());1840 const rparen = tree.nextToken(if_node.condition.lastToken());
19081841
1909 try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if1842 try renderToken(tree, stream, if_node.if_token, Space.Space); // if
1910 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1843 try renderToken(tree, stream, lparen, Space.None); // (
19111844
1912 try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition1845 try renderExpression(allocator, stream, tree, if_node.condition, Space.None); // condition
19131846
1914 const body_is_if_block = if_node.body.tag == .If;1847 const body_is_if_block = if_node.body.tag == .If;
1915 const body_is_block = nodeIsBlock(if_node.body);1848 const body_is_block = nodeIsBlock(if_node.body);
19161849
1917 if (body_is_if_block) {1850 if (body_is_if_block) {
1918 try renderExtraNewline(tree, stream, start_col, if_node.body);1851 try renderExtraNewline(tree, stream, if_node.body);
1919 } else if (body_is_block) {1852 } else if (body_is_block) {
1920 const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;1853 const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;
1921 try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )1854 try renderToken(tree, stream, rparen, after_rparen_space); // )
19221855
1923 if (if_node.payload) |payload| {1856 if (if_node.payload) |payload| {
1924 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.BlockStart); // |x|1857 try renderExpression(allocator, stream, tree, payload, Space.BlockStart); // |x|
1925 }1858 }
19261859
1927 if (if_node.@"else") |@"else"| {1860 if (if_node.@"else") |@"else"| {
1928 try renderExpression(allocator, stream, tree, indent, start_col, if_node.body, Space.SpaceOrOutdent);1861 try renderExpression(allocator, stream, tree, if_node.body, Space.SpaceOrOutdent);
1929 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);1862 return renderExpression(allocator, stream, tree, &@"else".base, space);
1930 } else {1863 } else {
1931 return renderExpression(allocator, stream, tree, indent, start_col, if_node.body, space);1864 return renderExpression(allocator, stream, tree, if_node.body, space);
1932 }1865 }
1933 }1866 }
19341867
...@@ -1936,186 +1869,181 @@ fn renderExpression(...@@ -1936,186 +1869,181 @@ fn renderExpression(
19361869
1937 if (src_has_newline) {1870 if (src_has_newline) {
1938 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;1871 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
1939 try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )1872 try renderToken(tree, stream, rparen, after_rparen_space); // )
19401873
1941 if (if_node.payload) |payload| {1874 if (if_node.payload) |payload| {
1942 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Newline);1875 try renderExpression(allocator, stream, tree, payload, Space.Newline);
1943 }1876 }
19441877
1945 const new_indent = indent + indent_delta;
1946 try stream.writeByteNTimes(' ', new_indent);
1947
1948 if (if_node.@"else") |@"else"| {1878 if (if_node.@"else") |@"else"| {
1949 const else_is_block = nodeIsBlock(@"else".body);1879 const else_is_block = nodeIsBlock(@"else".body);
1950 try renderExpression(allocator, stream, tree, new_indent, start_col, if_node.body, Space.Newline);1880
1951 try stream.writeByteNTimes(' ', indent);1881 {
1882 stream.pushIndent();
1883 defer stream.popIndent();
1884 try renderExpression(allocator, stream, tree, if_node.body, Space.Newline);
1885 }
19521886
1953 if (else_is_block) {1887 if (else_is_block) {
1954 try renderToken(tree, stream, @"else".else_token, indent, start_col, Space.Space); // else1888 try renderToken(tree, stream, @"else".else_token, Space.Space); // else
19551889
1956 if (@"else".payload) |payload| {1890 if (@"else".payload) |payload| {
1957 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);1891 try renderExpression(allocator, stream, tree, payload, Space.Space);
1958 }1892 }
19591893
1960 return renderExpression(allocator, stream, tree, indent, start_col, @"else".body, space);1894 return renderExpression(allocator, stream, tree, @"else".body, space);
1961 } else {1895 } else {
1962 const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space;1896 const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space;
1963 try renderToken(tree, stream, @"else".else_token, indent, start_col, after_else_space); // else1897 try renderToken(tree, stream, @"else".else_token, after_else_space); // else
19641898
1965 if (@"else".payload) |payload| {1899 if (@"else".payload) |payload| {
1966 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Newline);1900 try renderExpression(allocator, stream, tree, payload, Space.Newline);
1967 }1901 }
1968 try stream.writeByteNTimes(' ', new_indent);
19691902
1970 return renderExpression(allocator, stream, tree, new_indent, start_col, @"else".body, space);1903 stream.pushIndent();
1904 defer stream.popIndent();
1905 return renderExpression(allocator, stream, tree, @"else".body, space);
1971 }1906 }
1972 } else {1907 } else {
1973 return renderExpression(allocator, stream, tree, new_indent, start_col, if_node.body, space);1908 stream.pushIndent();
1909 defer stream.popIndent();
1910 return renderExpression(allocator, stream, tree, if_node.body, space);
1974 }1911 }
1975 }1912 }
19761913
1977 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1914 // Single line if statement
1915
1916 try renderToken(tree, stream, rparen, Space.Space); // )
19781917
1979 if (if_node.payload) |payload| {1918 if (if_node.payload) |payload| {
1980 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);1919 try renderExpression(allocator, stream, tree, payload, Space.Space);
1981 }1920 }
19821921
1983 if (if_node.@"else") |@"else"| {1922 if (if_node.@"else") |@"else"| {
1984 try renderExpression(allocator, stream, tree, indent, start_col, if_node.body, Space.Space);1923 try renderExpression(allocator, stream, tree, if_node.body, Space.Space);
1985 try renderToken(tree, stream, @"else".else_token, indent, start_col, Space.Space);1924 try renderToken(tree, stream, @"else".else_token, Space.Space);
19861925
1987 if (@"else".payload) |payload| {1926 if (@"else".payload) |payload| {
1988 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);1927 try renderExpression(allocator, stream, tree, payload, Space.Space);
1989 }1928 }
19901929
1991 return renderExpression(allocator, stream, tree, indent, start_col, @"else".body, space);1930 return renderExpression(allocator, stream, tree, @"else".body, space);
1992 } else {1931 } else {
1993 return renderExpression(allocator, stream, tree, indent, start_col, if_node.body, space);1932 return renderExpression(allocator, stream, tree, if_node.body, space);
1994 }1933 }
1995 },1934 },
19961935
1997 .Asm => {1936 .Asm => {
1998 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);1937 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
19991938
2000 try renderToken(tree, stream, asm_node.asm_token, indent, start_col, Space.Space); // asm1939 try renderToken(tree, stream, asm_node.asm_token, Space.Space); // asm
20011940
2002 if (asm_node.volatile_token) |volatile_token| {1941 if (asm_node.volatile_token) |volatile_token| {
2003 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile1942 try renderToken(tree, stream, volatile_token, Space.Space); // volatile
2004 try renderToken(tree, stream, tree.nextToken(volatile_token), indent, start_col, Space.None); // (1943 try renderToken(tree, stream, tree.nextToken(volatile_token), Space.None); // (
2005 } else {1944 } else {
2006 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (1945 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), Space.None); // (
2007 }1946 }
20081947
2009 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {1948 asmblk: {
2010 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);1949 stream.pushIndent();
2011 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);1950 defer stream.popIndent();
2012 }
20131951
2014 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.Newline);1952 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1953 try renderExpression(allocator, stream, tree, asm_node.template, Space.None);
1954 break :asmblk;
1955 }
20151956
2016 const indent_once = indent + indent_delta;1957 try renderExpression(allocator, stream, tree, asm_node.template, Space.Newline);
20171958
2018 if (asm_node.template.tag == .MultilineStringLiteral) {1959 const colon1 = tree.nextToken(asm_node.template.lastToken());
2019 // After rendering a multiline string literal the cursor is
2020 // already offset by indent
2021 try stream.writeByteNTimes(' ', indent_delta);
2022 } else {
2023 try stream.writeByteNTimes(' ', indent_once);
2024 }
20251960
2026 const colon1 = tree.nextToken(asm_node.template.lastToken());1961 const colon2 = if (asm_node.outputs.len == 0) blk: {
2027 const indent_extra = indent_once + 2;1962 try renderToken(tree, stream, colon1, Space.Newline); // :
20281963
2029 const colon2 = if (asm_node.outputs.len == 0) blk: {1964 break :blk tree.nextToken(colon1);
2030 try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :1965 } else blk: {
2031 try stream.writeByteNTimes(' ', indent_once);1966 try renderToken(tree, stream, colon1, Space.Space); // :
20321967
2033 break :blk tree.nextToken(colon1);1968 stream.pushIndentN(2);
2034 } else blk: {1969 defer stream.popIndent();
2035 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
2036
2037 for (asm_node.outputs) |*asm_output, i| {
2038 if (i + 1 < asm_node.outputs.len) {
2039 const next_asm_output = asm_node.outputs[i + 1];
2040 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None);
2041
2042 const comma = tree.prevToken(next_asm_output.firstToken());
2043 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
2044 try renderExtraNewlineToken(tree, stream, start_col, next_asm_output.firstToken());
2045
2046 try stream.writeByteNTimes(' ', indent_extra);
2047 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
2048 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
2049 try stream.writeByteNTimes(' ', indent);
2050 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
2051 } else {
2052 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
2053 try stream.writeByteNTimes(' ', indent_once);
2054 const comma_or_colon = tree.nextToken(asm_output.lastToken());
2055 break :blk switch (tree.token_ids[comma_or_colon]) {
2056 .Comma => tree.nextToken(comma_or_colon),
2057 else => comma_or_colon,
2058 };
2059 }
2060 }
2061 unreachable;
2062 };
20631970
2064 const colon3 = if (asm_node.inputs.len == 0) blk: {1971 for (asm_node.outputs) |*asm_output, i| {
2065 try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :1972 if (i + 1 < asm_node.outputs.len) {
2066 try stream.writeByteNTimes(' ', indent_once);1973 const next_asm_output = asm_node.outputs[i + 1];
1974 try renderAsmOutput(allocator, stream, tree, asm_output, Space.None);
20671975
2068 break :blk tree.nextToken(colon2);1976 const comma = tree.prevToken(next_asm_output.firstToken());
2069 } else blk: {1977 try renderToken(tree, stream, comma, Space.Newline); // ,
2070 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :1978 try renderExtraNewlineToken(tree, stream, next_asm_output.firstToken());
20711979 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
2072 for (asm_node.inputs) |*asm_input, i| {1980 try renderAsmOutput(allocator, stream, tree, asm_output, Space.Newline);
2073 if (i + 1 < asm_node.inputs.len) {1981 break :asmblk;
2074 const next_asm_input = &asm_node.inputs[i + 1];1982 } else {
2075 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None);1983 try renderAsmOutput(allocator, stream, tree, asm_output, Space.Newline);
20761984 const comma_or_colon = tree.nextToken(asm_output.lastToken());
2077 const comma = tree.prevToken(next_asm_input.firstToken());1985 break :blk switch (tree.token_ids[comma_or_colon]) {
2078 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,1986 .Comma => tree.nextToken(comma_or_colon),
2079 try renderExtraNewlineToken(tree, stream, start_col, next_asm_input.firstToken());1987 else => comma_or_colon,
20801988 };
2081 try stream.writeByteNTimes(' ', indent_extra);1989 }
2082 } else if (asm_node.clobbers.len == 0) {
2083 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
2084 try stream.writeByteNTimes(' ', indent);
2085 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
2086 } else {
2087 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
2088 try stream.writeByteNTimes(' ', indent_once);
2089 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2090 break :blk switch (tree.token_ids[comma_or_colon]) {
2091 .Comma => tree.nextToken(comma_or_colon),
2092 else => comma_or_colon,
2093 };
2094 }1990 }
2095 }1991 unreachable;
2096 unreachable;1992 };
2097 };
20981993
2099 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :1994 const colon3 = if (asm_node.inputs.len == 0) blk: {
1995 try renderToken(tree, stream, colon2, Space.Newline); // :
1996 break :blk tree.nextToken(colon2);
1997 } else blk: {
1998 try renderToken(tree, stream, colon2, Space.Space); // :
1999 stream.pushIndentN(2);
2000 defer stream.popIndent();
2001 for (asm_node.inputs) |*asm_input, i| {
2002 if (i + 1 < asm_node.inputs.len) {
2003 const next_asm_input = &asm_node.inputs[i + 1];
2004 try renderAsmInput(allocator, stream, tree, asm_input, Space.None);
2005
2006 const comma = tree.prevToken(next_asm_input.firstToken());
2007 try renderToken(tree, stream, comma, Space.Newline); // ,
2008 try renderExtraNewlineToken(tree, stream, next_asm_input.firstToken());
2009 } else if (asm_node.clobbers.len == 0) {
2010 try renderAsmInput(allocator, stream, tree, asm_input, Space.Newline);
2011 break :asmblk;
2012 } else {
2013 try renderAsmInput(allocator, stream, tree, asm_input, Space.Newline);
2014 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2015 break :blk switch (tree.token_ids[comma_or_colon]) {
2016 .Comma => tree.nextToken(comma_or_colon),
2017 else => comma_or_colon,
2018 };
2019 }
2020 }
2021 unreachable;
2022 };
21002023
2101 for (asm_node.clobbers) |clobber_node, i| {2024 try renderToken(tree, stream, colon3, Space.Space); // :
2102 if (i + 1 >= asm_node.clobbers.len) {2025 stream.pushIndentN(2);
2103 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);2026 defer stream.popIndent();
2104 try stream.writeByteNTimes(' ', indent);2027 for (asm_node.clobbers) |clobber_node, i| {
2105 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);2028 if (i + 1 >= asm_node.clobbers.len) {
2106 } else {2029 try renderExpression(allocator, stream, tree, clobber_node, Space.Newline);
2107 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.None);2030 break :asmblk;
2108 const comma = tree.nextToken(clobber_node.lastToken());2031 } else {
2109 try renderToken(tree, stream, comma, indent_once, start_col, Space.Space); // ,2032 try renderExpression(allocator, stream, tree, clobber_node, Space.None);
2033 const comma = tree.nextToken(clobber_node.lastToken());
2034 try renderToken(tree, stream, comma, Space.Space); // ,
2035 }
2110 }2036 }
2111 }2037 }
2038
2039 return renderToken(tree, stream, asm_node.rparen, space);
2112 },2040 },
21132041
2114 .EnumLiteral => {2042 .EnumLiteral => {
2115 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);2043 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
21162044
2117 try renderToken(tree, stream, enum_literal.dot, indent, start_col, Space.None); // .2045 try renderToken(tree, stream, enum_literal.dot, Space.None); // .
2118 return renderToken(tree, stream, enum_literal.name, indent, start_col, space); // name2046 return renderToken(tree, stream, enum_literal.name, space); // name
2119 },2047 },
21202048
2121 .ContainerField,2049 .ContainerField,
...@@ -2131,116 +2059,113 @@ fn renderArrayType(...@@ -2131,116 +2059,113 @@ fn renderArrayType(
2131 allocator: *mem.Allocator,2059 allocator: *mem.Allocator,
2132 stream: anytype,2060 stream: anytype,
2133 tree: *ast.Tree,2061 tree: *ast.Tree,
2134 indent: usize,
2135 start_col: *usize,
2136 lbracket: ast.TokenIndex,2062 lbracket: ast.TokenIndex,
2137 rhs: *ast.Node,2063 rhs: *ast.Node,
2138 len_expr: *ast.Node,2064 len_expr: *ast.Node,
2139 opt_sentinel: ?*ast.Node,2065 opt_sentinel: ?*ast.Node,
2140 space: Space,2066 space: Space,
2141) (@TypeOf(stream).Error || Error)!void {2067) (@TypeOf(stream.*).Error || Error)!void {
2142 const rbracket = tree.nextToken(if (opt_sentinel) |sentinel|2068 const rbracket = tree.nextToken(if (opt_sentinel) |sentinel|
2143 sentinel.lastToken()2069 sentinel.lastToken()
2144 else2070 else
2145 len_expr.lastToken());2071 len_expr.lastToken());
21462072
2147 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
2148
2149 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;2073 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
2150 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;2074 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
2151 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
2152 const new_space = if (ends_with_comment) Space.Newline else Space.None;2075 const new_space = if (ends_with_comment) Space.Newline else Space.None;
2153 try renderExpression(allocator, stream, tree, new_indent, start_col, len_expr, new_space);2076 {
2154 if (starts_with_comment) {2077 const do_indent = (starts_with_comment or ends_with_comment);
2155 try stream.writeByte('\n');2078 if (do_indent) stream.pushIndent();
2156 }2079 defer if (do_indent) stream.popIndent();
2157 if (ends_with_comment or starts_with_comment) {2080
2158 try stream.writeByteNTimes(' ', indent);2081 try renderToken(tree, stream, lbracket, Space.None); // [
2159 }2082 try renderExpression(allocator, stream, tree, len_expr, new_space);
2160 if (opt_sentinel) |sentinel| {2083
2161 const colon_token = tree.prevToken(sentinel.firstToken());2084 if (starts_with_comment) {
2162 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :2085 try stream.maybeInsertNewline();
2163 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);2086 }
2087 if (opt_sentinel) |sentinel| {
2088 const colon_token = tree.prevToken(sentinel.firstToken());
2089 try renderToken(tree, stream, colon_token, Space.None); // :
2090 try renderExpression(allocator, stream, tree, sentinel, Space.None);
2091 }
2092 if (starts_with_comment) {
2093 try stream.maybeInsertNewline();
2094 }
2164 }2095 }
2165 try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]2096 try renderToken(tree, stream, rbracket, Space.None); // ]
21662097
2167 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);2098 return renderExpression(allocator, stream, tree, rhs, space);
2168}2099}
21692100
2170fn renderAsmOutput(2101fn renderAsmOutput(
2171 allocator: *mem.Allocator,2102 allocator: *mem.Allocator,
2172 stream: anytype,2103 stream: anytype,
2173 tree: *ast.Tree,2104 tree: *ast.Tree,
2174 indent: usize,
2175 start_col: *usize,
2176 asm_output: *const ast.Node.Asm.Output,2105 asm_output: *const ast.Node.Asm.Output,
2177 space: Space,2106 space: Space,
2178) (@TypeOf(stream).Error || Error)!void {2107) (@TypeOf(stream.*).Error || Error)!void {
2179 try stream.writeAll("[");2108 try stream.writer().writeAll("[");
2180 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);2109 try renderExpression(allocator, stream, tree, asm_output.symbolic_name, Space.None);
2181 try stream.writeAll("] ");2110 try stream.writer().writeAll("] ");
2182 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);2111 try renderExpression(allocator, stream, tree, asm_output.constraint, Space.None);
2183 try stream.writeAll(" (");2112 try stream.writer().writeAll(" (");
21842113
2185 switch (asm_output.kind) {2114 switch (asm_output.kind) {
2186 ast.Node.Asm.Output.Kind.Variable => |variable_name| {2115 ast.Node.Asm.Output.Kind.Variable => |variable_name| {
2187 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);2116 try renderExpression(allocator, stream, tree, &variable_name.base, Space.None);
2188 },2117 },
2189 ast.Node.Asm.Output.Kind.Return => |return_type| {2118 ast.Node.Asm.Output.Kind.Return => |return_type| {
2190 try stream.writeAll("-> ");2119 try stream.writer().writeAll("-> ");
2191 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);2120 try renderExpression(allocator, stream, tree, return_type, Space.None);
2192 },2121 },
2193 }2122 }
21942123
2195 return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )2124 return renderToken(tree, stream, asm_output.lastToken(), space); // )
2196}2125}
21972126
2198fn renderAsmInput(2127fn renderAsmInput(
2199 allocator: *mem.Allocator,2128 allocator: *mem.Allocator,
2200 stream: anytype,2129 stream: anytype,
2201 tree: *ast.Tree,2130 tree: *ast.Tree,
2202 indent: usize,
2203 start_col: *usize,
2204 asm_input: *const ast.Node.Asm.Input,2131 asm_input: *const ast.Node.Asm.Input,
2205 space: Space,2132 space: Space,
2206) (@TypeOf(stream).Error || Error)!void {2133) (@TypeOf(stream.*).Error || Error)!void {
2207 try stream.writeAll("[");2134 try stream.writer().writeAll("[");
2208 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);2135 try renderExpression(allocator, stream, tree, asm_input.symbolic_name, Space.None);
2209 try stream.writeAll("] ");2136 try stream.writer().writeAll("] ");
2210 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);2137 try renderExpression(allocator, stream, tree, asm_input.constraint, Space.None);
2211 try stream.writeAll(" (");2138 try stream.writer().writeAll(" (");
2212 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);2139 try renderExpression(allocator, stream, tree, asm_input.expr, Space.None);
2213 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )2140 return renderToken(tree, stream, asm_input.lastToken(), space); // )
2214}2141}
22152142
2216fn renderVarDecl(2143fn renderVarDecl(
2217 allocator: *mem.Allocator,2144 allocator: *mem.Allocator,
2218 stream: anytype,2145 stream: anytype,
2219 tree: *ast.Tree,2146 tree: *ast.Tree,
2220 indent: usize,
2221 start_col: *usize,
2222 var_decl: *ast.Node.VarDecl,2147 var_decl: *ast.Node.VarDecl,
2223) (@TypeOf(stream).Error || Error)!void {2148) (@TypeOf(stream.*).Error || Error)!void {
2224 if (var_decl.getTrailer("visib_token")) |visib_token| {2149 if (var_decl.getTrailer("visib_token")) |visib_token| {
2225 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub2150 try renderToken(tree, stream, visib_token, Space.Space); // pub
2226 }2151 }
22272152
2228 if (var_decl.getTrailer("extern_export_token")) |extern_export_token| {2153 if (var_decl.getTrailer("extern_export_token")) |extern_export_token| {
2229 try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern2154 try renderToken(tree, stream, extern_export_token, Space.Space); // extern
22302155
2231 if (var_decl.getTrailer("lib_name")) |lib_name| {2156 if (var_decl.getTrailer("lib_name")) |lib_name| {
2232 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"2157 try renderExpression(allocator, stream, tree, lib_name, Space.Space); // "lib"
2233 }2158 }
2234 }2159 }
22352160
2236 if (var_decl.getTrailer("comptime_token")) |comptime_token| {2161 if (var_decl.getTrailer("comptime_token")) |comptime_token| {
2237 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime2162 try renderToken(tree, stream, comptime_token, Space.Space); // comptime
2238 }2163 }
22392164
2240 if (var_decl.getTrailer("thread_local_token")) |thread_local_token| {2165 if (var_decl.getTrailer("thread_local_token")) |thread_local_token| {
2241 try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal2166 try renderToken(tree, stream, thread_local_token, Space.Space); // threadlocal
2242 }2167 }
2243 try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var2168 try renderToken(tree, stream, var_decl.mut_token, Space.Space); // var
22442169
2245 const name_space = if (var_decl.getTrailer("type_node") == null and2170 const name_space = if (var_decl.getTrailer("type_node") == null and
2246 (var_decl.getTrailer("align_node") != null or2171 (var_decl.getTrailer("align_node") != null or
...@@ -2249,70 +2174,69 @@ fn renderVarDecl(...@@ -2249,70 +2174,69 @@ fn renderVarDecl(
2249 Space.Space2174 Space.Space
2250 else2175 else
2251 Space.None;2176 Space.None;
2252 try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);2177 try renderToken(tree, stream, var_decl.name_token, name_space);
22532178
2254 if (var_decl.getTrailer("type_node")) |type_node| {2179 if (var_decl.getTrailer("type_node")) |type_node| {
2255 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);2180 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), Space.Space);
2256 const s = if (var_decl.getTrailer("align_node") != null or2181 const s = if (var_decl.getTrailer("align_node") != null or
2257 var_decl.getTrailer("section_node") != null or2182 var_decl.getTrailer("section_node") != null or
2258 var_decl.getTrailer("init_node") != null) Space.Space else Space.None;2183 var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2259 try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);2184 try renderExpression(allocator, stream, tree, type_node, s);
2260 }2185 }
22612186
2262 if (var_decl.getTrailer("align_node")) |align_node| {2187 if (var_decl.getTrailer("align_node")) |align_node| {
2263 const lparen = tree.prevToken(align_node.firstToken());2188 const lparen = tree.prevToken(align_node.firstToken());
2264 const align_kw = tree.prevToken(lparen);2189 const align_kw = tree.prevToken(lparen);
2265 const rparen = tree.nextToken(align_node.lastToken());2190 const rparen = tree.nextToken(align_node.lastToken());
2266 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align2191 try renderToken(tree, stream, align_kw, Space.None); // align
2267 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (2192 try renderToken(tree, stream, lparen, Space.None); // (
2268 try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);2193 try renderExpression(allocator, stream, tree, align_node, Space.None);
2269 const s = if (var_decl.getTrailer("section_node") != null or var_decl.getTrailer("init_node") != null) Space.Space else Space.None;2194 const s = if (var_decl.getTrailer("section_node") != null or var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2270 try renderToken(tree, stream, rparen, indent, start_col, s); // )2195 try renderToken(tree, stream, rparen, s); // )
2271 }2196 }
22722197
2273 if (var_decl.getTrailer("section_node")) |section_node| {2198 if (var_decl.getTrailer("section_node")) |section_node| {
2274 const lparen = tree.prevToken(section_node.firstToken());2199 const lparen = tree.prevToken(section_node.firstToken());
2275 const section_kw = tree.prevToken(lparen);2200 const section_kw = tree.prevToken(lparen);
2276 const rparen = tree.nextToken(section_node.lastToken());2201 const rparen = tree.nextToken(section_node.lastToken());
2277 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection2202 try renderToken(tree, stream, section_kw, Space.None); // linksection
2278 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (2203 try renderToken(tree, stream, lparen, Space.None); // (
2279 try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None);2204 try renderExpression(allocator, stream, tree, section_node, Space.None);
2280 const s = if (var_decl.getTrailer("init_node") != null) Space.Space else Space.None;2205 const s = if (var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2281 try renderToken(tree, stream, rparen, indent, start_col, s); // )2206 try renderToken(tree, stream, rparen, s); // )
2282 }2207 }
22832208
2284 if (var_decl.getTrailer("init_node")) |init_node| {2209 if (var_decl.getTrailer("init_node")) |init_node| {
2285 const s = if (init_node.tag == .MultilineStringLiteral) Space.None else Space.Space;2210 const s = if (init_node.tag == .MultilineStringLiteral) Space.None else Space.Space;
2286 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // =2211 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, s); // =
2287 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);2212 stream.pushIndentOneShot();
2213 try renderExpression(allocator, stream, tree, init_node, Space.None);
2288 }2214 }
22892215
2290 try renderToken(tree, stream, var_decl.semicolon_token, indent, start_col, Space.Newline);2216 try renderToken(tree, stream, var_decl.semicolon_token, Space.Newline);
2291}2217}
22922218
2293fn renderParamDecl(2219fn renderParamDecl(
2294 allocator: *mem.Allocator,2220 allocator: *mem.Allocator,
2295 stream: anytype,2221 stream: anytype,
2296 tree: *ast.Tree,2222 tree: *ast.Tree,
2297 indent: usize,
2298 start_col: *usize,
2299 param_decl: ast.Node.FnProto.ParamDecl,2223 param_decl: ast.Node.FnProto.ParamDecl,
2300 space: Space,2224 space: Space,
2301) (@TypeOf(stream).Error || Error)!void {2225) (@TypeOf(stream.*).Error || Error)!void {
2302 try renderDocComments(tree, stream, param_decl, param_decl.doc_comments, indent, start_col);2226 try renderDocComments(tree, stream, param_decl, param_decl.doc_comments);
23032227
2304 if (param_decl.comptime_token) |comptime_token| {2228 if (param_decl.comptime_token) |comptime_token| {
2305 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);2229 try renderToken(tree, stream, comptime_token, Space.Space);
2306 }2230 }
2307 if (param_decl.noalias_token) |noalias_token| {2231 if (param_decl.noalias_token) |noalias_token| {
2308 try renderToken(tree, stream, noalias_token, indent, start_col, Space.Space);2232 try renderToken(tree, stream, noalias_token, Space.Space);
2309 }2233 }
2310 if (param_decl.name_token) |name_token| {2234 if (param_decl.name_token) |name_token| {
2311 try renderToken(tree, stream, name_token, indent, start_col, Space.None);2235 try renderToken(tree, stream, name_token, Space.None);
2312 try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :2236 try renderToken(tree, stream, tree.nextToken(name_token), Space.Space); // :
2313 }2237 }
2314 switch (param_decl.param_type) {2238 switch (param_decl.param_type) {
2315 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),2239 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, node, space),
2316 }2240 }
2317}2241}
23182242
...@@ -2320,24 +2244,22 @@ fn renderStatement(...@@ -2320,24 +2244,22 @@ fn renderStatement(
2320 allocator: *mem.Allocator,2244 allocator: *mem.Allocator,
2321 stream: anytype,2245 stream: anytype,
2322 tree: *ast.Tree,2246 tree: *ast.Tree,
2323 indent: usize,
2324 start_col: *usize,
2325 base: *ast.Node,2247 base: *ast.Node,
2326) (@TypeOf(stream).Error || Error)!void {2248) (@TypeOf(stream.*).Error || Error)!void {
2327 switch (base.tag) {2249 switch (base.tag) {
2328 .VarDecl => {2250 .VarDecl => {
2329 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);2251 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
2330 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);2252 try renderVarDecl(allocator, stream, tree, var_decl);
2331 },2253 },
2332 else => {2254 else => {
2333 if (base.requireSemiColon()) {2255 if (base.requireSemiColon()) {
2334 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);2256 try renderExpression(allocator, stream, tree, base, Space.None);
23352257
2336 const semicolon_index = tree.nextToken(base.lastToken());2258 const semicolon_index = tree.nextToken(base.lastToken());
2337 assert(tree.token_ids[semicolon_index] == .Semicolon);2259 assert(tree.token_ids[semicolon_index] == .Semicolon);
2338 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);2260 try renderToken(tree, stream, semicolon_index, Space.Newline);
2339 } else {2261 } else {
2340 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);2262 try renderExpression(allocator, stream, tree, base, Space.Newline);
2341 }2263 }
2342 },2264 },
2343 }2265 }
...@@ -2358,22 +2280,17 @@ fn renderTokenOffset(...@@ -2358,22 +2280,17 @@ fn renderTokenOffset(
2358 tree: *ast.Tree,2280 tree: *ast.Tree,
2359 stream: anytype,2281 stream: anytype,
2360 token_index: ast.TokenIndex,2282 token_index: ast.TokenIndex,
2361 indent: usize,
2362 start_col: *usize,
2363 space: Space,2283 space: Space,
2364 token_skip_bytes: usize,2284 token_skip_bytes: usize,
2365) (@TypeOf(stream).Error || Error)!void {2285) (@TypeOf(stream.*).Error || Error)!void {
2366 if (space == Space.BlockStart) {2286 if (space == Space.BlockStart) {
2367 if (start_col.* < indent + indent_delta)2287 // If placing the lbrace on the current line would cause an uggly gap then put the lbrace on the next line
2368 return renderToken(tree, stream, token_index, indent, start_col, Space.Space);2288 const new_space = if (stream.isLineOverIndented()) Space.Newline else Space.Space;
2369 try renderToken(tree, stream, token_index, indent, start_col, Space.Newline);2289 return renderToken(tree, stream, token_index, new_space);
2370 try stream.writeByteNTimes(' ', indent);
2371 start_col.* = indent;
2372 return;
2373 }2290 }
23742291
2375 var token_loc = tree.token_locs[token_index];2292 var token_loc = tree.token_locs[token_index];
2376 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));2293 try stream.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));
23772294
2378 if (space == Space.NoComment)2295 if (space == Space.NoComment)
2379 return;2296 return;
...@@ -2382,20 +2299,20 @@ fn renderTokenOffset(...@@ -2382,20 +2299,20 @@ fn renderTokenOffset(
2382 var next_token_loc = tree.token_locs[token_index + 1];2299 var next_token_loc = tree.token_locs[token_index + 1];
23832300
2384 if (space == Space.Comma) switch (next_token_id) {2301 if (space == Space.Comma) switch (next_token_id) {
2385 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),2302 .Comma => return renderToken(tree, stream, token_index + 1, Space.Newline),
2386 .LineComment => {2303 .LineComment => {
2387 try stream.writeAll(", ");2304 try stream.writer().writeAll(", ");
2388 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);2305 return renderToken(tree, stream, token_index + 1, Space.Newline);
2389 },2306 },
2390 else => {2307 else => {
2391 if (token_index + 2 < tree.token_ids.len and2308 if (token_index + 2 < tree.token_ids.len and
2392 tree.token_ids[token_index + 2] == .MultilineStringLiteralLine)2309 tree.token_ids[token_index + 2] == .MultilineStringLiteralLine)
2393 {2310 {
2394 try stream.writeAll(",");2311 try stream.writer().writeAll(",");
2395 return;2312 return;
2396 } else {2313 } else {
2397 try stream.writeAll(",\n");2314 try stream.writer().writeAll(",");
2398 start_col.* = 0;2315 try stream.insertNewline();
2399 return;2316 return;
2400 }2317 }
2401 },2318 },
...@@ -2419,15 +2336,14 @@ fn renderTokenOffset(...@@ -2419,15 +2336,14 @@ fn renderTokenOffset(
2419 if (next_token_id == .MultilineStringLiteralLine) {2336 if (next_token_id == .MultilineStringLiteralLine) {
2420 return;2337 return;
2421 } else {2338 } else {
2422 try stream.writeAll("\n");2339 try stream.insertNewline();
2423 start_col.* = 0;
2424 return;2340 return;
2425 }2341 }
2426 },2342 },
2427 Space.Space, Space.SpaceOrOutdent => {2343 Space.Space, Space.SpaceOrOutdent => {
2428 if (next_token_id == .MultilineStringLiteralLine)2344 if (next_token_id == .MultilineStringLiteralLine)
2429 return;2345 return;
2430 try stream.writeByte(' ');2346 try stream.writer().writeByte(' ');
2431 return;2347 return;
2432 },2348 },
2433 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,2349 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
...@@ -2444,8 +2360,7 @@ fn renderTokenOffset(...@@ -2444,8 +2360,7 @@ fn renderTokenOffset(
2444 next_token_id = tree.token_ids[token_index + offset];2360 next_token_id = tree.token_ids[token_index + offset];
2445 next_token_loc = tree.token_locs[token_index + offset];2361 next_token_loc = tree.token_locs[token_index + offset];
2446 if (next_token_id != .LineComment) {2362 if (next_token_id != .LineComment) {
2447 try stream.writeByte('\n');2363 try stream.insertNewline();
2448 start_col.* = 0;
2449 return;2364 return;
2450 }2365 }
2451 },2366 },
...@@ -2458,7 +2373,7 @@ fn renderTokenOffset(...@@ -2458,7 +2373,7 @@ fn renderTokenOffset(
24582373
2459 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);2374 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2460 if (loc.line == 0) {2375 if (loc.line == 0) {
2461 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});2376 try stream.writer().print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});
2462 offset = 2;2377 offset = 2;
2463 token_loc = next_token_loc;2378 token_loc = next_token_loc;
2464 next_token_loc = tree.token_locs[token_index + offset];2379 next_token_loc = tree.token_locs[token_index + offset];
...@@ -2466,26 +2381,16 @@ fn renderTokenOffset(...@@ -2466,26 +2381,16 @@ fn renderTokenOffset(
2466 if (next_token_id != .LineComment) {2381 if (next_token_id != .LineComment) {
2467 switch (space) {2382 switch (space) {
2468 Space.None, Space.Space => {2383 Space.None, Space.Space => {
2469 try stream.writeByte('\n');2384 try stream.insertNewline();
2470 const after_comment_token = tree.token_ids[token_index + offset];
2471 const next_line_indent = switch (after_comment_token) {
2472 .RParen, .RBrace, .RBracket => indent,
2473 else => indent + indent_delta,
2474 };
2475 try stream.writeByteNTimes(' ', next_line_indent);
2476 start_col.* = next_line_indent;
2477 },2385 },
2478 Space.SpaceOrOutdent => {2386 Space.SpaceOrOutdent => {
2479 try stream.writeByte('\n');2387 try stream.insertNewline();
2480 try stream.writeByteNTimes(' ', indent);
2481 start_col.* = indent;
2482 },2388 },
2483 Space.Newline => {2389 Space.Newline => {
2484 if (next_token_id == .MultilineStringLiteralLine) {2390 if (next_token_id == .MultilineStringLiteralLine) {
2485 return;2391 return;
2486 } else {2392 } else {
2487 try stream.writeAll("\n");2393 try stream.insertNewline();
2488 start_col.* = 0;
2489 return;2394 return;
2490 }2395 }
2491 },2396 },
...@@ -2501,10 +2406,9 @@ fn renderTokenOffset(...@@ -2501,10 +2406,9 @@ fn renderTokenOffset(
2501 // translate-c doesn't generate correct newlines2406 // translate-c doesn't generate correct newlines
2502 // in generated code (loc.line == 0) so treat that case2407 // in generated code (loc.line == 0) so treat that case
2503 // as though there was meant to be a newline between the tokens2408 // as though there was meant to be a newline between the tokens
2504 const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);2409 var newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);
2505 try stream.writeByteNTimes('\n', newline_count);2410 while (newline_count > 0) : (newline_count -= 1) try stream.insertNewline();
2506 try stream.writeByteNTimes(' ', indent);2411 try stream.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
2507 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
25082412
2509 offset += 1;2413 offset += 1;
2510 token_loc = next_token_loc;2414 token_loc = next_token_loc;
...@@ -2516,32 +2420,15 @@ fn renderTokenOffset(...@@ -2516,32 +2420,15 @@ fn renderTokenOffset(
2516 if (next_token_id == .MultilineStringLiteralLine) {2420 if (next_token_id == .MultilineStringLiteralLine) {
2517 return;2421 return;
2518 } else {2422 } else {
2519 try stream.writeAll("\n");2423 try stream.insertNewline();
2520 start_col.* = 0;
2521 return;2424 return;
2522 }2425 }
2523 },2426 },
2524 Space.None, Space.Space => {2427 Space.None, Space.Space => {
2525 try stream.writeByte('\n');2428 try stream.insertNewline();
2526
2527 const after_comment_token = tree.token_ids[token_index + offset];
2528 const next_line_indent = switch (after_comment_token) {
2529 .RParen, .RBrace, .RBracket => blk: {
2530 if (indent > indent_delta) {
2531 break :blk indent - indent_delta;
2532 } else {
2533 break :blk 0;
2534 }
2535 },
2536 else => indent,
2537 };
2538 try stream.writeByteNTimes(' ', next_line_indent);
2539 start_col.* = next_line_indent;
2540 },2429 },
2541 Space.SpaceOrOutdent => {2430 Space.SpaceOrOutdent => {
2542 try stream.writeByte('\n');2431 try stream.insertNewline();
2543 try stream.writeByteNTimes(' ', indent);
2544 start_col.* = indent;
2545 },2432 },
2546 Space.NoNewline => {},2433 Space.NoNewline => {},
2547 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,2434 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
...@@ -2556,11 +2443,9 @@ fn renderToken(...@@ -2556,11 +2443,9 @@ fn renderToken(
2556 tree: *ast.Tree,2443 tree: *ast.Tree,
2557 stream: anytype,2444 stream: anytype,
2558 token_index: ast.TokenIndex,2445 token_index: ast.TokenIndex,
2559 indent: usize,
2560 start_col: *usize,
2561 space: Space,2446 space: Space,
2562) (@TypeOf(stream).Error || Error)!void {2447) (@TypeOf(stream.*).Error || Error)!void {
2563 return renderTokenOffset(tree, stream, token_index, indent, start_col, space, 0);2448 return renderTokenOffset(tree, stream, token_index, space, 0);
2564}2449}
25652450
2566fn renderDocComments(2451fn renderDocComments(
...@@ -2568,11 +2453,9 @@ fn renderDocComments(...@@ -2568,11 +2453,9 @@ fn renderDocComments(
2568 stream: anytype,2453 stream: anytype,
2569 node: anytype,2454 node: anytype,
2570 doc_comments: ?*ast.Node.DocComment,2455 doc_comments: ?*ast.Node.DocComment,
2571 indent: usize,2456) (@TypeOf(stream.*).Error || Error)!void {
2572 start_col: *usize,
2573) (@TypeOf(stream).Error || Error)!void {
2574 const comment = doc_comments orelse return;2457 const comment = doc_comments orelse return;
2575 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);2458 return renderDocCommentsToken(tree, stream, comment, node.firstToken());
2576}2459}
25772460
2578fn renderDocCommentsToken(2461fn renderDocCommentsToken(
...@@ -2580,20 +2463,16 @@ fn renderDocCommentsToken(...@@ -2580,20 +2463,16 @@ fn renderDocCommentsToken(
2580 stream: anytype,2463 stream: anytype,
2581 comment: *ast.Node.DocComment,2464 comment: *ast.Node.DocComment,
2582 first_token: ast.TokenIndex,2465 first_token: ast.TokenIndex,
2583 indent: usize,2466) (@TypeOf(stream.*).Error || Error)!void {
2584 start_col: *usize,
2585) (@TypeOf(stream).Error || Error)!void {
2586 var tok_i = comment.first_line;2467 var tok_i = comment.first_line;
2587 while (true) : (tok_i += 1) {2468 while (true) : (tok_i += 1) {
2588 switch (tree.token_ids[tok_i]) {2469 switch (tree.token_ids[tok_i]) {
2589 .DocComment, .ContainerDocComment => {2470 .DocComment, .ContainerDocComment => {
2590 if (comment.first_line < first_token) {2471 if (comment.first_line < first_token) {
2591 try renderToken(tree, stream, tok_i, indent, start_col, Space.Newline);2472 try renderToken(tree, stream, tok_i, Space.Newline);
2592 try stream.writeByteNTimes(' ', indent);
2593 } else {2473 } else {
2594 try renderToken(tree, stream, tok_i, indent, start_col, Space.NoComment);2474 try renderToken(tree, stream, tok_i, Space.NoComment);
2595 try stream.writeAll("\n");2475 try stream.insertNewline();
2596 try stream.writeByteNTimes(' ', indent);
2597 }2476 }
2598 },2477 },
2599 .LineComment => continue,2478 .LineComment => continue,
...@@ -2665,41 +2544,10 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {...@@ -2665,41 +2544,10 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
2665 };2544 };
2666}2545}
26672546
2668/// A `std.io.OutStream` that returns whether the given character has been written to it.2547fn copyFixingWhitespace(stream: anytype, slice: []const u8) @TypeOf(stream.*).Error!void {
2669/// The contents are not written to anything.
2670const FindByteOutStream = struct {
2671 byte_found: bool,
2672 byte: u8,
2673
2674 pub const Error = error{};
2675 pub const OutStream = std.io.OutStream(*FindByteOutStream, Error, write);
2676
2677 pub fn init(byte: u8) FindByteOutStream {
2678 return FindByteOutStream{
2679 .byte = byte,
2680 .byte_found = false,
2681 };
2682 }
2683
2684 pub fn write(self: *FindByteOutStream, bytes: []const u8) Error!usize {
2685 if (self.byte_found) return bytes.len;
2686 self.byte_found = blk: {
2687 for (bytes) |b|
2688 if (b == self.byte) break :blk true;
2689 break :blk false;
2690 };
2691 return bytes.len;
2692 }
2693
2694 pub fn outStream(self: *FindByteOutStream) OutStream {
2695 return .{ .context = self };
2696 }
2697};
2698
2699fn copyFixingWhitespace(stream: anytype, slice: []const u8) @TypeOf(stream).Error!void {
2700 for (slice) |byte| switch (byte) {2548 for (slice) |byte| switch (byte) {
2701 '\t' => try stream.writeAll(" "),2549 '\t' => try stream.writer().writeAll(" "),
2702 '\r' => {},2550 '\r' => {},
2703 else => try stream.writeByte(byte),2551 else => try stream.writer().writeByte(byte),
2704 };2552 };
2705}2553}
src-self-hosted/main.zig+5-4
...@@ -682,13 +682,13 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -682,13 +682,13 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
682 process.exit(1);682 process.exit(1);
683 }683 }
684 if (check_flag) {684 if (check_flag) {
685 const anything_changed = try std.zig.render(gpa, io.null_out_stream, tree);685 const anything_changed = try std.zig.render(gpa, &io.null_out_stream, tree);
686 const code = if (anything_changed) @as(u8, 1) else @as(u8, 0);686 const code = if (anything_changed) @as(u8, 1) else @as(u8, 0);
687 process.exit(code);687 process.exit(code);
688 }688 }
689689
690 const stdout = io.getStdOut().outStream();690 const stdout = io.getStdOut().outStream();
691 _ = try std.zig.render(gpa, stdout, tree);691 _ = try std.zig.render(gpa, &stdout, tree);
692 return;692 return;
693 }693 }
694694
...@@ -830,7 +830,7 @@ fn fmtPathFile(...@@ -830,7 +830,7 @@ fn fmtPathFile(
830 }830 }
831831
832 if (check_mode) {832 if (check_mode) {
833 const anything_changed = try std.zig.render(fmt.gpa, io.null_out_stream, tree);833 const anything_changed = try std.zig.render(fmt.gpa, &io.null_out_stream, tree);
834 if (anything_changed) {834 if (anything_changed) {
835 std.debug.print("{}\n", .{file_path});835 std.debug.print("{}\n", .{file_path});
836 fmt.any_error = true;836 fmt.any_error = true;
...@@ -839,7 +839,8 @@ fn fmtPathFile(...@@ -839,7 +839,8 @@ fn fmtPathFile(
839 // As a heuristic, we make enough capacity for the same as the input source.839 // As a heuristic, we make enough capacity for the same as the input source.
840 try fmt.out_buffer.ensureCapacity(source_code.len);840 try fmt.out_buffer.ensureCapacity(source_code.len);
841 fmt.out_buffer.items.len = 0;841 fmt.out_buffer.items.len = 0;
842 const anything_changed = try std.zig.render(fmt.gpa, fmt.out_buffer.writer(), tree);842 const writer = fmt.out_buffer.writer();
843 const anything_changed = try std.zig.render(fmt.gpa, &writer, tree);
843 if (!anything_changed)844 if (!anything_changed)
844 return; // Good thing we didn't waste any file system access on this.845 return; // Good thing we didn't waste any file system access on this.
845846
src-self-hosted/stage2.zig+1-1
...@@ -151,7 +151,7 @@ export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, error...@@ -151,7 +151,7 @@ export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, error
151151
152export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {152export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
153 const c_out_stream = std.io.cOutStream(output_file);153 const c_out_stream = std.io.cOutStream(output_file);
154 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {154 _ = std.zig.render(std.heap.c_allocator, &c_out_stream, tree) catch |e| switch (e) {
155 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode155 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
156 error.NotOpenForWriting => unreachable,156 error.NotOpenForWriting => unreachable,
157 error.SystemResources => return .SystemResources,157 error.SystemResources => return .SystemResources,