authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-02 18:14:28-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-09-02 18:14:28-04:00
log405c7215a8054680a789cf94afe41fd66c7d61c7
treea528933363e18fb9ba1f805e5951f1130f0e779d
parent12ce6eb8f65e6de5920c713cf2767e4b8ba0f1d3
parentbb848dbeeec133b2ca1d6dc42fe9dd04b848b58a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6194 from LakeByTheWoods/fmt_indentation

Refactor zig fmt indentation. Remove indent from rendering code

8 files changed, 1132 insertions(+), 920 deletions(-)

lib/std/io.zig+9
...@@ -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;
lib/std/io/auto_indenting_stream.zig created+148
...@@ -0,0 +1,148 @@
1const std = @import("../std.zig");
2const io = std.io;
3const mem = std.mem;
4const assert = std.debug.assert;
5
6/// Automatically inserts indentation of written data by keeping
7/// track of the current indentation level
8pub fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
9 return struct {
10 const Self = @This();
11 pub const Error = UnderlyingWriter.Error;
12 pub const Writer = io.Writer(*Self, Error, write);
13
14 underlying_writer: UnderlyingWriter,
15
16 indent_count: usize = 0,
17 indent_delta: usize,
18 current_line_empty: bool = true,
19 indent_one_shot_count: usize = 0, // automatically popped when applied
20 applied_indent: usize = 0, // the most recently applied indent
21 indent_next_line: usize = 0, // not used until the next line
22
23 pub fn writer(self: *Self) Writer {
24 return .{ .context = self };
25 }
26
27 pub fn write(self: *Self, bytes: []const u8) Error!usize {
28 if (bytes.len == 0)
29 return @as(usize, 0);
30
31 try self.applyIndent();
32 return self.writeNoIndent(bytes);
33 }
34
35 // Change the indent delta without changing the final indentation level
36 pub fn setIndentDelta(self: *Self, indent_delta: usize) void {
37 if (self.indent_delta == indent_delta) {
38 return;
39 } else if (self.indent_delta > indent_delta) {
40 assert(self.indent_delta % indent_delta == 0);
41 self.indent_count = self.indent_count * (self.indent_delta / indent_delta);
42 } else {
43 // assert that the current indentation (in spaces) in a multiple of the new delta
44 assert((self.indent_count * self.indent_delta) % indent_delta == 0);
45 self.indent_count = self.indent_count / (indent_delta / self.indent_delta);
46 }
47 self.indent_delta = indent_delta;
48 }
49
50 fn writeNoIndent(self: *Self, bytes: []const u8) Error!usize {
51 if (bytes.len == 0)
52 return @as(usize, 0);
53
54 try self.underlying_writer.writeAll(bytes);
55 if (bytes[bytes.len - 1] == '\n')
56 self.resetLine();
57 return bytes.len;
58 }
59
60 pub fn insertNewline(self: *Self) Error!void {
61 _ = try self.writeNoIndent("\n");
62 }
63
64 fn resetLine(self: *Self) void {
65 self.current_line_empty = true;
66 self.indent_next_line = 0;
67 }
68
69 /// Insert a newline unless the current line is blank
70 pub fn maybeInsertNewline(self: *Self) Error!void {
71 if (!self.current_line_empty)
72 try self.insertNewline();
73 }
74
75 /// Push default indentation
76 pub fn pushIndent(self: *Self) void {
77 // Doesn't actually write any indentation.
78 // Just primes the stream to be able to write the correct indentation if it needs to.
79 self.indent_count += 1;
80 }
81
82 /// Push an indent that is automatically popped after being applied
83 pub fn pushIndentOneShot(self: *Self) void {
84 self.indent_one_shot_count += 1;
85 self.pushIndent();
86 }
87
88 /// Turns all one-shot indents into regular indents
89 /// Returns number of indents that must now be manually popped
90 pub fn lockOneShotIndent(self: *Self) usize {
91 var locked_count = self.indent_one_shot_count;
92 self.indent_one_shot_count = 0;
93 return locked_count;
94 }
95
96 /// Push an indent that should not take effect until the next line
97 pub fn pushIndentNextLine(self: *Self) void {
98 self.indent_next_line += 1;
99 self.pushIndent();
100 }
101
102 pub fn popIndent(self: *Self) void {
103 assert(self.indent_count != 0);
104 self.indent_count -= 1;
105
106 if (self.indent_next_line > 0)
107 self.indent_next_line -= 1;
108 }
109
110 /// Writes ' ' bytes if the current line is empty
111 fn applyIndent(self: *Self) Error!void {
112 const current_indent = self.currentIndent();
113 if (self.current_line_empty and current_indent > 0) {
114 try self.underlying_writer.writeByteNTimes(' ', current_indent);
115 self.applied_indent = current_indent;
116 }
117
118 self.indent_count -= self.indent_one_shot_count;
119 self.indent_one_shot_count = 0;
120 self.current_line_empty = false;
121 }
122
123 /// Checks to see if the most recent indentation exceeds the currently pushed indents
124 pub fn isLineOverIndented(self: *Self) bool {
125 if (self.current_line_empty) return false;
126 return self.applied_indent > self.currentIndent();
127 }
128
129 fn currentIndent(self: *Self) usize {
130 var indent_current: usize = 0;
131 if (self.indent_count > 0) {
132 const indent_count = self.indent_count - self.indent_next_line;
133 indent_current = indent_count * self.indent_delta;
134 }
135 return indent_current;
136 }
137 };
138}
139
140pub fn autoIndentingStream(
141 indent_delta: usize,
142 underlying_writer: anytype,
143) AutoIndentingStream(@TypeOf(underlying_writer)) {
144 return AutoIndentingStream(@TypeOf(underlying_writer)){
145 .underlying_writer = underlying_writer,
146 .indent_delta = indent_delta,
147 };
148}
lib/std/io/change_detection_stream.zig created+55
...@@ -0,0 +1,55 @@
1const std = @import("../std.zig");
2const io = std.io;
3const mem = std.mem;
4const assert = std.debug.assert;
5
6/// Used to detect if the data written to a stream differs from a source buffer
7pub fn ChangeDetectionStream(comptime WriterType: type) type {
8 return struct {
9 const Self = @This();
10 pub const Error = WriterType.Error;
11 pub const Writer = io.Writer(*Self, Error, write);
12
13 anything_changed: bool,
14 underlying_writer: WriterType,
15 source_index: usize,
16 source: []const u8,
17
18 pub fn writer(self: *Self) Writer {
19 return .{ .context = self };
20 }
21
22 fn write(self: *Self, bytes: []const u8) Error!usize {
23 if (!self.anything_changed) {
24 const end = self.source_index + bytes.len;
25 if (end > self.source.len) {
26 self.anything_changed = true;
27 } else {
28 const src_slice = self.source[self.source_index..end];
29 self.source_index += bytes.len;
30 if (!mem.eql(u8, bytes, src_slice)) {
31 self.anything_changed = true;
32 }
33 }
34 }
35
36 return self.underlying_writer.write(bytes);
37 }
38
39 pub fn changeDetected(self: *Self) bool {
40 return self.anything_changed or (self.source_index != self.source.len);
41 }
42 };
43}
44
45pub fn changeDetectionStream(
46 source: []const u8,
47 underlying_writer: anytype,
48) ChangeDetectionStream(@TypeOf(underlying_writer)) {
49 return ChangeDetectionStream(@TypeOf(underlying_writer)){
50 .anything_changed = false,
51 .underlying_writer = underlying_writer,
52 .source_index = 0,
53 .source = source,
54 };
55}
lib/std/io/find_byte_out_stream.zig created+40
...@@ -0,0 +1,40 @@
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 UnderlyingWriter: type) type {
8 return struct {
9 const Self = @This();
10 pub const Error = UnderlyingWriter.Error;
11 pub const Writer = io.Writer(*Self, Error, write);
12
13 underlying_writer: UnderlyingWriter,
14 byte_found: bool,
15 byte: u8,
16
17 pub fn writer(self: *Self) Writer {
18 return .{ .context = self };
19 }
20
21 fn write(self: *Self, bytes: []const u8) Error!usize {
22 if (!self.byte_found) {
23 self.byte_found = blk: {
24 for (bytes) |b|
25 if (b == self.byte) break :blk true;
26 break :blk false;
27 };
28 }
29 return self.underlying_writer.write(bytes);
30 }
31 };
32}
33
34pub fn findByteOutStream(byte: u8, underlying_writer: anytype) FindByteOutStream(@TypeOf(underlying_writer)) {
35 return FindByteOutStream(@TypeOf(underlying_writer)){
36 .underlying_writer = underlying_writer,
37 .byte = byte,
38 .byte_found = false,
39 };
40}
lib/std/target.zig+1-1
...@@ -101,7 +101,7 @@ pub const Target = struct {...@@ -101,7 +101,7 @@ pub const Target = struct {
101101
102 /// Latest Windows version that the Zig Standard Library is aware of102 /// Latest Windows version that the Zig Standard Library is aware of
103 pub const latest = WindowsVersion.win10_20h1;103 pub const latest = WindowsVersion.win10_20h1;
104 104
105 pub const Range = struct {105 pub const Range = struct {
106 min: WindowsVersion,106 min: WindowsVersion,
107 max: WindowsVersion,107 max: WindowsVersion,
lib/std/zig/parser_test.zig+114-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,34 @@ test "zig fmt: C var args" {...@@ -3214,6 +3293,34 @@ 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
3313test "zig fmt: Don't add extra newline after if" {
3314 try testCanonical(
3315 \\pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
3316 \\ if (cwd().symLink(existing_path, new_path, .{})) {
3317 \\ return;
3318 \\ }
3319 \\}
3320 \\
3321 );
3322}
3323
3217const std = @import("std");3324const std = @import("std");
3218const mem = std.mem;3325const mem = std.mem;
3219const warn = std.debug.warn;3326const warn = std.debug.warn;
...@@ -3256,7 +3363,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b...@@ -3256,7 +3363,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
3256 var buffer = std.ArrayList(u8).init(allocator);3363 var buffer = std.ArrayList(u8).init(allocator);
3257 errdefer buffer.deinit();3364 errdefer buffer.deinit();
32583365
3259 anything_changed.* = try std.zig.render(allocator, buffer.outStream(), tree);3366 const outStream = buffer.outStream();
3367 anything_changed.* = try std.zig.render(allocator, outStream, tree);
3260 return buffer.toOwnedSlice();3368 return buffer.toOwnedSlice();
3261}3369}
3262fn testTransform(source: []const u8, expected_source: []const u8) !void {3370fn testTransform(source: []const u8, expected_source: []const u8) !void {
lib/std/zig/render.zig+763-912
...@@ -6,10 +6,12 @@...@@ -6,10 +6,12 @@
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
12const indent_delta = 4;13const indent_delta = 4;
14const asm_indent_delta = 2;
1315
14pub const Error = error{16pub const Error = error{
15 /// Ran out of memory allocating call stack frames to complete rendering.17 /// Ran out of memory allocating call stack frames to complete rendering.
...@@ -21,70 +23,32 @@ pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (@Typ...@@ -21,70 +23,32 @@ pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (@Typ
21 // cannot render an invalid tree23 // cannot render an invalid tree
22 std.debug.assert(tree.errors.len == 0);24 std.debug.assert(tree.errors.len == 0);
2325
24 // make a passthrough stream that checks whether something changed26 var change_detection_stream = std.io.changeDetectionStream(tree.source, stream);
25 const MyStream = struct {27 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, change_detection_stream.writer());
26 const MyStream = @This();
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 ais: anytype,
73 tree: *ast.Tree,37 tree: *ast.Tree,
74) (@TypeOf(stream).Error || Error)!void {38) (@TypeOf(ais.*).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 ais.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 ais.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
...@@ -145,7 +109,7 @@ fn renderRoot(...@@ -145,7 +109,7 @@ fn renderRoot(
145 // If there's no next reformatted `decl`, just copy the109 // If there's no next reformatted `decl`, just copy the
146 // remaining input tokens and bail out.110 // remaining input tokens and bail out.
147 const start = tree.token_locs[copy_start_token_index].start;111 const start = tree.token_locs[copy_start_token_index].start;
148 try copyFixingWhitespace(stream, tree.source[start..]);112 try copyFixingWhitespace(ais, tree.source[start..]);
149 return;113 return;
150 }114 }
151 decl = root_decls[decl_i];115 decl = root_decls[decl_i];
...@@ -186,26 +150,25 @@ fn renderRoot(...@@ -186,26 +150,25 @@ fn renderRoot(
186150
187 const start = tree.token_locs[copy_start_token_index].start;151 const start = tree.token_locs[copy_start_token_index].start;
188 const end = tree.token_locs[copy_end_token_index].start;152 const end = tree.token_locs[copy_end_token_index].start;
189 try copyFixingWhitespace(stream, tree.source[start..end]);153 try copyFixingWhitespace(ais, tree.source[start..end]);
190 }154 }
191155
192 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);156 try renderTopLevelDecl(allocator, ais, 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, ais, 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, ais: anytype, node: *ast.Node) @TypeOf(ais.*).Error!void {
200 return renderExtraNewlineToken(tree, stream, start_col, node.firstToken());164 return renderExtraNewlineToken(tree, ais, node.firstToken());
201}165}
202166
203fn renderExtraNewlineToken(167fn renderExtraNewlineToken(
204 tree: *ast.Tree,168 tree: *ast.Tree,
205 stream: anytype,169 ais: anytype,
206 start_col: *usize,
207 first_token: ast.TokenIndex,170 first_token: ast.TokenIndex,
208) @TypeOf(stream).Error!void {171) @TypeOf(ais.*).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 ais.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, ais: anytype, tree: *ast.Tree, decl: *ast.Node) (@TypeOf(ais.*).Error || Error)!void {
227 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Newline);189 try renderContainerDecl(allocator, ais, 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, ais: anytype, tree: *ast.Tree, decl: *ast.Node, space: Space) (@TypeOf(ais.*).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.getDocComments(), indent, start_col);197 try renderDocComments(tree, ais, fn_proto, fn_proto.getDocComments());
236198
237 if (fn_proto.getBodyNode()) |body_node| {199 if (fn_proto.getBodyNode()) |body_node| {
238 try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);200 try renderExpression(allocator, ais, tree, decl, .Space);
239 try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);201 try renderExpression(allocator, ais, tree, body_node, space);
240 } else {202 } else {
241 try renderExpression(allocator, stream, tree, indent, start_col, decl, .None);203 try renderExpression(allocator, ais, tree, decl, .None);
242 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, start_col, space);204 try renderToken(tree, ais, 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, ais, visib_token, .Space); // pub
251 }213 }
252 try renderToken(tree, stream, use_decl.use_token, indent, start_col, .Space); // usingnamespace214 try renderToken(tree, ais, use_decl.use_token, .Space); // usingnamespace
253 try renderExpression(allocator, stream, tree, indent, start_col, use_decl.expr, .None);215 try renderExpression(allocator, ais, tree, use_decl.expr, .None);
254 try renderToken(tree, stream, use_decl.semicolon_token, indent, start_col, space); // ;216 try renderToken(tree, ais, 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.getDocComments(), indent, start_col);222 try renderDocComments(tree, ais, var_decl, var_decl.getDocComments());
261 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);223 try renderVarDecl(allocator, ais, 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, ais, test_decl, test_decl.doc_comments);
268 try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);230 try renderToken(tree, ais, test_decl.test_token, .Space);
269 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);231 try renderExpression(allocator, ais, tree, test_decl.name, .Space);
270 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space);232 try renderExpression(allocator, ais, 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, ais, 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, ais, 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, ais, 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, ais, field.name_token, .None); // name
294 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // :256 try renderToken(tree, ais, 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, ais, 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, ais, align_kw, .None); // align
302 try renderToken(tree, stream, lparen_token, indent, start_col, .None); // (264 try renderToken(tree, ais, lparen_token, .None); // (
303 try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment265 try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment
304 try renderToken(tree, stream, rparen_token, indent, start_col, last_token_space); // )266 try renderToken(tree, ais, 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, ais, 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, ais, field.name_token, .Space); // name
310 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // =272 try renderToken(tree, ais, 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, ais, 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, ais, field.name_token, .None); // name
314 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // :276 try renderToken(tree, ais, 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, ais, 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, ais, align_kw, .None); // align
322 try renderToken(tree, stream, lparen_token, indent, start_col, .None); // (284 try renderToken(tree, ais, lparen_token, .None); // (
323 try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment285 try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment
324 try renderToken(tree, stream, rparen_token, indent, start_col, .Space); // )286 try renderToken(tree, ais, rparen_token, .Space); // )
325 } else {287 } else {
326 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type288 try renderExpression(allocator, ais, 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, ais, 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, ais, 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, ais, 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, ais, 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, ais, 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, ais, 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 {
...@@ -363,13 +324,11 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr...@@ -363,13 +324,11 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
363324
364fn renderExpression(325fn renderExpression(
365 allocator: *mem.Allocator,326 allocator: *mem.Allocator,
366 stream: anytype,327 ais: 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(ais.*).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, ais, 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 ais.writer().writeAll("anytype");
394 if (space == .Comma) try stream.writeAll(",\n");353 if (space == .Comma) try ais.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, ais, 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, ais, label, Space.None);
428 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);387 try renderToken(tree, ais, 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 ais.pushIndentNextLine();
433 return renderToken(tree, stream, block.rbrace, indent, start_col, space);392 defer ais.popIndent();
393 try renderToken(tree, ais, block.lbrace, Space.None);
434 } else {394 } else {
435 const block_indent = indent + indent_delta;395 ais.pushIndentNextLine();
436 try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);396 defer ais.popIndent();
397
398 try renderToken(tree, ais, 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, ais, 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, ais, 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, ais, 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, ais, 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, ais, tree, payload, Space.Space);
458 }417 }
459 return renderExpression(allocator, stream, tree, indent, start_col, defer_node.expr, space);418 return renderExpression(allocator, ais, 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, ais, comptime_node.comptime_token, Space.Space);
465 return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);424 return renderExpression(allocator, ais, 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 ais.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, ais, 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, ais, 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, ais, suspend_node.suspend_token, Space.Space);
483 return renderExpression(allocator, stream, tree, indent, start_col, body, space);442 return renderExpression(allocator, ais, tree, body, space);
484 } else {443 } else {
485 return renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, space);444 return renderToken(tree, ais, 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, ais, 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, ais, 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, ais, tree, payload, Space.Space);
510 }463 }
511464
512 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);465 ais.pushIndentOneShot();
466 return renderExpression(allocator, ais, 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, ais, 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, ais, infix_op_node.op_token, after_op_space);
572 if (after_op_space == Space.Newline and526 ais.pushIndentOneShot();
573 tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine)527 return renderExpression(allocator, ais, 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, ais, casted_node.op_token, Space.None);
591 return renderExpression(allocator, stream, tree, indent, start_col, casted_node.rhs, space);539 return renderExpression(allocator, ais, tree, casted_node.rhs, space);
592 },540 },
593541
594 .Try,542 .Try,
...@@ -596,18 +544,16 @@ fn renderExpression(...@@ -596,18 +544,16 @@ 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, ais, casted_node.op_token, Space.Space);
600 return renderExpression(allocator, stream, tree, indent, start_col, casted_node.rhs, space);548 return renderExpression(allocator, ais, tree, casted_node.rhs, space);
601 },549 },
602550
603 .ArrayType => {551 .ArrayType => {
604 const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base);552 const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base);
605 return renderArrayType(553 return renderArrayType(
606 allocator,554 allocator,
607 stream,555 ais,
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,
...@@ -619,10 +565,8 @@ fn renderExpression(...@@ -619,10 +565,8 @@ fn renderExpression(
619 const array_type = @fieldParentPtr(ast.Node.ArrayTypeSentinel, "base", base);565 const array_type = @fieldParentPtr(ast.Node.ArrayTypeSentinel, "base", base);
620 return renderArrayType(566 return renderArrayType(
621 allocator,567 allocator,
622 stream,568 ais,
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 ais.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 ais.writer().writeAll("[*c")
641 else585 else
642 try stream.writeAll("[*"),586 try ais.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, ais, 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, ais, 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 ais.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, ais, 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, ais, align_token, Space.None); // align
667 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (611 try renderToken(tree, ais, lparen_token, Space.None); // (
668612
669 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);613 try renderExpression(allocator, ais, 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, ais, colon1, Space.None); // :
676 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);620 try renderExpression(allocator, ais, tree, bit_range.start, Space.None);
677 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :621 try renderToken(tree, ais, colon2, Space.None); // :
678 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);622 try renderExpression(allocator, ais, 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, ais, 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, ais, 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, ais, 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, ais, volatile_token, Space.Space); // volatile
692 }636 }
693 return renderExpression(allocator, stream, tree, indent, start_col, ptr_type.rhs, space);637 return renderExpression(allocator, ais, 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, ais, 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, ais, colon_token, Space.None); // :
702 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);646 try renderExpression(allocator, ais, tree, sentinel, Space.None);
703 try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), indent, start_col, Space.None); // ]647 try renderToken(tree, ais, 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, ais, 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, ais, 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, ais, align_token, Space.None); // align
716 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (660 try renderToken(tree, ais, lparen_token, Space.None); // (
717661
718 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);662 try renderExpression(allocator, ais, 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, ais, colon1, Space.None); // :
725 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);669 try renderExpression(allocator, ais, tree, bit_range.start, Space.None);
726 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :670 try renderToken(tree, ais, colon2, Space.None); // :
727 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);671 try renderExpression(allocator, ais, 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, ais, 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, ais, 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, ais, 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, ais, volatile_token, Space.Space);
741 }685 }
742 return renderExpression(allocator, stream, tree, indent, start_col, slice_type.rhs, space);686 return renderExpression(allocator, ais, 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, ais, dot, Space.None),
772 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),716 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
717 }
718
719 {
720 ais.pushIndent();
721 defer ais.popIndent();
722 try renderToken(tree, ais, 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, ais, 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, ais, dot, Space.None),
782 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),732 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
783 }733 }
784 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);734 try renderToken(tree, ais, lbrace, Space.None);
785 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);735 try renderExpression(allocator, ais, tree, expr, Space.None);
786 return renderToken(tree, stream, rtoken, indent, start_col, space);736 return renderToken(tree, ais, 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, ais, dot, Space.None),
791 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),741 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
792 }742 }
793743
794 // scan to find row size744 // scan to find row size
...@@ -830,79 +780,70 @@ fn renderExpression(...@@ -830,79 +780,70 @@ fn renderExpression(
830 var expr_widths = widths[0 .. widths.len - row_size];780 var expr_widths = widths[0 .. widths.len - row_size];
831 var column_widths = widths[widths.len - row_size ..];781 var column_widths = widths[widths.len - row_size ..];
832782
833 // Null stream for counting the printed length of each expression783 // Null ais 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.writer());
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 ais.pushIndentNextLine();
798 defer ais.popIndent();
799 try renderToken(tree, ais, 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, ais, 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, ais, 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 ais.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, ais, comma, Space.Newline); // ,
872 }822 } else {
873 col = 1;823 try renderToken(tree, ais, comma, Space.None); // ,
824 }
874825
875 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {826 try renderExtraNewline(tree, ais, 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, ais, 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, ais, 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, ais, 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, ais, 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, ais, comma, Space.Space); // ,
900 } else {841 } else {
901 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.Space);842 try renderExpression(allocator, ais, tree, expr, Space.Space);
902 }843 }
903 }844 }
904845
905 return renderToken(tree, stream, rtoken, indent, start_col, space);846 return renderToken(tree, ais, 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, ais, dot, Space.None),
936 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),877 .node => |node| try renderExpression(allocator, ais, 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 ais.pushIndentNextLine();
882 defer ais.popIndent();
883 try renderToken(tree, ais, lbrace, Space.None);
884 }
885
886 return renderToken(tree, ais, 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.writer());
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, ais, dot, Space.None),
981 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),928 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
982 }929 }
983 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);930 try renderToken(tree, ais, lbrace, Space.Space);
984 try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space);931 try renderExpression(allocator, ais, tree, &field_init.base, Space.Space);
985 return renderToken(tree, stream, rtoken, indent, start_col, space);932 return renderToken(tree, ais, 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, ais, dot, Space.None),
992 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),939 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
993 }940 }
994 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);941 try renderToken(tree, ais, 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, ais, 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, ais, comma, Space.Space);
1002 } else {949 } else {
1003 try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.Space);950 try renderExpression(allocator, ais, tree, field_init, Space.Space);
1004 }951 }
1005 }952 }
1006953
1007 return renderToken(tree, stream, rtoken, indent, start_col, space);954 return renderToken(tree, ais, rtoken, space);
1008 }955 }
1009956
1010 const new_indent = indent + indent_delta;957 {
958 switch (lhs) {
959 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
960 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
961 }
1011962
1012 switch (lhs) {963 ais.pushIndentNextLine();
1013 .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None),964 defer ais.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, ais, 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, ais, 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, ais, comma, Space.Newline);
1026975
1027 try renderExtraNewline(tree, stream, start_col, field_inits[i + 1]);976 try renderExtraNewline(tree, ais, 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, ais, tree, field_init, Space.Comma);
979 }
1030 }980 }
1031 }981 }
1032982
1033 try stream.writeByteNTimes(' ', indent);983 return renderToken(tree, ais, 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, ais, async_token, Space.Space);
1041 }990 }
1042991
1043 try renderExpression(allocator, stream, tree, indent, start_col, call.lhs, Space.None);992 try renderExpression(allocator, ais, 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, ais, lparen, Space.None);
1049 return renderToken(tree, stream, call.rtoken, indent, start_col, space);998 return renderToken(tree, ais, 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, ais, 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 ais.pushIndent();
1064 break :blk indent;1012 defer ais.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, ais, 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, ais, comma, Space.Newline); // ,
1074 try renderExtraNewline(tree, stream, start_col, params[i + 1]);1019 try renderExtraNewline(tree, ais, 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, ais, 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, ais, call.rtoken, space);
1081 }1025 }
10821026
1083 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1027 try renderToken(tree, ais, 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) ais.pushIndentOneShot();
1032
1033 try renderExpression(allocator, ais, 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, ais, comma, Space.Space);
1092 }1039 }
1093 }1040 }
1094 return renderToken(tree, stream, call.rtoken, indent, start_col, space);1041 return renderToken(tree, ais, 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, ais, tree, suffix_op.lhs, Space.None);
1104 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [1051 try renderToken(tree, ais, 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 ais.pushIndent();
1112 try stream.writeByte('\n');1059 defer ais.popIndent();
1113 }1060 try renderExpression(allocator, ais, 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 ais.maybeInsertNewline();
1063 return renderToken(tree, ais, 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, ais, 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, ais, lbracket, Space.None); // [
1133 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.start, after_start_space);1079 try renderExpression(allocator, ais, tree, suffix_op.start, after_start_space);
1134 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..1080 try renderToken(tree, ais, 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, ais, 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, ais, colon, Space.None); // :
1142 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);1088 try renderExpression(allocator, ais, tree, sentinel, Space.None);
1143 }1089 }
1144 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]1090 return renderToken(tree, ais, 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, ais, tree, suffix_op.lhs, Space.None);
1150 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*1097 return renderToken(tree, ais, 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, ais, 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, ais, tree.prevToken(suffix_op.rtoken), Space.None); // .
1157 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?1104 return renderToken(tree, ais, 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, ais, 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, ais, 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, ais, 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, ais, label, space); // label
1176 }1123 }
1177 try renderToken(tree, stream, label, indent, start_col, Space.Space); // label1124 try renderToken(tree, ais, label, Space.Space); // label
1178 }1125 }
1179 return renderExpression(allocator, stream, tree, indent, start_col, maybe_rhs.?, space);1126 return renderExpression(allocator, ais, 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, ais, 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, ais, colon, Space.None); // :
1188 return renderToken(tree, stream, label, indent, start_col, space); // label1135 return renderToken(tree, ais, label, space); // label
1189 } else {1136 } else {
1190 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // continue1137 return renderToken(tree, ais, 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, ais, flow_expr.ltoken, Space.Space);
1198 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);1145 return renderExpression(allocator, ais, tree, rhs, space);
1199 } else {1146 } else {
1200 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space);1147 return renderToken(tree, ais, 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, ais, payload.lpipe, Space.None);
1208 try renderExpression(allocator, stream, tree, indent, start_col, payload.error_symbol, Space.None);1155 try renderExpression(allocator, ais, tree, payload.error_symbol, Space.None);
1209 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);1156 return renderToken(tree, ais, 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, ais, 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, ais, ptr_token, Space.None);
1218 }1165 }
1219 try renderExpression(allocator, stream, tree, indent, start_col, payload.value_symbol, Space.None);1166 try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None);
1220 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);1167 return renderToken(tree, ais, 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, ais, 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, ais, ptr_token, Space.None);
1229 }1176 }
1230 try renderExpression(allocator, stream, tree, indent, start_col, payload.value_symbol, Space.None);1177 try renderExpression(allocator, ais, 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, ais, comma, Space.Space);
1236 try renderExpression(allocator, stream, tree, indent, start_col, index_symbol, Space.None);1183 try renderExpression(allocator, ais, tree, index_symbol, Space.None);
1237 }1184 }
12381185
1239 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);1186 return renderToken(tree, ais, 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, ais, 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 ais.pushIndentOneShot();
1195 try renderExpression(allocator, ais, tree, grouped_expr.expr, Space.None);
1196 }
1197 return renderToken(tree, ais, 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, ais, field_init.period_token, Space.None); // .
1254 try renderToken(tree, stream, field_init.name_token, indent, start_col, Space.Space); // name1204 try renderToken(tree, ais, 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, ais, 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, ais, 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, ais, 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, ais, 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, ais, 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, ais, lparen, Space.None); // (
1277 try renderToken(tree, stream, enum_token, indent, start_col, Space.None); // enum1227 try renderToken(tree, ais, 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, ais, tree.nextToken(enum_token), Space.None); // (
1281 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);1231 try renderExpression(allocator, ais, 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, ais, rparen, Space.None); // )
1285 try renderToken(tree, stream, tree.nextToken(rparen), indent, start_col, Space.Space); // )1235 try renderToken(tree, ais, 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, ais, 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, ais, 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, ais, lparen, Space.None); // (
1297 try renderExpression(allocator, stream, tree, indent, start_col, type_expr, Space.None);1247 try renderExpression(allocator, ais, tree, type_expr, Space.None);
1298 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1248 try renderToken(tree, ais, 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 ais.pushIndentNextLine();
1255 defer ais.popIndent();
1256 try renderToken(tree, ais, container_decl.lbrace_token, Space.None); // {
1257 }
1258 return renderToken(tree, ais, 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 ais.pushIndentNextLine();
1336 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // {1290 defer ais.popIndent();
1291 try renderToken(tree, ais, 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, ais, 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, ais, 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, ais, container_decl.lbrace_token, .Newline); // {
13521304
1353 const new_indent = indent + indent_delta;1305 ais.pushIndent();
1354 try stream.writeByteNTimes(' ', new_indent);1306 defer ais.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, ais, 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, ais, 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, ais, 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, ais, 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, ais, err_set_decl.error_token, Space.None);
1381 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);1331 try renderToken(tree, ais, lbrace, Space.None);
1382 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);1332 return renderToken(tree, ais, 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, ais, err_set_decl.error_token, Space.None); // error
1397 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {1347 try renderToken(tree, ais, lbrace, Space.None); // {
1398 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);1348 try renderExpression(allocator, ais, tree, node, Space.None);
1399 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }1349 return renderToken(tree, ais, 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, ais, 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,72 +1357,66 @@ fn renderExpression(...@@ -1407,72 +1357,66 @@ 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 ais.pushIndent();
14121362 defer ais.popIndent();
1413 const decls = err_set_decl.decls();1363
1414 for (decls) |node, i| {1364 try renderToken(tree, ais, 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, ais, tree, node, Space.None);
1419 try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // ,1369 try renderToken(tree, ais, tree.nextToken(node.lastToken()), Space.Newline); // ,
14201370
1421 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);1371 try renderExtraNewline(tree, ais, decls[i + 1]);
1422 } else {1372 } else {
1423 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);1373 try renderExpression(allocator, ais, tree, node, Space.Comma);
1374 }
1424 }1375 }
1425 }1376 }
14261377
1427 try stream.writeByteNTimes(' ', indent);1378 return renderToken(tree, ais, 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, ais, 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, ais, 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, ais, comma_token, Space.Space); // ,
1440 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);1390 try renderExtraNewline(tree, ais, decls[i + 1]);
1441 } else {1391 } else {
1442 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);1392 try renderExpression(allocator, ais, 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, ais, 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, ais, tag, tag.doc_comments);
1454 return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name1404 return renderToken(tree, ais, 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 = ais.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) ais.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 ais.maybeInsertNewline();
1473 skip_first_indent = false;1417
1418 for (multiline_str_literal.lines()) |t| try renderToken(tree, ais, t, Space.None);
1474 }1419 }
1475 try stream.writeByteNTimes(' ', indent);
1476 },1420 },
14771421
1478 .BuiltinCall => {1422 .BuiltinCall => {
...@@ -1480,9 +1424,9 @@ fn renderExpression(...@@ -1480,9 +1424,9 @@ fn renderExpression(
14801424
1481 // TODO remove after 0.7.0 release1425 // TODO remove after 0.7.0 release
1482 if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))1426 if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))
1483 return stream.writeAll("@Type(.Opaque)");1427 return ais.writer().writeAll("@Type(.Opaque)");
14841428
1485 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name1429 try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
14861430
1487 const src_params_trailing_comma = blk: {1431 const src_params_trailing_comma = blk: {
1488 if (builtin_call.params_len < 2) break :blk false;1432 if (builtin_call.params_len < 2) break :blk false;
...@@ -1494,31 +1438,30 @@ fn renderExpression(...@@ -1494,31 +1438,30 @@ fn renderExpression(
1494 const lparen = tree.nextToken(builtin_call.builtin_token);1438 const lparen = tree.nextToken(builtin_call.builtin_token);
14951439
1496 if (!src_params_trailing_comma) {1440 if (!src_params_trailing_comma) {
1497 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1441 try renderToken(tree, ais, lparen, Space.None); // (
14981442
1499 // render all on one line, no trailing comma1443 // render all on one line, no trailing comma
1500 const params = builtin_call.params();1444 const params = builtin_call.params();
1501 for (params) |param_node, i| {1445 for (params) |param_node, i| {
1502 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);1446 try renderExpression(allocator, ais, tree, param_node, Space.None);
15031447
1504 if (i + 1 < params.len) {1448 if (i + 1 < params.len) {
1505 const comma_token = tree.nextToken(param_node.lastToken());1449 const comma_token = tree.nextToken(param_node.lastToken());
1506 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1450 try renderToken(tree, ais, comma_token, Space.Space); // ,
1507 }1451 }
1508 }1452 }
1509 } else {1453 } else {
1510 // one param per line1454 // one param per line
1511 const new_indent = indent + indent_delta;1455 ais.pushIndent();
1512 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (1456 defer ais.popIndent();
1457 try renderToken(tree, ais, lparen, Space.Newline); // (
15131458
1514 for (builtin_call.params()) |param_node| {1459 for (builtin_call.params()) |param_node| {
1515 try stream.writeByteNTimes(' ', new_indent);1460 try renderExpression(allocator, ais, tree, param_node, Space.Comma);
1516 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);
1517 }1461 }
1518 try stream.writeByteNTimes(' ', indent);
1519 }1462 }
15201463
1521 return renderToken(tree, stream, builtin_call.rparen_token, indent, start_col, space); // )1464 return renderToken(tree, ais, builtin_call.rparen_token, space); // )
1522 },1465 },
15231466
1524 .FnProto => {1467 .FnProto => {
...@@ -1528,24 +1471,24 @@ fn renderExpression(...@@ -1528,24 +1471,24 @@ fn renderExpression(
1528 const visib_token = tree.token_ids[visib_token_index];1471 const visib_token = tree.token_ids[visib_token_index];
1529 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);1472 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
15301473
1531 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub1474 try renderToken(tree, ais, visib_token_index, Space.Space); // pub
1532 }1475 }
15331476
1534 if (fn_proto.getExternExportInlineToken()) |extern_export_inline_token| {1477 if (fn_proto.getExternExportInlineToken()) |extern_export_inline_token| {
1535 if (fn_proto.getIsExternPrototype() == null)1478 if (fn_proto.getIsExternPrototype() == null)
1536 try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline1479 try renderToken(tree, ais, extern_export_inline_token, Space.Space); // extern/export/inline
1537 }1480 }
15381481
1539 if (fn_proto.getLibName()) |lib_name| {1482 if (fn_proto.getLibName()) |lib_name| {
1540 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);1483 try renderExpression(allocator, ais, tree, lib_name, Space.Space);
1541 }1484 }
15421485
1543 const lparen = if (fn_proto.getNameToken()) |name_token| blk: {1486 const lparen = if (fn_proto.getNameToken()) |name_token| blk: {
1544 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn1487 try renderToken(tree, ais, fn_proto.fn_token, Space.Space); // fn
1545 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name1488 try renderToken(tree, ais, name_token, Space.None); // name
1546 break :blk tree.nextToken(name_token);1489 break :blk tree.nextToken(name_token);
1547 } else blk: {1490 } else blk: {
1548 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn1491 try renderToken(tree, ais, fn_proto.fn_token, Space.Space); // fn
1549 break :blk tree.nextToken(fn_proto.fn_token);1492 break :blk tree.nextToken(fn_proto.fn_token);
1550 };1493 };
1551 assert(tree.token_ids[lparen] == .LParen);1494 assert(tree.token_ids[lparen] == .LParen);
...@@ -1572,47 +1515,45 @@ fn renderExpression(...@@ -1572,47 +1515,45 @@ fn renderExpression(
1572 };1515 };
15731516
1574 if (!src_params_trailing_comma) {1517 if (!src_params_trailing_comma) {
1575 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1518 try renderToken(tree, ais, lparen, Space.None); // (
15761519
1577 // render all on one line, no trailing comma1520 // render all on one line, no trailing comma
1578 for (fn_proto.params()) |param_decl, i| {1521 for (fn_proto.params()) |param_decl, i| {
1579 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);1522 try renderParamDecl(allocator, ais, tree, param_decl, Space.None);
15801523
1581 if (i + 1 < fn_proto.params_len or fn_proto.getVarArgsToken() != null) {1524 if (i + 1 < fn_proto.params_len or fn_proto.getVarArgsToken() != null) {
1582 const comma = tree.nextToken(param_decl.lastToken());1525 const comma = tree.nextToken(param_decl.lastToken());
1583 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,1526 try renderToken(tree, ais, comma, Space.Space); // ,
1584 }1527 }
1585 }1528 }
1586 if (fn_proto.getVarArgsToken()) |var_args_token| {1529 if (fn_proto.getVarArgsToken()) |var_args_token| {
1587 try renderToken(tree, stream, var_args_token, indent, start_col, Space.None);1530 try renderToken(tree, ais, var_args_token, Space.None);
1588 }1531 }
1589 } else {1532 } else {
1590 // one param per line1533 // one param per line
1591 const new_indent = indent + indent_delta;1534 ais.pushIndent();
1592 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (1535 defer ais.popIndent();
1536 try renderToken(tree, ais, lparen, Space.Newline); // (
15931537
1594 for (fn_proto.params()) |param_decl| {1538 for (fn_proto.params()) |param_decl| {
1595 try stream.writeByteNTimes(' ', new_indent);1539 try renderParamDecl(allocator, ais, tree, param_decl, Space.Comma);
1596 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
1597 }1540 }
1598 if (fn_proto.getVarArgsToken()) |var_args_token| {1541 if (fn_proto.getVarArgsToken()) |var_args_token| {
1599 try stream.writeByteNTimes(' ', new_indent);1542 try renderToken(tree, ais, var_args_token, Space.Comma);
1600 try renderToken(tree, stream, var_args_token, new_indent, start_col, Space.Comma);
1601 }1543 }
1602 try stream.writeByteNTimes(' ', indent);
1603 }1544 }
16041545
1605 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1546 try renderToken(tree, ais, rparen, Space.Space); // )
16061547
1607 if (fn_proto.getAlignExpr()) |align_expr| {1548 if (fn_proto.getAlignExpr()) |align_expr| {
1608 const align_rparen = tree.nextToken(align_expr.lastToken());1549 const align_rparen = tree.nextToken(align_expr.lastToken());
1609 const align_lparen = tree.prevToken(align_expr.firstToken());1550 const align_lparen = tree.prevToken(align_expr.firstToken());
1610 const align_kw = tree.prevToken(align_lparen);1551 const align_kw = tree.prevToken(align_lparen);
16111552
1612 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align1553 try renderToken(tree, ais, align_kw, Space.None); // align
1613 try renderToken(tree, stream, align_lparen, indent, start_col, Space.None); // (1554 try renderToken(tree, ais, align_lparen, Space.None); // (
1614 try renderExpression(allocator, stream, tree, indent, start_col, align_expr, Space.None);1555 try renderExpression(allocator, ais, tree, align_expr, Space.None);
1615 try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )1556 try renderToken(tree, ais, align_rparen, Space.Space); // )
1616 }1557 }
16171558
1618 if (fn_proto.getSectionExpr()) |section_expr| {1559 if (fn_proto.getSectionExpr()) |section_expr| {
...@@ -1620,10 +1561,10 @@ fn renderExpression(...@@ -1620,10 +1561,10 @@ fn renderExpression(
1620 const section_lparen = tree.prevToken(section_expr.firstToken());1561 const section_lparen = tree.prevToken(section_expr.firstToken());
1621 const section_kw = tree.prevToken(section_lparen);1562 const section_kw = tree.prevToken(section_lparen);
16221563
1623 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // section1564 try renderToken(tree, ais, section_kw, Space.None); // section
1624 try renderToken(tree, stream, section_lparen, indent, start_col, Space.None); // (1565 try renderToken(tree, ais, section_lparen, Space.None); // (
1625 try renderExpression(allocator, stream, tree, indent, start_col, section_expr, Space.None);1566 try renderExpression(allocator, ais, tree, section_expr, Space.None);
1626 try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )1567 try renderToken(tree, ais, section_rparen, Space.Space); // )
1627 }1568 }
16281569
1629 if (fn_proto.getCallconvExpr()) |callconv_expr| {1570 if (fn_proto.getCallconvExpr()) |callconv_expr| {
...@@ -1631,23 +1572,23 @@ fn renderExpression(...@@ -1631,23 +1572,23 @@ fn renderExpression(
1631 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());1572 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
1632 const callconv_kw = tree.prevToken(callconv_lparen);1573 const callconv_kw = tree.prevToken(callconv_lparen);
16331574
1634 try renderToken(tree, stream, callconv_kw, indent, start_col, Space.None); // callconv1575 try renderToken(tree, ais, callconv_kw, Space.None); // callconv
1635 try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (1576 try renderToken(tree, ais, callconv_lparen, Space.None); // (
1636 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);1577 try renderExpression(allocator, ais, tree, callconv_expr, Space.None);
1637 try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )1578 try renderToken(tree, ais, callconv_rparen, Space.Space); // )
1638 } else if (fn_proto.getIsExternPrototype() != null) {1579 } else if (fn_proto.getIsExternPrototype() != null) {
1639 try stream.writeAll("callconv(.C) ");1580 try ais.writer().writeAll("callconv(.C) ");
1640 } else if (fn_proto.getIsAsync() != null) {1581 } else if (fn_proto.getIsAsync() != null) {
1641 try stream.writeAll("callconv(.Async) ");1582 try ais.writer().writeAll("callconv(.Async) ");
1642 }1583 }
16431584
1644 switch (fn_proto.return_type) {1585 switch (fn_proto.return_type) {
1645 .Explicit => |node| {1586 .Explicit => |node| {
1646 return renderExpression(allocator, stream, tree, indent, start_col, node, space);1587 return renderExpression(allocator, ais, tree, node, space);
1647 },1588 },
1648 .InferErrorSet => |node| {1589 .InferErrorSet => |node| {
1649 try renderToken(tree, stream, tree.prevToken(node.firstToken()), indent, start_col, Space.None); // !1590 try renderToken(tree, ais, tree.prevToken(node.firstToken()), Space.None); // !
1650 return renderExpression(allocator, stream, tree, indent, start_col, node, space);1591 return renderExpression(allocator, ais, tree, node, space);
1651 },1592 },
1652 .Invalid => unreachable,1593 .Invalid => unreachable,
1653 }1594 }
...@@ -1657,11 +1598,11 @@ fn renderExpression(...@@ -1657,11 +1598,11 @@ fn renderExpression(
1657 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);1598 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
16581599
1659 if (anyframe_type.result) |result| {1600 if (anyframe_type.result) |result| {
1660 try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe1601 try renderToken(tree, ais, anyframe_type.anyframe_token, Space.None); // anyframe
1661 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->1602 try renderToken(tree, ais, result.arrow_token, Space.None); // ->
1662 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);1603 return renderExpression(allocator, ais, tree, result.return_type, space);
1663 } else {1604 } else {
1664 return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe1605 return renderToken(tree, ais, anyframe_type.anyframe_token, space); // anyframe
1665 }1606 }
1666 },1607 },
16671608
...@@ -1670,38 +1611,38 @@ fn renderExpression(...@@ -1670,38 +1611,38 @@ fn renderExpression(
1670 .Switch => {1611 .Switch => {
1671 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);1612 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
16721613
1673 try renderToken(tree, stream, switch_node.switch_token, indent, start_col, Space.Space); // switch1614 try renderToken(tree, ais, switch_node.switch_token, Space.Space); // switch
1674 try renderToken(tree, stream, tree.nextToken(switch_node.switch_token), indent, start_col, Space.None); // (1615 try renderToken(tree, ais, tree.nextToken(switch_node.switch_token), Space.None); // (
16751616
1676 const rparen = tree.nextToken(switch_node.expr.lastToken());1617 const rparen = tree.nextToken(switch_node.expr.lastToken());
1677 const lbrace = tree.nextToken(rparen);1618 const lbrace = tree.nextToken(rparen);
16781619
1679 if (switch_node.cases_len == 0) {1620 if (switch_node.cases_len == 0) {
1680 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);1621 try renderExpression(allocator, ais, tree, switch_node.expr, Space.None);
1681 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1622 try renderToken(tree, ais, rparen, Space.Space); // )
1682 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {1623 try renderToken(tree, ais, lbrace, Space.None); // {
1683 return renderToken(tree, stream, switch_node.rbrace, indent, start_col, space); // }1624 return renderToken(tree, ais, switch_node.rbrace, space); // }
1684 }1625 }
16851626
1686 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);1627 try renderExpression(allocator, ais, tree, switch_node.expr, Space.None);
16871628 try renderToken(tree, ais, rparen, Space.Space); // )
1688 const new_indent = indent + indent_delta;
16891629
1690 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1630 {
1691 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {1631 ais.pushIndentNextLine();
1632 defer ais.popIndent();
1633 try renderToken(tree, ais, lbrace, Space.Newline); // {
16921634
1693 const cases = switch_node.cases();1635 const cases = switch_node.cases();
1694 for (cases) |node, i| {1636 for (cases) |node, i| {
1695 try stream.writeByteNTimes(' ', new_indent);1637 try renderExpression(allocator, ais, tree, node, Space.Comma);
1696 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
16971638
1698 if (i + 1 < cases.len) {1639 if (i + 1 < cases.len) {
1699 try renderExtraNewline(tree, stream, start_col, cases[i + 1]);1640 try renderExtraNewline(tree, ais, cases[i + 1]);
1641 }
1700 }1642 }
1701 }1643 }
17021644
1703 try stream.writeByteNTimes(' ', indent);1645 return renderToken(tree, ais, switch_node.rbrace, space); // }
1704 return renderToken(tree, stream, switch_node.rbrace, indent, start_col, space); // }
1705 },1646 },
17061647
1707 .SwitchCase => {1648 .SwitchCase => {
...@@ -1718,43 +1659,41 @@ fn renderExpression(...@@ -1718,43 +1659,41 @@ fn renderExpression(
1718 const items = switch_case.items();1659 const items = switch_case.items();
1719 for (items) |node, i| {1660 for (items) |node, i| {
1720 if (i + 1 < items.len) {1661 if (i + 1 < items.len) {
1721 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);1662 try renderExpression(allocator, ais, tree, node, Space.None);
17221663
1723 const comma_token = tree.nextToken(node.lastToken());1664 const comma_token = tree.nextToken(node.lastToken());
1724 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1665 try renderToken(tree, ais, comma_token, Space.Space); // ,
1725 try renderExtraNewline(tree, stream, start_col, items[i + 1]);1666 try renderExtraNewline(tree, ais, items[i + 1]);
1726 } else {1667 } else {
1727 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);1668 try renderExpression(allocator, ais, tree, node, Space.Space);
1728 }1669 }
1729 }1670 }
1730 } else {1671 } else {
1731 const items = switch_case.items();1672 const items = switch_case.items();
1732 for (items) |node, i| {1673 for (items) |node, i| {
1733 if (i + 1 < items.len) {1674 if (i + 1 < items.len) {
1734 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);1675 try renderExpression(allocator, ais, tree, node, Space.None);
17351676
1736 const comma_token = tree.nextToken(node.lastToken());1677 const comma_token = tree.nextToken(node.lastToken());
1737 try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // ,1678 try renderToken(tree, ais, comma_token, Space.Newline); // ,
1738 try renderExtraNewline(tree, stream, start_col, items[i + 1]);1679 try renderExtraNewline(tree, ais, items[i + 1]);
1739 try stream.writeByteNTimes(' ', indent);
1740 } else {1680 } else {
1741 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Comma);1681 try renderExpression(allocator, ais, tree, node, Space.Comma);
1742 try stream.writeByteNTimes(' ', indent);
1743 }1682 }
1744 }1683 }
1745 }1684 }
17461685
1747 try renderToken(tree, stream, switch_case.arrow_token, indent, start_col, Space.Space); // =>1686 try renderToken(tree, ais, switch_case.arrow_token, Space.Space); // =>
17481687
1749 if (switch_case.payload) |payload| {1688 if (switch_case.payload) |payload| {
1750 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);1689 try renderExpression(allocator, ais, tree, payload, Space.Space);
1751 }1690 }
17521691
1753 return renderExpression(allocator, stream, tree, indent, start_col, switch_case.expr, space);1692 return renderExpression(allocator, ais, tree, switch_case.expr, space);
1754 },1693 },
1755 .SwitchElse => {1694 .SwitchElse => {
1756 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);1695 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
1757 return renderToken(tree, stream, switch_else.token, indent, start_col, space);1696 return renderToken(tree, ais, switch_else.token, space);
1758 },1697 },
1759 .Else => {1698 .Else => {
1760 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);1699 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
...@@ -1763,37 +1702,37 @@ fn renderExpression(...@@ -1763,37 +1702,37 @@ fn renderExpression(
1763 const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken());1702 const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken());
17641703
1765 const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline;1704 const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline;
1766 try renderToken(tree, stream, else_node.else_token, indent, start_col, after_else_space);1705 try renderToken(tree, ais, else_node.else_token, after_else_space);
17671706
1768 if (else_node.payload) |payload| {1707 if (else_node.payload) |payload| {
1769 const payload_space = if (same_line) Space.Space else Space.Newline;1708 const payload_space = if (same_line) Space.Space else Space.Newline;
1770 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);1709 try renderExpression(allocator, ais, tree, payload, payload_space);
1771 }1710 }
17721711
1773 if (same_line) {1712 if (same_line) {
1774 return renderExpression(allocator, stream, tree, indent, start_col, else_node.body, space);1713 return renderExpression(allocator, ais, tree, else_node.body, space);
1714 } else {
1715 ais.pushIndent();
1716 defer ais.popIndent();
1717 return renderExpression(allocator, ais, tree, else_node.body, space);
1775 }1718 }
1776
1777 try stream.writeByteNTimes(' ', indent + indent_delta);
1778 start_col.* = indent + indent_delta;
1779 return renderExpression(allocator, stream, tree, indent, start_col, else_node.body, space);
1780 },1719 },
17811720
1782 .While => {1721 .While => {
1783 const while_node = @fieldParentPtr(ast.Node.While, "base", base);1722 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
17841723
1785 if (while_node.label) |label| {1724 if (while_node.label) |label| {
1786 try renderToken(tree, stream, label, indent, start_col, Space.None); // label1725 try renderToken(tree, ais, label, Space.None); // label
1787 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); // :1726 try renderToken(tree, ais, tree.nextToken(label), Space.Space); // :
1788 }1727 }
17891728
1790 if (while_node.inline_token) |inline_token| {1729 if (while_node.inline_token) |inline_token| {
1791 try renderToken(tree, stream, inline_token, indent, start_col, Space.Space); // inline1730 try renderToken(tree, ais, inline_token, Space.Space); // inline
1792 }1731 }
17931732
1794 try renderToken(tree, stream, while_node.while_token, indent, start_col, Space.Space); // while1733 try renderToken(tree, ais, while_node.while_token, Space.Space); // while
1795 try renderToken(tree, stream, tree.nextToken(while_node.while_token), indent, start_col, Space.None); // (1734 try renderToken(tree, ais, tree.nextToken(while_node.while_token), Space.None); // (
1796 try renderExpression(allocator, stream, tree, indent, start_col, while_node.condition, Space.None);1735 try renderExpression(allocator, ais, tree, while_node.condition, Space.None);
17971736
1798 const cond_rparen = tree.nextToken(while_node.condition.lastToken());1737 const cond_rparen = tree.nextToken(while_node.condition.lastToken());
17991738
...@@ -1815,12 +1754,12 @@ fn renderExpression(...@@ -1815,12 +1754,12 @@ fn renderExpression(
18151754
1816 {1755 {
1817 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;1756 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;
1818 try renderToken(tree, stream, cond_rparen, indent, start_col, rparen_space); // )1757 try renderToken(tree, ais, cond_rparen, rparen_space); // )
1819 }1758 }
18201759
1821 if (while_node.payload) |payload| {1760 if (while_node.payload) |payload| {
1822 const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;1761 const payload_space = Space.Space; //if (while_node.continue_expr != null) Space.Space else block_start_space;
1823 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);1762 try renderExpression(allocator, ais, tree, payload, payload_space);
1824 }1763 }
18251764
1826 if (while_node.continue_expr) |continue_expr| {1765 if (while_node.continue_expr) |continue_expr| {
...@@ -1828,29 +1767,22 @@ fn renderExpression(...@@ -1828,29 +1767,22 @@ fn renderExpression(
1828 const lparen = tree.prevToken(continue_expr.firstToken());1767 const lparen = tree.prevToken(continue_expr.firstToken());
1829 const colon = tree.prevToken(lparen);1768 const colon = tree.prevToken(lparen);
18301769
1831 try renderToken(tree, stream, colon, indent, start_col, Space.Space); // :1770 try renderToken(tree, ais, colon, Space.Space); // :
1832 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1771 try renderToken(tree, ais, lparen, Space.None); // (
18331772
1834 try renderExpression(allocator, stream, tree, indent, start_col, continue_expr, Space.None);1773 try renderExpression(allocator, ais, tree, continue_expr, Space.None);
18351774
1836 try renderToken(tree, stream, rparen, indent, start_col, block_start_space); // )1775 try renderToken(tree, ais, rparen, block_start_space); // )
1837 }1776 }
18381777
1839 var new_indent = indent;1778 {
1840 if (block_start_space == Space.Newline) {1779 if (!body_is_block) ais.pushIndent();
1841 new_indent += indent_delta;1780 defer if (!body_is_block) ais.popIndent();
1842 try stream.writeByteNTimes(' ', new_indent);1781 try renderExpression(allocator, ais, tree, while_node.body, after_body_space);
1843 start_col.* = new_indent;
1844 }1782 }
18451783
1846 try renderExpression(allocator, stream, tree, indent, start_col, while_node.body, after_body_space);
1847
1848 if (while_node.@"else") |@"else"| {1784 if (while_node.@"else") |@"else"| {
1849 if (after_body_space == Space.Newline) {1785 return renderExpression(allocator, ais, tree, &@"else".base, space);
1850 try stream.writeByteNTimes(' ', indent);
1851 start_col.* = indent;
1852 }
1853 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);
1854 }1786 }
1855 },1787 },
18561788
...@@ -1858,17 +1790,17 @@ fn renderExpression(...@@ -1858,17 +1790,17 @@ fn renderExpression(
1858 const for_node = @fieldParentPtr(ast.Node.For, "base", base);1790 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
18591791
1860 if (for_node.label) |label| {1792 if (for_node.label) |label| {
1861 try renderToken(tree, stream, label, indent, start_col, Space.None); // label1793 try renderToken(tree, ais, label, Space.None); // label
1862 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); // :1794 try renderToken(tree, ais, tree.nextToken(label), Space.Space); // :
1863 }1795 }
18641796
1865 if (for_node.inline_token) |inline_token| {1797 if (for_node.inline_token) |inline_token| {
1866 try renderToken(tree, stream, inline_token, indent, start_col, Space.Space); // inline1798 try renderToken(tree, ais, inline_token, Space.Space); // inline
1867 }1799 }
18681800
1869 try renderToken(tree, stream, for_node.for_token, indent, start_col, Space.Space); // for1801 try renderToken(tree, ais, for_node.for_token, Space.Space); // for
1870 try renderToken(tree, stream, tree.nextToken(for_node.for_token), indent, start_col, Space.None); // (1802 try renderToken(tree, ais, tree.nextToken(for_node.for_token), Space.None); // (
1871 try renderExpression(allocator, stream, tree, indent, start_col, for_node.array_expr, Space.None);1803 try renderExpression(allocator, ais, tree, for_node.array_expr, Space.None);
18721804
1873 const rparen = tree.nextToken(for_node.array_expr.lastToken());1805 const rparen = tree.nextToken(for_node.array_expr.lastToken());
18741806
...@@ -1876,10 +1808,10 @@ fn renderExpression(...@@ -1876,10 +1808,10 @@ fn renderExpression(
1876 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());1808 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
1877 const body_on_same_line = body_is_block or src_one_line_to_body;1809 const body_on_same_line = body_is_block or src_one_line_to_body;
18781810
1879 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1811 try renderToken(tree, ais, rparen, Space.Space); // )
18801812
1881 const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;1813 const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;
1882 try renderExpression(allocator, stream, tree, indent, start_col, for_node.payload, space_after_payload); // |x|1814 try renderExpression(allocator, ais, tree, for_node.payload, space_after_payload); // |x|
18831815
1884 const space_after_body = blk: {1816 const space_after_body = blk: {
1885 if (for_node.@"else") |@"else"| {1817 if (for_node.@"else") |@"else"| {
...@@ -1894,13 +1826,14 @@ fn renderExpression(...@@ -1894,13 +1826,14 @@ fn renderExpression(
1894 }1826 }
1895 };1827 };
18961828
1897 const body_indent = if (body_on_same_line) indent else indent + indent_delta;1829 {
1898 if (!body_on_same_line) try stream.writeByteNTimes(' ', body_indent);1830 if (!body_on_same_line) ais.pushIndent();
1899 try renderExpression(allocator, stream, tree, body_indent, start_col, for_node.body, space_after_body); // { body }1831 defer if (!body_on_same_line) ais.popIndent();
1832 try renderExpression(allocator, ais, tree, for_node.body, space_after_body); // { body }
1833 }
19001834
1901 if (for_node.@"else") |@"else"| {1835 if (for_node.@"else") |@"else"| {
1902 if (space_after_body == Space.Newline) try stream.writeByteNTimes(' ', indent);1836 return renderExpression(allocator, ais, tree, &@"else".base, space); // else
1903 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space); // else
1904 }1837 }
1905 },1838 },
19061839
...@@ -1910,29 +1843,29 @@ fn renderExpression(...@@ -1910,29 +1843,29 @@ fn renderExpression(
1910 const lparen = tree.nextToken(if_node.if_token);1843 const lparen = tree.nextToken(if_node.if_token);
1911 const rparen = tree.nextToken(if_node.condition.lastToken());1844 const rparen = tree.nextToken(if_node.condition.lastToken());
19121845
1913 try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if1846 try renderToken(tree, ais, if_node.if_token, Space.Space); // if
1914 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1847 try renderToken(tree, ais, lparen, Space.None); // (
19151848
1916 try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition1849 try renderExpression(allocator, ais, tree, if_node.condition, Space.None); // condition
19171850
1918 const body_is_if_block = if_node.body.tag == .If;1851 const body_is_if_block = if_node.body.tag == .If;
1919 const body_is_block = nodeIsBlock(if_node.body);1852 const body_is_block = nodeIsBlock(if_node.body);
19201853
1921 if (body_is_if_block) {1854 if (body_is_if_block) {
1922 try renderExtraNewline(tree, stream, start_col, if_node.body);1855 try renderExtraNewline(tree, ais, if_node.body);
1923 } else if (body_is_block) {1856 } else if (body_is_block) {
1924 const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;1857 const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;
1925 try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )1858 try renderToken(tree, ais, rparen, after_rparen_space); // )
19261859
1927 if (if_node.payload) |payload| {1860 if (if_node.payload) |payload| {
1928 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.BlockStart); // |x|1861 try renderExpression(allocator, ais, tree, payload, Space.BlockStart); // |x|
1929 }1862 }
19301863
1931 if (if_node.@"else") |@"else"| {1864 if (if_node.@"else") |@"else"| {
1932 try renderExpression(allocator, stream, tree, indent, start_col, if_node.body, Space.SpaceOrOutdent);1865 try renderExpression(allocator, ais, tree, if_node.body, Space.SpaceOrOutdent);
1933 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);1866 return renderExpression(allocator, ais, tree, &@"else".base, space);
1934 } else {1867 } else {
1935 return renderExpression(allocator, stream, tree, indent, start_col, if_node.body, space);1868 return renderExpression(allocator, ais, tree, if_node.body, space);
1936 }1869 }
1937 }1870 }
19381871
...@@ -1940,186 +1873,184 @@ fn renderExpression(...@@ -1940,186 +1873,184 @@ fn renderExpression(
19401873
1941 if (src_has_newline) {1874 if (src_has_newline) {
1942 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;1875 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
1943 try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )1876 try renderToken(tree, ais, rparen, after_rparen_space); // )
19441877
1945 if (if_node.payload) |payload| {1878 if (if_node.payload) |payload| {
1946 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Newline);1879 try renderExpression(allocator, ais, tree, payload, Space.Newline);
1947 }1880 }
19481881
1949 const new_indent = indent + indent_delta;
1950 try stream.writeByteNTimes(' ', new_indent);
1951
1952 if (if_node.@"else") |@"else"| {1882 if (if_node.@"else") |@"else"| {
1953 const else_is_block = nodeIsBlock(@"else".body);1883 const else_is_block = nodeIsBlock(@"else".body);
1954 try renderExpression(allocator, stream, tree, new_indent, start_col, if_node.body, Space.Newline);1884
1955 try stream.writeByteNTimes(' ', indent);1885 {
1886 ais.pushIndent();
1887 defer ais.popIndent();
1888 try renderExpression(allocator, ais, tree, if_node.body, Space.Newline);
1889 }
19561890
1957 if (else_is_block) {1891 if (else_is_block) {
1958 try renderToken(tree, stream, @"else".else_token, indent, start_col, Space.Space); // else1892 try renderToken(tree, ais, @"else".else_token, Space.Space); // else
19591893
1960 if (@"else".payload) |payload| {1894 if (@"else".payload) |payload| {
1961 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);1895 try renderExpression(allocator, ais, tree, payload, Space.Space);
1962 }1896 }
19631897
1964 return renderExpression(allocator, stream, tree, indent, start_col, @"else".body, space);1898 return renderExpression(allocator, ais, tree, @"else".body, space);
1965 } else {1899 } else {
1966 const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space;1900 const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space;
1967 try renderToken(tree, stream, @"else".else_token, indent, start_col, after_else_space); // else1901 try renderToken(tree, ais, @"else".else_token, after_else_space); // else
19681902
1969 if (@"else".payload) |payload| {1903 if (@"else".payload) |payload| {
1970 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Newline);1904 try renderExpression(allocator, ais, tree, payload, Space.Newline);
1971 }1905 }
1972 try stream.writeByteNTimes(' ', new_indent);
19731906
1974 return renderExpression(allocator, stream, tree, new_indent, start_col, @"else".body, space);1907 ais.pushIndent();
1908 defer ais.popIndent();
1909 return renderExpression(allocator, ais, tree, @"else".body, space);
1975 }1910 }
1976 } else {1911 } else {
1977 return renderExpression(allocator, stream, tree, new_indent, start_col, if_node.body, space);1912 ais.pushIndent();
1913 defer ais.popIndent();
1914 return renderExpression(allocator, ais, tree, if_node.body, space);
1978 }1915 }
1979 }1916 }
19801917
1981 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1918 // Single line if statement
1919
1920 try renderToken(tree, ais, rparen, Space.Space); // )
19821921
1983 if (if_node.payload) |payload| {1922 if (if_node.payload) |payload| {
1984 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);1923 try renderExpression(allocator, ais, tree, payload, Space.Space);
1985 }1924 }
19861925
1987 if (if_node.@"else") |@"else"| {1926 if (if_node.@"else") |@"else"| {
1988 try renderExpression(allocator, stream, tree, indent, start_col, if_node.body, Space.Space);1927 try renderExpression(allocator, ais, tree, if_node.body, Space.Space);
1989 try renderToken(tree, stream, @"else".else_token, indent, start_col, Space.Space);1928 try renderToken(tree, ais, @"else".else_token, Space.Space);
19901929
1991 if (@"else".payload) |payload| {1930 if (@"else".payload) |payload| {
1992 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);1931 try renderExpression(allocator, ais, tree, payload, Space.Space);
1993 }1932 }
19941933
1995 return renderExpression(allocator, stream, tree, indent, start_col, @"else".body, space);1934 return renderExpression(allocator, ais, tree, @"else".body, space);
1996 } else {1935 } else {
1997 return renderExpression(allocator, stream, tree, indent, start_col, if_node.body, space);1936 return renderExpression(allocator, ais, tree, if_node.body, space);
1998 }1937 }
1999 },1938 },
20001939
2001 .Asm => {1940 .Asm => {
2002 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);1941 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
20031942
2004 try renderToken(tree, stream, asm_node.asm_token, indent, start_col, Space.Space); // asm1943 try renderToken(tree, ais, asm_node.asm_token, Space.Space); // asm
20051944
2006 if (asm_node.volatile_token) |volatile_token| {1945 if (asm_node.volatile_token) |volatile_token| {
2007 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile1946 try renderToken(tree, ais, volatile_token, Space.Space); // volatile
2008 try renderToken(tree, stream, tree.nextToken(volatile_token), indent, start_col, Space.None); // (1947 try renderToken(tree, ais, tree.nextToken(volatile_token), Space.None); // (
2009 } else {1948 } else {
2010 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (1949 try renderToken(tree, ais, tree.nextToken(asm_node.asm_token), Space.None); // (
2011 }1950 }
20121951
2013 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {1952 asmblk: {
2014 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);1953 ais.pushIndent();
2015 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);1954 defer ais.popIndent();
2016 }
20171955
2018 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.Newline);1956 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1957 try renderExpression(allocator, ais, tree, asm_node.template, Space.None);
1958 break :asmblk;
1959 }
20191960
2020 const indent_once = indent + indent_delta;1961 try renderExpression(allocator, ais, tree, asm_node.template, Space.Newline);
20211962
2022 if (asm_node.template.tag == .MultilineStringLiteral) {1963 ais.setIndentDelta(asm_indent_delta);
2023 // After rendering a multiline string literal the cursor is1964 defer ais.setIndentDelta(indent_delta);
2024 // already offset by indent
2025 try stream.writeByteNTimes(' ', indent_delta);
2026 } else {
2027 try stream.writeByteNTimes(' ', indent_once);
2028 }
20291965
2030 const colon1 = tree.nextToken(asm_node.template.lastToken());1966 const colon1 = tree.nextToken(asm_node.template.lastToken());
2031 const indent_extra = indent_once + 2;
20321967
2033 const colon2 = if (asm_node.outputs.len == 0) blk: {1968 const colon2 = if (asm_node.outputs.len == 0) blk: {
2034 try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :1969 try renderToken(tree, ais, colon1, Space.Newline); // :
2035 try stream.writeByteNTimes(' ', indent_once);
20361970
2037 break :blk tree.nextToken(colon1);1971 break :blk tree.nextToken(colon1);
2038 } else blk: {1972 } else blk: {
2039 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :1973 try renderToken(tree, ais, colon1, Space.Space); // :
2040
2041 for (asm_node.outputs) |*asm_output, i| {
2042 if (i + 1 < asm_node.outputs.len) {
2043 const next_asm_output = asm_node.outputs[i + 1];
2044 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None);
2045
2046 const comma = tree.prevToken(next_asm_output.firstToken());
2047 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
2048 try renderExtraNewlineToken(tree, stream, start_col, next_asm_output.firstToken());
2049
2050 try stream.writeByteNTimes(' ', indent_extra);
2051 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
2052 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
2053 try stream.writeByteNTimes(' ', indent);
2054 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
2055 } else {
2056 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
2057 try stream.writeByteNTimes(' ', indent_once);
2058 const comma_or_colon = tree.nextToken(asm_output.lastToken());
2059 break :blk switch (tree.token_ids[comma_or_colon]) {
2060 .Comma => tree.nextToken(comma_or_colon),
2061 else => comma_or_colon,
2062 };
2063 }
2064 }
2065 unreachable;
2066 };
20671974
2068 const colon3 = if (asm_node.inputs.len == 0) blk: {1975 ais.pushIndent();
2069 try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :1976 defer ais.popIndent();
2070 try stream.writeByteNTimes(' ', indent_once);
20711977
2072 break :blk tree.nextToken(colon2);1978 for (asm_node.outputs) |*asm_output, i| {
2073 } else blk: {1979 if (i + 1 < asm_node.outputs.len) {
2074 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :1980 const next_asm_output = asm_node.outputs[i + 1];
20751981 try renderAsmOutput(allocator, ais, tree, asm_output, Space.None);
2076 for (asm_node.inputs) |*asm_input, i| {1982
2077 if (i + 1 < asm_node.inputs.len) {1983 const comma = tree.prevToken(next_asm_output.firstToken());
2078 const next_asm_input = &asm_node.inputs[i + 1];1984 try renderToken(tree, ais, comma, Space.Newline); // ,
2079 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None);1985 try renderExtraNewlineToken(tree, ais, next_asm_output.firstToken());
20801986 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
2081 const comma = tree.prevToken(next_asm_input.firstToken());1987 try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline);
2082 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,1988 break :asmblk;
2083 try renderExtraNewlineToken(tree, stream, start_col, next_asm_input.firstToken());1989 } else {
20841990 try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline);
2085 try stream.writeByteNTimes(' ', indent_extra);1991 const comma_or_colon = tree.nextToken(asm_output.lastToken());
2086 } else if (asm_node.clobbers.len == 0) {1992 break :blk switch (tree.token_ids[comma_or_colon]) {
2087 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);1993 .Comma => tree.nextToken(comma_or_colon),
2088 try stream.writeByteNTimes(' ', indent);1994 else => comma_or_colon,
2089 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )1995 };
2090 } else {1996 }
2091 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
2092 try stream.writeByteNTimes(' ', indent_once);
2093 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2094 break :blk switch (tree.token_ids[comma_or_colon]) {
2095 .Comma => tree.nextToken(comma_or_colon),
2096 else => comma_or_colon,
2097 };
2098 }1997 }
2099 }1998 unreachable;
2100 unreachable;1999 };
2101 };
21022000
2103 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :2001 const colon3 = if (asm_node.inputs.len == 0) blk: {
2002 try renderToken(tree, ais, colon2, Space.Newline); // :
2003 break :blk tree.nextToken(colon2);
2004 } else blk: {
2005 try renderToken(tree, ais, colon2, Space.Space); // :
2006 ais.pushIndent();
2007 defer ais.popIndent();
2008 for (asm_node.inputs) |*asm_input, i| {
2009 if (i + 1 < asm_node.inputs.len) {
2010 const next_asm_input = &asm_node.inputs[i + 1];
2011 try renderAsmInput(allocator, ais, tree, asm_input, Space.None);
2012
2013 const comma = tree.prevToken(next_asm_input.firstToken());
2014 try renderToken(tree, ais, comma, Space.Newline); // ,
2015 try renderExtraNewlineToken(tree, ais, next_asm_input.firstToken());
2016 } else if (asm_node.clobbers.len == 0) {
2017 try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline);
2018 break :asmblk;
2019 } else {
2020 try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline);
2021 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2022 break :blk switch (tree.token_ids[comma_or_colon]) {
2023 .Comma => tree.nextToken(comma_or_colon),
2024 else => comma_or_colon,
2025 };
2026 }
2027 }
2028 unreachable;
2029 };
21042030
2105 for (asm_node.clobbers) |clobber_node, i| {2031 try renderToken(tree, ais, colon3, Space.Space); // :
2106 if (i + 1 >= asm_node.clobbers.len) {2032 ais.pushIndent();
2107 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);2033 defer ais.popIndent();
2108 try stream.writeByteNTimes(' ', indent);2034 for (asm_node.clobbers) |clobber_node, i| {
2109 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);2035 if (i + 1 >= asm_node.clobbers.len) {
2110 } else {2036 try renderExpression(allocator, ais, tree, clobber_node, Space.Newline);
2111 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.None);2037 break :asmblk;
2112 const comma = tree.nextToken(clobber_node.lastToken());2038 } else {
2113 try renderToken(tree, stream, comma, indent_once, start_col, Space.Space); // ,2039 try renderExpression(allocator, ais, tree, clobber_node, Space.None);
2040 const comma = tree.nextToken(clobber_node.lastToken());
2041 try renderToken(tree, ais, comma, Space.Space); // ,
2042 }
2114 }2043 }
2115 }2044 }
2045
2046 return renderToken(tree, ais, asm_node.rparen, space);
2116 },2047 },
21172048
2118 .EnumLiteral => {2049 .EnumLiteral => {
2119 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);2050 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
21202051
2121 try renderToken(tree, stream, enum_literal.dot, indent, start_col, Space.None); // .2052 try renderToken(tree, ais, enum_literal.dot, Space.None); // .
2122 return renderToken(tree, stream, enum_literal.name, indent, start_col, space); // name2053 return renderToken(tree, ais, enum_literal.name, space); // name
2123 },2054 },
21242055
2125 .ContainerField,2056 .ContainerField,
...@@ -2133,118 +2064,115 @@ fn renderExpression(...@@ -2133,118 +2064,115 @@ fn renderExpression(
21332064
2134fn renderArrayType(2065fn renderArrayType(
2135 allocator: *mem.Allocator,2066 allocator: *mem.Allocator,
2136 stream: anytype,2067 ais: anytype,
2137 tree: *ast.Tree,2068 tree: *ast.Tree,
2138 indent: usize,
2139 start_col: *usize,
2140 lbracket: ast.TokenIndex,2069 lbracket: ast.TokenIndex,
2141 rhs: *ast.Node,2070 rhs: *ast.Node,
2142 len_expr: *ast.Node,2071 len_expr: *ast.Node,
2143 opt_sentinel: ?*ast.Node,2072 opt_sentinel: ?*ast.Node,
2144 space: Space,2073 space: Space,
2145) (@TypeOf(stream).Error || Error)!void {2074) (@TypeOf(ais.*).Error || Error)!void {
2146 const rbracket = tree.nextToken(if (opt_sentinel) |sentinel|2075 const rbracket = tree.nextToken(if (opt_sentinel) |sentinel|
2147 sentinel.lastToken()2076 sentinel.lastToken()
2148 else2077 else
2149 len_expr.lastToken());2078 len_expr.lastToken());
21502079
2151 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
2152
2153 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;2080 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
2154 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;2081 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
2155 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
2156 const new_space = if (ends_with_comment) Space.Newline else Space.None;2082 const new_space = if (ends_with_comment) Space.Newline else Space.None;
2157 try renderExpression(allocator, stream, tree, new_indent, start_col, len_expr, new_space);2083 {
2158 if (starts_with_comment) {2084 const do_indent = (starts_with_comment or ends_with_comment);
2159 try stream.writeByte('\n');2085 if (do_indent) ais.pushIndent();
2160 }2086 defer if (do_indent) ais.popIndent();
2161 if (ends_with_comment or starts_with_comment) {2087
2162 try stream.writeByteNTimes(' ', indent);2088 try renderToken(tree, ais, lbracket, Space.None); // [
2163 }2089 try renderExpression(allocator, ais, tree, len_expr, new_space);
2164 if (opt_sentinel) |sentinel| {2090
2165 const colon_token = tree.prevToken(sentinel.firstToken());2091 if (starts_with_comment) {
2166 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :2092 try ais.maybeInsertNewline();
2167 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);2093 }
2094 if (opt_sentinel) |sentinel| {
2095 const colon_token = tree.prevToken(sentinel.firstToken());
2096 try renderToken(tree, ais, colon_token, Space.None); // :
2097 try renderExpression(allocator, ais, tree, sentinel, Space.None);
2098 }
2099 if (starts_with_comment) {
2100 try ais.maybeInsertNewline();
2101 }
2168 }2102 }
2169 try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]2103 try renderToken(tree, ais, rbracket, Space.None); // ]
21702104
2171 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);2105 return renderExpression(allocator, ais, tree, rhs, space);
2172}2106}
21732107
2174fn renderAsmOutput(2108fn renderAsmOutput(
2175 allocator: *mem.Allocator,2109 allocator: *mem.Allocator,
2176 stream: anytype,2110 ais: anytype,
2177 tree: *ast.Tree,2111 tree: *ast.Tree,
2178 indent: usize,
2179 start_col: *usize,
2180 asm_output: *const ast.Node.Asm.Output,2112 asm_output: *const ast.Node.Asm.Output,
2181 space: Space,2113 space: Space,
2182) (@TypeOf(stream).Error || Error)!void {2114) (@TypeOf(ais.*).Error || Error)!void {
2183 try stream.writeAll("[");2115 try ais.writer().writeAll("[");
2184 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);2116 try renderExpression(allocator, ais, tree, asm_output.symbolic_name, Space.None);
2185 try stream.writeAll("] ");2117 try ais.writer().writeAll("] ");
2186 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);2118 try renderExpression(allocator, ais, tree, asm_output.constraint, Space.None);
2187 try stream.writeAll(" (");2119 try ais.writer().writeAll(" (");
21882120
2189 switch (asm_output.kind) {2121 switch (asm_output.kind) {
2190 ast.Node.Asm.Output.Kind.Variable => |variable_name| {2122 ast.Node.Asm.Output.Kind.Variable => |variable_name| {
2191 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);2123 try renderExpression(allocator, ais, tree, &variable_name.base, Space.None);
2192 },2124 },
2193 ast.Node.Asm.Output.Kind.Return => |return_type| {2125 ast.Node.Asm.Output.Kind.Return => |return_type| {
2194 try stream.writeAll("-> ");2126 try ais.writer().writeAll("-> ");
2195 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);2127 try renderExpression(allocator, ais, tree, return_type, Space.None);
2196 },2128 },
2197 }2129 }
21982130
2199 return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )2131 return renderToken(tree, ais, asm_output.lastToken(), space); // )
2200}2132}
22012133
2202fn renderAsmInput(2134fn renderAsmInput(
2203 allocator: *mem.Allocator,2135 allocator: *mem.Allocator,
2204 stream: anytype,2136 ais: anytype,
2205 tree: *ast.Tree,2137 tree: *ast.Tree,
2206 indent: usize,
2207 start_col: *usize,
2208 asm_input: *const ast.Node.Asm.Input,2138 asm_input: *const ast.Node.Asm.Input,
2209 space: Space,2139 space: Space,
2210) (@TypeOf(stream).Error || Error)!void {2140) (@TypeOf(ais.*).Error || Error)!void {
2211 try stream.writeAll("[");2141 try ais.writer().writeAll("[");
2212 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);2142 try renderExpression(allocator, ais, tree, asm_input.symbolic_name, Space.None);
2213 try stream.writeAll("] ");2143 try ais.writer().writeAll("] ");
2214 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);2144 try renderExpression(allocator, ais, tree, asm_input.constraint, Space.None);
2215 try stream.writeAll(" (");2145 try ais.writer().writeAll(" (");
2216 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);2146 try renderExpression(allocator, ais, tree, asm_input.expr, Space.None);
2217 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )2147 return renderToken(tree, ais, asm_input.lastToken(), space); // )
2218}2148}
22192149
2220fn renderVarDecl(2150fn renderVarDecl(
2221 allocator: *mem.Allocator,2151 allocator: *mem.Allocator,
2222 stream: anytype,2152 ais: anytype,
2223 tree: *ast.Tree,2153 tree: *ast.Tree,
2224 indent: usize,
2225 start_col: *usize,
2226 var_decl: *ast.Node.VarDecl,2154 var_decl: *ast.Node.VarDecl,
2227) (@TypeOf(stream).Error || Error)!void {2155) (@TypeOf(ais.*).Error || Error)!void {
2228 if (var_decl.getVisibToken()) |visib_token| {2156 if (var_decl.getVisibToken()) |visib_token| {
2229 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub2157 try renderToken(tree, ais, visib_token, Space.Space); // pub
2230 }2158 }
22312159
2232 if (var_decl.getExternExportToken()) |extern_export_token| {2160 if (var_decl.getExternExportToken()) |extern_export_token| {
2233 try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern2161 try renderToken(tree, ais, extern_export_token, Space.Space); // extern
22342162
2235 if (var_decl.getLibName()) |lib_name| {2163 if (var_decl.getLibName()) |lib_name| {
2236 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"2164 try renderExpression(allocator, ais, tree, lib_name, Space.Space); // "lib"
2237 }2165 }
2238 }2166 }
22392167
2240 if (var_decl.getComptimeToken()) |comptime_token| {2168 if (var_decl.getComptimeToken()) |comptime_token| {
2241 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime2169 try renderToken(tree, ais, comptime_token, Space.Space); // comptime
2242 }2170 }
22432171
2244 if (var_decl.getThreadLocalToken()) |thread_local_token| {2172 if (var_decl.getThreadLocalToken()) |thread_local_token| {
2245 try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal2173 try renderToken(tree, ais, thread_local_token, Space.Space); // threadlocal
2246 }2174 }
2247 try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var2175 try renderToken(tree, ais, var_decl.mut_token, Space.Space); // var
22482176
2249 const name_space = if (var_decl.getTypeNode() == null and2177 const name_space = if (var_decl.getTypeNode() == null and
2250 (var_decl.getAlignNode() != null or2178 (var_decl.getAlignNode() != null or
...@@ -2253,95 +2181,92 @@ fn renderVarDecl(...@@ -2253,95 +2181,92 @@ fn renderVarDecl(
2253 Space.Space2181 Space.Space
2254 else2182 else
2255 Space.None;2183 Space.None;
2256 try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);2184 try renderToken(tree, ais, var_decl.name_token, name_space);
22572185
2258 if (var_decl.getTypeNode()) |type_node| {2186 if (var_decl.getTypeNode()) |type_node| {
2259 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);2187 try renderToken(tree, ais, tree.nextToken(var_decl.name_token), Space.Space);
2260 const s = if (var_decl.getAlignNode() != null or2188 const s = if (var_decl.getAlignNode() != null or
2261 var_decl.getSectionNode() != null or2189 var_decl.getSectionNode() != null or
2262 var_decl.getInitNode() != null) Space.Space else Space.None;2190 var_decl.getInitNode() != null) Space.Space else Space.None;
2263 try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);2191 try renderExpression(allocator, ais, tree, type_node, s);
2264 }2192 }
22652193
2266 if (var_decl.getAlignNode()) |align_node| {2194 if (var_decl.getAlignNode()) |align_node| {
2267 const lparen = tree.prevToken(align_node.firstToken());2195 const lparen = tree.prevToken(align_node.firstToken());
2268 const align_kw = tree.prevToken(lparen);2196 const align_kw = tree.prevToken(lparen);
2269 const rparen = tree.nextToken(align_node.lastToken());2197 const rparen = tree.nextToken(align_node.lastToken());
2270 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align2198 try renderToken(tree, ais, align_kw, Space.None); // align
2271 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (2199 try renderToken(tree, ais, lparen, Space.None); // (
2272 try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);2200 try renderExpression(allocator, ais, tree, align_node, Space.None);
2273 const s = if (var_decl.getSectionNode() != null or var_decl.getInitNode() != null) Space.Space else Space.None;2201 const s = if (var_decl.getSectionNode() != null or var_decl.getInitNode() != null) Space.Space else Space.None;
2274 try renderToken(tree, stream, rparen, indent, start_col, s); // )2202 try renderToken(tree, ais, rparen, s); // )
2275 }2203 }
22762204
2277 if (var_decl.getSectionNode()) |section_node| {2205 if (var_decl.getSectionNode()) |section_node| {
2278 const lparen = tree.prevToken(section_node.firstToken());2206 const lparen = tree.prevToken(section_node.firstToken());
2279 const section_kw = tree.prevToken(lparen);2207 const section_kw = tree.prevToken(lparen);
2280 const rparen = tree.nextToken(section_node.lastToken());2208 const rparen = tree.nextToken(section_node.lastToken());
2281 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection2209 try renderToken(tree, ais, section_kw, Space.None); // linksection
2282 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (2210 try renderToken(tree, ais, lparen, Space.None); // (
2283 try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None);2211 try renderExpression(allocator, ais, tree, section_node, Space.None);
2284 const s = if (var_decl.getInitNode() != null) Space.Space else Space.None;2212 const s = if (var_decl.getInitNode() != null) Space.Space else Space.None;
2285 try renderToken(tree, stream, rparen, indent, start_col, s); // )2213 try renderToken(tree, ais, rparen, s); // )
2286 }2214 }
22872215
2288 if (var_decl.getInitNode()) |init_node| {2216 if (var_decl.getInitNode()) |init_node| {
2289 const s = if (init_node.tag == .MultilineStringLiteral) Space.None else Space.Space;2217 const s = if (init_node.tag == .MultilineStringLiteral) Space.None else Space.Space;
2290 try renderToken(tree, stream, var_decl.getEqToken().?, indent, start_col, s); // =2218 try renderToken(tree, ais, var_decl.getEqToken().?, s); // =
2291 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);2219 ais.pushIndentOneShot();
2220 try renderExpression(allocator, ais, tree, init_node, Space.None);
2292 }2221 }
22932222
2294 try renderToken(tree, stream, var_decl.semicolon_token, indent, start_col, Space.Newline);2223 try renderToken(tree, ais, var_decl.semicolon_token, Space.Newline);
2295}2224}
22962225
2297fn renderParamDecl(2226fn renderParamDecl(
2298 allocator: *mem.Allocator,2227 allocator: *mem.Allocator,
2299 stream: anytype,2228 ais: anytype,
2300 tree: *ast.Tree,2229 tree: *ast.Tree,
2301 indent: usize,
2302 start_col: *usize,
2303 param_decl: ast.Node.FnProto.ParamDecl,2230 param_decl: ast.Node.FnProto.ParamDecl,
2304 space: Space,2231 space: Space,
2305) (@TypeOf(stream).Error || Error)!void {2232) (@TypeOf(ais.*).Error || Error)!void {
2306 try renderDocComments(tree, stream, param_decl, param_decl.doc_comments, indent, start_col);2233 try renderDocComments(tree, ais, param_decl, param_decl.doc_comments);
23072234
2308 if (param_decl.comptime_token) |comptime_token| {2235 if (param_decl.comptime_token) |comptime_token| {
2309 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);2236 try renderToken(tree, ais, comptime_token, Space.Space);
2310 }2237 }
2311 if (param_decl.noalias_token) |noalias_token| {2238 if (param_decl.noalias_token) |noalias_token| {
2312 try renderToken(tree, stream, noalias_token, indent, start_col, Space.Space);2239 try renderToken(tree, ais, noalias_token, Space.Space);
2313 }2240 }
2314 if (param_decl.name_token) |name_token| {2241 if (param_decl.name_token) |name_token| {
2315 try renderToken(tree, stream, name_token, indent, start_col, Space.None);2242 try renderToken(tree, ais, name_token, Space.None);
2316 try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :2243 try renderToken(tree, ais, tree.nextToken(name_token), Space.Space); // :
2317 }2244 }
2318 switch (param_decl.param_type) {2245 switch (param_decl.param_type) {
2319 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),2246 .any_type, .type_expr => |node| try renderExpression(allocator, ais, tree, node, space),
2320 }2247 }
2321}2248}
23222249
2323fn renderStatement(2250fn renderStatement(
2324 allocator: *mem.Allocator,2251 allocator: *mem.Allocator,
2325 stream: anytype,2252 ais: anytype,
2326 tree: *ast.Tree,2253 tree: *ast.Tree,
2327 indent: usize,
2328 start_col: *usize,
2329 base: *ast.Node,2254 base: *ast.Node,
2330) (@TypeOf(stream).Error || Error)!void {2255) (@TypeOf(ais.*).Error || Error)!void {
2331 switch (base.tag) {2256 switch (base.tag) {
2332 .VarDecl => {2257 .VarDecl => {
2333 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);2258 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
2334 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);2259 try renderVarDecl(allocator, ais, tree, var_decl);
2335 },2260 },
2336 else => {2261 else => {
2337 if (base.requireSemiColon()) {2262 if (base.requireSemiColon()) {
2338 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);2263 try renderExpression(allocator, ais, tree, base, Space.None);
23392264
2340 const semicolon_index = tree.nextToken(base.lastToken());2265 const semicolon_index = tree.nextToken(base.lastToken());
2341 assert(tree.token_ids[semicolon_index] == .Semicolon);2266 assert(tree.token_ids[semicolon_index] == .Semicolon);
2342 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);2267 try renderToken(tree, ais, semicolon_index, Space.Newline);
2343 } else {2268 } else {
2344 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);2269 try renderExpression(allocator, ais, tree, base, Space.Newline);
2345 }2270 }
2346 },2271 },
2347 }2272 }
...@@ -2360,24 +2285,19 @@ const Space = enum {...@@ -2360,24 +2285,19 @@ const Space = enum {
23602285
2361fn renderTokenOffset(2286fn renderTokenOffset(
2362 tree: *ast.Tree,2287 tree: *ast.Tree,
2363 stream: anytype,2288 ais: anytype,
2364 token_index: ast.TokenIndex,2289 token_index: ast.TokenIndex,
2365 indent: usize,
2366 start_col: *usize,
2367 space: Space,2290 space: Space,
2368 token_skip_bytes: usize,2291 token_skip_bytes: usize,
2369) (@TypeOf(stream).Error || Error)!void {2292) (@TypeOf(ais.*).Error || Error)!void {
2370 if (space == Space.BlockStart) {2293 if (space == Space.BlockStart) {
2371 if (start_col.* < indent + indent_delta)2294 // If placing the lbrace on the current line would cause an uggly gap then put the lbrace on the next line
2372 return renderToken(tree, stream, token_index, indent, start_col, Space.Space);2295 const new_space = if (ais.isLineOverIndented()) Space.Newline else Space.Space;
2373 try renderToken(tree, stream, token_index, indent, start_col, Space.Newline);2296 return renderToken(tree, ais, token_index, new_space);
2374 try stream.writeByteNTimes(' ', indent);
2375 start_col.* = indent;
2376 return;
2377 }2297 }
23782298
2379 var token_loc = tree.token_locs[token_index];2299 var token_loc = tree.token_locs[token_index];
2380 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));2300 try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));
23812301
2382 if (space == Space.NoComment)2302 if (space == Space.NoComment)
2383 return;2303 return;
...@@ -2386,20 +2306,20 @@ fn renderTokenOffset(...@@ -2386,20 +2306,20 @@ fn renderTokenOffset(
2386 var next_token_loc = tree.token_locs[token_index + 1];2306 var next_token_loc = tree.token_locs[token_index + 1];
23872307
2388 if (space == Space.Comma) switch (next_token_id) {2308 if (space == Space.Comma) switch (next_token_id) {
2389 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),2309 .Comma => return renderToken(tree, ais, token_index + 1, Space.Newline),
2390 .LineComment => {2310 .LineComment => {
2391 try stream.writeAll(", ");2311 try ais.writer().writeAll(", ");
2392 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);2312 return renderToken(tree, ais, token_index + 1, Space.Newline);
2393 },2313 },
2394 else => {2314 else => {
2395 if (token_index + 2 < tree.token_ids.len and2315 if (token_index + 2 < tree.token_ids.len and
2396 tree.token_ids[token_index + 2] == .MultilineStringLiteralLine)2316 tree.token_ids[token_index + 2] == .MultilineStringLiteralLine)
2397 {2317 {
2398 try stream.writeAll(",");2318 try ais.writer().writeAll(",");
2399 return;2319 return;
2400 } else {2320 } else {
2401 try stream.writeAll(",\n");2321 try ais.writer().writeAll(",");
2402 start_col.* = 0;2322 try ais.insertNewline();
2403 return;2323 return;
2404 }2324 }
2405 },2325 },
...@@ -2423,15 +2343,14 @@ fn renderTokenOffset(...@@ -2423,15 +2343,14 @@ fn renderTokenOffset(
2423 if (next_token_id == .MultilineStringLiteralLine) {2343 if (next_token_id == .MultilineStringLiteralLine) {
2424 return;2344 return;
2425 } else {2345 } else {
2426 try stream.writeAll("\n");2346 try ais.insertNewline();
2427 start_col.* = 0;
2428 return;2347 return;
2429 }2348 }
2430 },2349 },
2431 Space.Space, Space.SpaceOrOutdent => {2350 Space.Space, Space.SpaceOrOutdent => {
2432 if (next_token_id == .MultilineStringLiteralLine)2351 if (next_token_id == .MultilineStringLiteralLine)
2433 return;2352 return;
2434 try stream.writeByte(' ');2353 try ais.writer().writeByte(' ');
2435 return;2354 return;
2436 },2355 },
2437 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,2356 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
...@@ -2448,8 +2367,7 @@ fn renderTokenOffset(...@@ -2448,8 +2367,7 @@ fn renderTokenOffset(
2448 next_token_id = tree.token_ids[token_index + offset];2367 next_token_id = tree.token_ids[token_index + offset];
2449 next_token_loc = tree.token_locs[token_index + offset];2368 next_token_loc = tree.token_locs[token_index + offset];
2450 if (next_token_id != .LineComment) {2369 if (next_token_id != .LineComment) {
2451 try stream.writeByte('\n');2370 try ais.insertNewline();
2452 start_col.* = 0;
2453 return;2371 return;
2454 }2372 }
2455 },2373 },
...@@ -2462,7 +2380,7 @@ fn renderTokenOffset(...@@ -2462,7 +2380,7 @@ fn renderTokenOffset(
24622380
2463 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);2381 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2464 if (loc.line == 0) {2382 if (loc.line == 0) {
2465 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});2383 try ais.writer().print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});
2466 offset = 2;2384 offset = 2;
2467 token_loc = next_token_loc;2385 token_loc = next_token_loc;
2468 next_token_loc = tree.token_locs[token_index + offset];2386 next_token_loc = tree.token_locs[token_index + offset];
...@@ -2470,26 +2388,16 @@ fn renderTokenOffset(...@@ -2470,26 +2388,16 @@ fn renderTokenOffset(
2470 if (next_token_id != .LineComment) {2388 if (next_token_id != .LineComment) {
2471 switch (space) {2389 switch (space) {
2472 Space.None, Space.Space => {2390 Space.None, Space.Space => {
2473 try stream.writeByte('\n');2391 try ais.insertNewline();
2474 const after_comment_token = tree.token_ids[token_index + offset];
2475 const next_line_indent = switch (after_comment_token) {
2476 .RParen, .RBrace, .RBracket => indent,
2477 else => indent + indent_delta,
2478 };
2479 try stream.writeByteNTimes(' ', next_line_indent);
2480 start_col.* = next_line_indent;
2481 },2392 },
2482 Space.SpaceOrOutdent => {2393 Space.SpaceOrOutdent => {
2483 try stream.writeByte('\n');2394 try ais.insertNewline();
2484 try stream.writeByteNTimes(' ', indent);
2485 start_col.* = indent;
2486 },2395 },
2487 Space.Newline => {2396 Space.Newline => {
2488 if (next_token_id == .MultilineStringLiteralLine) {2397 if (next_token_id == .MultilineStringLiteralLine) {
2489 return;2398 return;
2490 } else {2399 } else {
2491 try stream.writeAll("\n");2400 try ais.insertNewline();
2492 start_col.* = 0;
2493 return;2401 return;
2494 }2402 }
2495 },2403 },
...@@ -2505,10 +2413,9 @@ fn renderTokenOffset(...@@ -2505,10 +2413,9 @@ fn renderTokenOffset(
2505 // translate-c doesn't generate correct newlines2413 // translate-c doesn't generate correct newlines
2506 // in generated code (loc.line == 0) so treat that case2414 // in generated code (loc.line == 0) so treat that case
2507 // as though there was meant to be a newline between the tokens2415 // as though there was meant to be a newline between the tokens
2508 const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);2416 var newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);
2509 try stream.writeByteNTimes('\n', newline_count);2417 while (newline_count > 0) : (newline_count -= 1) try ais.insertNewline();
2510 try stream.writeByteNTimes(' ', indent);2418 try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
2511 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
25122419
2513 offset += 1;2420 offset += 1;
2514 token_loc = next_token_loc;2421 token_loc = next_token_loc;
...@@ -2520,32 +2427,15 @@ fn renderTokenOffset(...@@ -2520,32 +2427,15 @@ fn renderTokenOffset(
2520 if (next_token_id == .MultilineStringLiteralLine) {2427 if (next_token_id == .MultilineStringLiteralLine) {
2521 return;2428 return;
2522 } else {2429 } else {
2523 try stream.writeAll("\n");2430 try ais.insertNewline();
2524 start_col.* = 0;
2525 return;2431 return;
2526 }2432 }
2527 },2433 },
2528 Space.None, Space.Space => {2434 Space.None, Space.Space => {
2529 try stream.writeByte('\n');2435 try ais.insertNewline();
2530
2531 const after_comment_token = tree.token_ids[token_index + offset];
2532 const next_line_indent = switch (after_comment_token) {
2533 .RParen, .RBrace, .RBracket => blk: {
2534 if (indent > indent_delta) {
2535 break :blk indent - indent_delta;
2536 } else {
2537 break :blk 0;
2538 }
2539 },
2540 else => indent,
2541 };
2542 try stream.writeByteNTimes(' ', next_line_indent);
2543 start_col.* = next_line_indent;
2544 },2436 },
2545 Space.SpaceOrOutdent => {2437 Space.SpaceOrOutdent => {
2546 try stream.writeByte('\n');2438 try ais.insertNewline();
2547 try stream.writeByteNTimes(' ', indent);
2548 start_col.* = indent;
2549 },2439 },
2550 Space.NoNewline => {},2440 Space.NoNewline => {},
2551 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,2441 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
...@@ -2558,46 +2448,38 @@ fn renderTokenOffset(...@@ -2558,46 +2448,38 @@ fn renderTokenOffset(
25582448
2559fn renderToken(2449fn renderToken(
2560 tree: *ast.Tree,2450 tree: *ast.Tree,
2561 stream: anytype,2451 ais: anytype,
2562 token_index: ast.TokenIndex,2452 token_index: ast.TokenIndex,
2563 indent: usize,
2564 start_col: *usize,
2565 space: Space,2453 space: Space,
2566) (@TypeOf(stream).Error || Error)!void {2454) (@TypeOf(ais.*).Error || Error)!void {
2567 return renderTokenOffset(tree, stream, token_index, indent, start_col, space, 0);2455 return renderTokenOffset(tree, ais, token_index, space, 0);
2568}2456}
25692457
2570fn renderDocComments(2458fn renderDocComments(
2571 tree: *ast.Tree,2459 tree: *ast.Tree,
2572 stream: anytype,2460 ais: anytype,
2573 node: anytype,2461 node: anytype,
2574 doc_comments: ?*ast.Node.DocComment,2462 doc_comments: ?*ast.Node.DocComment,
2575 indent: usize,2463) (@TypeOf(ais.*).Error || Error)!void {
2576 start_col: *usize,
2577) (@TypeOf(stream).Error || Error)!void {
2578 const comment = doc_comments orelse return;2464 const comment = doc_comments orelse return;
2579 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);2465 return renderDocCommentsToken(tree, ais, comment, node.firstToken());
2580}2466}
25812467
2582fn renderDocCommentsToken(2468fn renderDocCommentsToken(
2583 tree: *ast.Tree,2469 tree: *ast.Tree,
2584 stream: anytype,2470 ais: anytype,
2585 comment: *ast.Node.DocComment,2471 comment: *ast.Node.DocComment,
2586 first_token: ast.TokenIndex,2472 first_token: ast.TokenIndex,
2587 indent: usize,2473) (@TypeOf(ais.*).Error || Error)!void {
2588 start_col: *usize,
2589) (@TypeOf(stream).Error || Error)!void {
2590 var tok_i = comment.first_line;2474 var tok_i = comment.first_line;
2591 while (true) : (tok_i += 1) {2475 while (true) : (tok_i += 1) {
2592 switch (tree.token_ids[tok_i]) {2476 switch (tree.token_ids[tok_i]) {
2593 .DocComment, .ContainerDocComment => {2477 .DocComment, .ContainerDocComment => {
2594 if (comment.first_line < first_token) {2478 if (comment.first_line < first_token) {
2595 try renderToken(tree, stream, tok_i, indent, start_col, Space.Newline);2479 try renderToken(tree, ais, tok_i, Space.Newline);
2596 try stream.writeByteNTimes(' ', indent);
2597 } else {2480 } else {
2598 try renderToken(tree, stream, tok_i, indent, start_col, Space.NoComment);2481 try renderToken(tree, ais, tok_i, Space.NoComment);
2599 try stream.writeAll("\n");2482 try ais.insertNewline();
2600 try stream.writeByteNTimes(' ', indent);
2601 }2483 }
2602 },2484 },
2603 .LineComment => continue,2485 .LineComment => continue,
...@@ -2669,41 +2551,10 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {...@@ -2669,41 +2551,10 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
2669 };2551 };
2670}2552}
26712553
2672/// A `std.io.OutStream` that returns whether the given character has been written to it.2554fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!void {
2673/// The contents are not written to anything.
2674const FindByteOutStream = struct {
2675 byte_found: bool,
2676 byte: u8,
2677
2678 pub const Error = error{};
2679 pub const OutStream = std.io.OutStream(*FindByteOutStream, Error, write);
2680
2681 pub fn init(byte: u8) FindByteOutStream {
2682 return FindByteOutStream{
2683 .byte = byte,
2684 .byte_found = false,
2685 };
2686 }
2687
2688 pub fn write(self: *FindByteOutStream, bytes: []const u8) Error!usize {
2689 if (self.byte_found) return bytes.len;
2690 self.byte_found = blk: {
2691 for (bytes) |b|
2692 if (b == self.byte) break :blk true;
2693 break :blk false;
2694 };
2695 return bytes.len;
2696 }
2697
2698 pub fn outStream(self: *FindByteOutStream) OutStream {
2699 return .{ .context = self };
2700 }
2701};
2702
2703fn copyFixingWhitespace(stream: anytype, slice: []const u8) @TypeOf(stream).Error!void {
2704 for (slice) |byte| switch (byte) {2555 for (slice) |byte| switch (byte) {
2705 '\t' => try stream.writeAll(" "),2556 '\t' => try ais.writer().writeAll(" "),
2706 '\r' => {},2557 '\r' => {},
2707 else => try stream.writeByte(byte),2558 else => try ais.writer().writeByte(byte),
2708 };2559 };
2709}2560}
src-self-hosted/main.zig+2-1
...@@ -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