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

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


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

lib/std/io.zig+11-2
......@@ -169,6 +169,15 @@ pub const BitOutStream = BitWriter;
169169/// Deprecated: use `bitWriter`
170170pub 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
172181pub const Packing = @import("io/serialization.zig").Packing;
173182
174183pub const Serializer = @import("io/serialization.zig").Serializer;
......@@ -182,10 +191,10 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt
182191pub const StreamSource = @import("io/stream_source.zig").StreamSource;
183192
184193/// A Writer that doesn't write to anything.
185pub const null_writer = @as(NullWriter, .{ .context = {} });
194pub var null_writer = @as(NullWriter, .{ .context = {} });
186195
187196/// Deprecated: use `null_writer`
188pub const null_out_stream = null_writer;
197pub var null_out_stream = null_writer;
189198
190199const NullWriter = Writer(void, error{}, dummyWrite);
191200/// Deprecated: use NullWriter
lib/std/io/auto_indenting_stream.zig created+135
......@@ -0,0 +1,135 @@
1const std = @import("../std.zig");
2const io = std.io;
3const mem = std.mem;
4const assert = std.debug.assert;
5
6pub fn AutoIndentingStream(comptime indent_delta: u8, comptime OutStreamType: type) type {
7 return struct {
8 const Self = @This();
9 pub const Error = OutStreamType.Error;
10 pub const OutStream = io.Writer(*Self, Error, write);
11
12 out_stream: *OutStreamType,
13 current_line_empty: bool = true,
14 indent_stack: [255]u8 = undefined,
15 indent_stack_top: u8 = 0,
16 indent_one_shot_count: u8 = 0, // automatically popped when applied
17 applied_indent: u8 = 0, // the most recently applied indent
18 indent_next_line: u8 = 0, // not used until the next line
19
20 pub fn init(out_stream: *OutStreamType) Self {
21 return Self{ .out_stream = out_stream };
22 }
23
24 pub fn writer(self: *Self) OutStream {
25 return .{ .context = self };
26 }
27
28 pub fn write(self: *Self, bytes: []const u8) Error!usize {
29 if (bytes.len == 0)
30 return @as(usize, 0);
31
32 try self.applyIndent();
33 return self.writeNoIndent(bytes);
34 }
35
36 fn writeNoIndent(self: *Self, bytes: []const u8) Error!usize {
37 try self.out_stream.outStream().writeAll(bytes);
38 if (bytes[bytes.len - 1] == '\n')
39 self.resetLine();
40 return bytes.len;
41 }
42
43 pub fn insertNewline(self: *Self) Error!void {
44 _ = try self.writeNoIndent("\n");
45 }
46
47 fn resetLine(self: *Self) void {
48 self.current_line_empty = true;
49 self.indent_next_line = 0;
50 }
51
52 /// Insert a newline unless the current line is blank
53 pub fn maybeInsertNewline(self: *Self) Error!void {
54 if (!self.current_line_empty)
55 try self.insertNewline();
56 }
57
58 /// Push default indentation
59 pub fn pushIndent(self: *Self) void {
60 // Doesn't actually write any indentation. Just primes the stream to be able to write the correct indentation if it needs to.
61 self.pushIndentN(indent_delta);
62 }
63
64 /// Push an indent of arbitrary width
65 pub fn pushIndentN(self: *Self, n: u8) void {
66 assert(self.indent_stack_top < std.math.maxInt(u8));
67 self.indent_stack[self.indent_stack_top] = n;
68 self.indent_stack_top += 1;
69 }
70
71 /// Push an indent that is automatically popped after being applied
72 pub fn pushIndentOneShot(self: *Self) void {
73 self.indent_one_shot_count += 1;
74 self.pushIndent();
75 }
76
77 /// Turns all one-shot indents into regular indents
78 /// Returns number of indents that must now be manually popped
79 pub fn lockOneShotIndent(self: *Self) u8 {
80 var locked_count = self.indent_one_shot_count;
81 self.indent_one_shot_count = 0;
82 return locked_count;
83 }
84
85 /// Push an indent that should not take effect until the next line
86 pub fn pushIndentNextLine(self: *Self) void {
87 self.indent_next_line += 1;
88 self.pushIndent();
89 }
90
91 pub fn popIndent(self: *Self) void {
92 assert(self.indent_stack_top != 0);
93 self.indent_stack_top -= 1;
94 self.indent_next_line = std.math.min(self.indent_stack_top, self.indent_next_line); // Tentative indent may have been popped before there was a newline
95 }
96
97 /// Writes ' ' bytes if the current line is empty
98 fn applyIndent(self: *Self) Error!void {
99 const current_indent = self.currentIndent();
100 if (self.current_line_empty and current_indent > 0) {
101 try self.out_stream.outStream().writeByteNTimes(' ', current_indent);
102 self.applied_indent = current_indent;
103 }
104
105 self.indent_stack_top -= self.indent_one_shot_count;
106 self.indent_one_shot_count = 0;
107 self.current_line_empty = false;
108 }
109
110 /// Checks to see if the most recent indentation exceeds the currently pushed indents
111 pub fn isLineOverIndented(self: *Self) bool {
112 if (self.current_line_empty) return false;
113 return self.applied_indent > self.currentIndent();
114 }
115
116 fn currentIndent(self: *Self) u8 {
117 var indent_current: u8 = 0;
118 if (self.indent_stack_top > 0) {
119 const stack_top = self.indent_stack_top - self.indent_next_line;
120 for (self.indent_stack[0..stack_top]) |indent| {
121 indent_current += indent;
122 }
123 }
124 return indent_current;
125 }
126 };
127}
128
129pub fn autoIndentingStream(
130 comptime indent_delta: u8,
131 underlying_stream: anytype,
132) AutoIndentingStream(indent_delta, @TypeOf(underlying_stream).Child) {
133 comptime assert(@typeInfo(@TypeOf(underlying_stream)) == .Pointer);
134 return AutoIndentingStream(indent_delta, @TypeOf(underlying_stream).Child).init(underlying_stream);
135}
lib/std/io/change_detection_stream.zig created+58
......@@ -0,0 +1,58 @@
1const std = @import("../std.zig");
2const io = std.io;
3const mem = std.mem;
4const assert = std.debug.assert;
5
6pub fn ChangeDetectionStream(comptime OutStreamType: type) type {
7 return struct {
8 const Self = @This();
9 pub const Error = OutStreamType.Error;
10 pub const OutStream = io.OutStream(*Self, Error, write);
11
12 anything_changed: bool = false,
13 out_stream: *OutStreamType,
14 source_index: usize,
15 source: []const u8,
16
17 pub fn init(source: []const u8, out_stream: *OutStreamType) Self {
18 return Self{
19 .out_stream = out_stream,
20 .source_index = 0,
21 .source = source,
22 };
23 }
24
25 pub fn outStream(self: *Self) OutStream {
26 return .{ .context = self };
27 }
28
29 fn write(self: *Self, bytes: []const u8) Error!usize {
30 if (!self.anything_changed) {
31 const end = self.source_index + bytes.len;
32 if (end > self.source.len) {
33 self.anything_changed = true;
34 } else {
35 const src_slice = self.source[self.source_index..end];
36 self.source_index += bytes.len;
37 if (!mem.eql(u8, bytes, src_slice)) {
38 self.anything_changed = true;
39 }
40 }
41 }
42
43 return self.out_stream.write(bytes);
44 }
45
46 pub fn changeDetected(self: *Self) bool {
47 return self.anything_changed or (self.source_index != self.source.len);
48 }
49 };
50}
51
52pub fn changeDetectionStream(
53 source: []const u8,
54 underlying_stream: anytype,
55) ChangeDetectionStream(@TypeOf(underlying_stream).Child) {
56 comptime assert(@typeInfo(@TypeOf(underlying_stream)) == .Pointer);
57 return ChangeDetectionStream(@TypeOf(underlying_stream).Child).init(source, underlying_stream);
58}
lib/std/io/find_byte_out_stream.zig created+44
......@@ -0,0 +1,44 @@
1const std = @import("../std.zig");
2const io = std.io;
3const assert = std.debug.assert;
4
5// An OutStream that returns whether the given character has been written to it.
6// The contents are not written to anything.
7pub fn FindByteOutStream(comptime OutStreamType: type) type {
8 return struct {
9 const Self = @This();
10 pub const Error = OutStreamType.Error;
11 pub const OutStream = io.OutStream(*Self, Error, write);
12
13 out_stream: *OutStreamType,
14 byte_found: bool,
15 byte: u8,
16
17 pub fn init(byte: u8, out_stream: *OutStreamType) Self {
18 return Self{
19 .out_stream = out_stream,
20 .byte = byte,
21 .byte_found = false,
22 };
23 }
24
25 pub fn outStream(self: *Self) OutStream {
26 return .{ .context = self };
27 }
28
29 fn write(self: *Self, bytes: []const u8) Error!usize {
30 if (!self.byte_found) {
31 self.byte_found = blk: {
32 for (bytes) |b|
33 if (b == self.byte) break :blk true;
34 break :blk false;
35 };
36 }
37 return self.out_stream.writer().write(bytes);
38 }
39 };
40}
41pub fn findByteOutStream(byte: u8, underlying_stream: anytype) FindByteOutStream(@TypeOf(underlying_stream).Child) {
42 comptime assert(@typeInfo(@TypeOf(underlying_stream)) == .Pointer);
43 return FindByteOutStream(@TypeOf(underlying_stream).Child).init(byte, underlying_stream);
44}
lib/std/io/writer.zig+4
......@@ -18,6 +18,10 @@ pub fn Writer(
1818 const Self = @This();
1919 pub const Error = WriteError;
2020
21 pub fn writer(self: *const Self) Self {
22 return self.*;
23 }
24
2125 pub fn write(self: Self, bytes: []const u8) Error!usize {
2226 return writeFn(self.context, bytes);
2327 }
lib/std/zig/parser_test.zig+103-6
......@@ -615,6 +615,17 @@ test "zig fmt: infix operator and then multiline string literal" {
615615 );
616616}
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
618629test "zig fmt: C pointers" {
619630 try testCanonical(
620631 \\const Ptr = [*c]i32;
......@@ -885,6 +896,28 @@ test "zig fmt: 2nd arg multiline string" {
885896 );
886897}
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
888921test "zig fmt: if condition wraps" {
889922 try testTransform(
890923 \\comptime {
......@@ -915,6 +948,11 @@ test "zig fmt: if condition wraps" {
915948 \\ var a = if (a) |*f| x: {
916949 \\ break :x &a.b;
917950 \\ } else |err| err;
951 \\ var a = if (cond and
952 \\ cond) |*f|
953 \\ x: {
954 \\ break :x &a.b;
955 \\ } else |err| err;
918956 \\}
919957 ,
920958 \\comptime {
......@@ -951,6 +989,35 @@ test "zig fmt: if condition wraps" {
951989 \\ var a = if (a) |*f| x: {
952990 \\ break :x &a.b;
953991 \\ } 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 \\ }
9541021 \\}
9551022 \\
9561023 );
......@@ -977,6 +1044,18 @@ test "zig fmt: if condition has line break but must not wrap" {
9771044 );
9781045}
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
9801059test "zig fmt: same-line doc comment on variable declaration" {
9811060 try testTransform(
9821061 \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
......@@ -1228,7 +1307,7 @@ test "zig fmt: array literal with hint" {
12281307 \\const a = []u8{
12291308 \\ 1, 2,
12301309 \\ 3, //
1231 \\ 4,
1310 \\ 4,
12321311 \\ 5, 6,
12331312 \\ 7,
12341313 \\};
......@@ -1293,7 +1372,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {
12931372 \\ \\ZIG_C_HEADER_FILES {}
12941373 \\ \\ZIG_DIA_GUIDS_LIB {}
12951374 \\ \\
1296 \\ ,
1375 \\ ,
12971376 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
12981377 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
12991378 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
......@@ -2885,20 +2964,20 @@ test "zig fmt: multiline string in array" {
28852964 try testCanonical(
28862965 \\const Foo = [][]const u8{
28872966 \\ \\aaa
2888 \\,
2967 \\ ,
28892968 \\ \\bbb
28902969 \\};
28912970 \\
28922971 \\fn bar() void {
28932972 \\ const Foo = [][]const u8{
28942973 \\ \\aaa
2895 \\ ,
2974 \\ ,
28962975 \\ \\bbb
28972976 \\ };
28982977 \\ const Bar = [][]const u8{ // comment here
28992978 \\ \\aaa
29002979 \\ \\
2901 \\ , // and another comment can go here
2980 \\ , // and another comment can go here
29022981 \\ \\bbb
29032982 \\ };
29042983 \\}
......@@ -3214,6 +3293,23 @@ test "zig fmt: C var args" {
32143293 );
32153294}
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
32173313const std = @import("std");
32183314const mem = std.mem;
32193315const warn = std.debug.warn;
......@@ -3256,7 +3352,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
32563352 var buffer = std.ArrayList(u8).init(allocator);
32573353 errdefer buffer.deinit();
32583354
3259 anything_changed.* = try std.zig.render(allocator, buffer.outStream(), tree);
3355 const outStream = buffer.outStream();
3356 anything_changed.* = try std.zig.render(allocator, &outStream, tree);
32603357 return buffer.toOwnedSlice();
32613358}
32623359fn testTransform(source: []const u8, expected_source: []const u8) !void {
lib/std/zig/render.zig+742-894
......@@ -6,6 +6,7 @@
66const std = @import("../std.zig");
77const assert = std.debug.assert;
88const mem = std.mem;
9const meta = std.meta;
910const ast = std.zig.ast;
1011const Token = std.zig.Token;
1112
......@@ -17,74 +18,37 @@ pub const Error = error{
1718};
1819
1920/// Returns whether anything changed
20pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (@TypeOf(stream).Error || Error)!bool {
21pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (meta.Child(@TypeOf(stream)).Error || Error)!bool {
2122 // cannot render an invalid tree
2223 std.debug.assert(tree.errors.len == 0);
2324
24 // make a passthrough stream that checks whether something changed
25 const MyStream = struct {
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 };
25 var s = stream.*;
26 var change_detection_stream = std.io.changeDetectionStream(tree.source, &s);
27 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &change_detection_stream);
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) {
64 my_stream.anything_changed = true;
65 }
66
67 return my_stream.anything_changed;
31 return change_detection_stream.changeDetected();
6832}
6933
7034fn renderRoot(
7135 allocator: *mem.Allocator,
7236 stream: anytype,
7337 tree: *ast.Tree,
74) (@TypeOf(stream).Error || Error)!void {
38) (@TypeOf(stream.*).Error || Error)!void {
39
7540 // render all the line comments at the beginning of the file
7641 for (tree.token_ids) |token_id, i| {
7742 if (token_id != .LineComment) break;
7843 const token_loc = tree.token_locs[i];
79 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
44 try stream.writer().print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
8045 const next_token = tree.token_locs[i + 1];
8146 const loc = tree.tokenLocationLoc(token_loc.end, next_token);
8247 if (loc.line >= 2) {
83 try stream.writeByte('\n');
48 try stream.insertNewline();
8449 }
8550 }
8651
87 var start_col: usize = 0;
8852 var decl_i: ast.NodeIndex = 0;
8953 const root_decls = tree.root_node.decls();
9054
......@@ -189,23 +153,22 @@ fn renderRoot(
189153 try copyFixingWhitespace(stream, tree.source[start..end]);
190154 }
191155
192 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);
156 try renderTopLevelDecl(allocator, stream, tree, decl);
193157 decl_i += 1;
194158 if (decl_i >= root_decls.len) return;
195 try renderExtraNewline(tree, stream, &start_col, root_decls[decl_i]);
159 try renderExtraNewline(tree, stream, root_decls[decl_i]);
196160 }
197161}
198162
199fn renderExtraNewline(tree: *ast.Tree, stream: anytype, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {
200 return renderExtraNewlineToken(tree, stream, start_col, node.firstToken());
163fn renderExtraNewline(tree: *ast.Tree, stream: anytype, node: *ast.Node) @TypeOf(stream.*).Error!void {
164 return renderExtraNewlineToken(tree, stream, node.firstToken());
201165}
202166
203167fn renderExtraNewlineToken(
204168 tree: *ast.Tree,
205169 stream: anytype,
206 start_col: *usize,
207170 first_token: ast.TokenIndex,
208) @TypeOf(stream).Error!void {
171) @TypeOf(stream.*).Error!void {
209172 var prev_token = first_token;
210173 if (prev_token == 0) return;
211174 var newline_threshold: usize = 2;
......@@ -218,28 +181,27 @@ fn renderExtraNewlineToken(
218181 const prev_token_end = tree.token_locs[prev_token - 1].end;
219182 const loc = tree.tokenLocation(prev_token_end, first_token);
220183 if (loc.line >= newline_threshold) {
221 try stream.writeByte('\n');
222 start_col.* = 0;
184 try stream.insertNewline();
223185 }
224186}
225187
226fn renderTopLevelDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Error || Error)!void {
227 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Newline);
188fn renderTopLevelDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, decl: *ast.Node) (@TypeOf(stream.*).Error || Error)!void {
189 try renderContainerDecl(allocator, stream, tree, decl, .Newline);
228190}
229191
230fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Error || Error)!void {
192fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, decl: *ast.Node, space: Space) (@TypeOf(stream.*).Error || Error)!void {
231193 switch (decl.tag) {
232194 .FnProto => {
233195 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
234196
235 try renderDocComments(tree, stream, fn_proto, fn_proto.getTrailer("doc_comments"), indent, start_col);
197 try renderDocComments(tree, stream, fn_proto, fn_proto.getTrailer("doc_comments"));
236198
237199 if (fn_proto.getTrailer("body_node")) |body_node| {
238 try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);
239 try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);
200 try renderExpression(allocator, stream, tree, decl, .Space);
201 try renderExpression(allocator, stream, tree, body_node, space);
240202 } else {
241 try renderExpression(allocator, stream, tree, indent, start_col, decl, .None);
242 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, start_col, space);
203 try renderExpression(allocator, stream, tree, decl, .None);
204 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), space);
243205 }
244206 },
245207
......@@ -247,35 +209,35 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
247209 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
248210
249211 if (use_decl.visib_token) |visib_token| {
250 try renderToken(tree, stream, visib_token, indent, start_col, .Space); // pub
212 try renderToken(tree, stream, visib_token, .Space); // pub
251213 }
252 try renderToken(tree, stream, use_decl.use_token, indent, start_col, .Space); // usingnamespace
253 try renderExpression(allocator, stream, tree, indent, start_col, use_decl.expr, .None);
254 try renderToken(tree, stream, use_decl.semicolon_token, indent, start_col, space); // ;
214 try renderToken(tree, stream, use_decl.use_token, .Space); // usingnamespace
215 try renderExpression(allocator, stream, tree, use_decl.expr, .None);
216 try renderToken(tree, stream, use_decl.semicolon_token, space); // ;
255217 },
256218
257219 .VarDecl => {
258220 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
259221
260 try renderDocComments(tree, stream, var_decl, var_decl.getTrailer("doc_comments"), indent, start_col);
261 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
222 try renderDocComments(tree, stream, var_decl, var_decl.getTrailer("doc_comments"));
223 try renderVarDecl(allocator, stream, tree, var_decl);
262224 },
263225
264226 .TestDecl => {
265227 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
266228
267 try renderDocComments(tree, stream, test_decl, test_decl.doc_comments, indent, start_col);
268 try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);
269 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);
270 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space);
229 try renderDocComments(tree, stream, test_decl, test_decl.doc_comments);
230 try renderToken(tree, stream, test_decl.test_token, .Space);
231 try renderExpression(allocator, stream, tree, test_decl.name, .Space);
232 try renderExpression(allocator, stream, tree, test_decl.body_node, space);
271233 },
272234
273235 .ContainerField => {
274236 const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
275237
276 try renderDocComments(tree, stream, field, field.doc_comments, indent, start_col);
238 try renderDocComments(tree, stream, field, field.doc_comments);
277239 if (field.comptime_token) |t| {
278 try renderToken(tree, stream, t, indent, start_col, .Space); // comptime
240 try renderToken(tree, stream, t, .Space); // comptime
279241 }
280242
281243 const src_has_trailing_comma = blk: {
......@@ -288,68 +250,67 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
288250 const last_token_space: Space = if (src_has_trailing_comma) .None else space;
289251
290252 if (field.type_expr == null and field.value_expr == null) {
291 try renderToken(tree, stream, field.name_token, indent, start_col, last_token_space); // name
253 try renderToken(tree, stream, field.name_token, last_token_space); // name
292254 } else if (field.type_expr != null and field.value_expr == null) {
293 try renderToken(tree, stream, field.name_token, indent, start_col, .None); // name
294 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // :
255 try renderToken(tree, stream, field.name_token, .None); // name
256 try renderToken(tree, stream, tree.nextToken(field.name_token), .Space); // :
295257
296258 if (field.align_expr) |align_value_expr| {
297 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type
259 try renderExpression(allocator, stream, tree, field.type_expr.?, .Space); // type
298260 const lparen_token = tree.prevToken(align_value_expr.firstToken());
299261 const align_kw = tree.prevToken(lparen_token);
300262 const rparen_token = tree.nextToken(align_value_expr.lastToken());
301 try renderToken(tree, stream, align_kw, indent, start_col, .None); // align
302 try renderToken(tree, stream, lparen_token, indent, start_col, .None); // (
303 try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment
304 try renderToken(tree, stream, rparen_token, indent, start_col, last_token_space); // )
263 try renderToken(tree, stream, align_kw, .None); // align
264 try renderToken(tree, stream, lparen_token, .None); // (
265 try renderExpression(allocator, stream, tree, align_value_expr, .None); // alignment
266 try renderToken(tree, stream, rparen_token, last_token_space); // )
305267 } else {
306 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, last_token_space); // type
268 try renderExpression(allocator, stream, tree, field.type_expr.?, last_token_space); // type
307269 }
308270 } else if (field.type_expr == null and field.value_expr != null) {
309 try renderToken(tree, stream, field.name_token, indent, start_col, .Space); // name
310 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // =
311 try renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, last_token_space); // value
271 try renderToken(tree, stream, field.name_token, .Space); // name
272 try renderToken(tree, stream, tree.nextToken(field.name_token), .Space); // =
273 try renderExpression(allocator, stream, tree, field.value_expr.?, last_token_space); // value
312274 } else {
313 try renderToken(tree, stream, field.name_token, indent, start_col, .None); // name
314 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // :
275 try renderToken(tree, stream, field.name_token, .None); // name
276 try renderToken(tree, stream, tree.nextToken(field.name_token), .Space); // :
315277
316278 if (field.align_expr) |align_value_expr| {
317 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type
279 try renderExpression(allocator, stream, tree, field.type_expr.?, .Space); // type
318280 const lparen_token = tree.prevToken(align_value_expr.firstToken());
319281 const align_kw = tree.prevToken(lparen_token);
320282 const rparen_token = tree.nextToken(align_value_expr.lastToken());
321 try renderToken(tree, stream, align_kw, indent, start_col, .None); // align
322 try renderToken(tree, stream, lparen_token, indent, start_col, .None); // (
323 try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment
324 try renderToken(tree, stream, rparen_token, indent, start_col, .Space); // )
283 try renderToken(tree, stream, align_kw, .None); // align
284 try renderToken(tree, stream, lparen_token, .None); // (
285 try renderExpression(allocator, stream, tree, align_value_expr, .None); // alignment
286 try renderToken(tree, stream, rparen_token, .Space); // )
325287 } else {
326 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type
288 try renderExpression(allocator, stream, tree, field.type_expr.?, .Space); // type
327289 }
328 try renderToken(tree, stream, tree.prevToken(field.value_expr.?.firstToken()), indent, start_col, .Space); // =
329 try renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, last_token_space); // value
290 try renderToken(tree, stream, tree.prevToken(field.value_expr.?.firstToken()), .Space); // =
291 try renderExpression(allocator, stream, tree, field.value_expr.?, last_token_space); // value
330292 }
331293
332294 if (src_has_trailing_comma) {
333295 const comma = tree.nextToken(field.lastToken());
334 try renderToken(tree, stream, comma, indent, start_col, space);
296 try renderToken(tree, stream, comma, space);
335297 }
336298 },
337299
338300 .Comptime => {
339301 assert(!decl.requireSemiColon());
340 try renderExpression(allocator, stream, tree, indent, start_col, decl, space);
302 try renderExpression(allocator, stream, tree, decl, space);
341303 },
342304
343305 .DocComment => {
344306 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);
345307 const kind = tree.token_ids[comment.first_line];
346 try renderToken(tree, stream, comment.first_line, indent, start_col, .Newline);
308 try renderToken(tree, stream, comment.first_line, .Newline);
347309 var tok_i = comment.first_line + 1;
348310 while (true) : (tok_i += 1) {
349311 const tok_id = tree.token_ids[tok_i];
350312 if (tok_id == kind) {
351 try stream.writeByteNTimes(' ', indent);
352 try renderToken(tree, stream, tok_i, indent, start_col, .Newline);
313 try renderToken(tree, stream, tok_i, .Newline);
353314 } else if (tok_id == .LineComment) {
354315 continue;
355316 } else {
......@@ -365,11 +326,9 @@ fn renderExpression(
365326 allocator: *mem.Allocator,
366327 stream: anytype,
367328 tree: *ast.Tree,
368 indent: usize,
369 start_col: *usize,
370329 base: *ast.Node,
371330 space: Space,
372) (@TypeOf(stream).Error || Error)!void {
331) (@TypeOf(stream.*).Error || Error)!void {
373332 switch (base.tag) {
374333 .Identifier,
375334 .IntegerLiteral,
......@@ -383,18 +342,18 @@ fn renderExpression(
383342 .UndefinedLiteral,
384343 => {
385344 const casted_node = base.cast(ast.Node.OneToken).?;
386 return renderToken(tree, stream, casted_node.token, indent, start_col, space);
345 return renderToken(tree, stream, casted_node.token, space);
387346 },
388347
389348 .AnyType => {
390349 const any_type = base.castTag(.AnyType).?;
391350 if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {
392351 // TODO remove in next release cycle
393 try stream.writeAll("anytype");
394 if (space == .Comma) try stream.writeAll(",\n");
352 try stream.writer().writeAll("anytype");
353 if (space == .Comma) try stream.writer().writeAll(",\n");
395354 return;
396355 }
397 return renderToken(tree, stream, any_type.token, indent, start_col, space);
356 return renderToken(tree, stream, any_type.token, space);
398357 },
399358
400359 .Block, .LabeledBlock => {
......@@ -424,65 +383,65 @@ fn renderExpression(
424383 };
425384
426385 if (block.label) |label| {
427 try renderToken(tree, stream, label, indent, start_col, Space.None);
428 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
386 try renderToken(tree, stream, label, Space.None);
387 try renderToken(tree, stream, tree.nextToken(label), Space.Space);
429388 }
430389
431390 if (block.statements.len == 0) {
432 try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None);
433 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
391 stream.pushIndentNextLine();
392 defer stream.popIndent();
393 try renderToken(tree, stream, block.lbrace, Space.None);
434394 } else {
435 const block_indent = indent + indent_delta;
436 try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);
395 stream.pushIndentNextLine();
396 defer stream.popIndent();
397
398 try renderToken(tree, stream, block.lbrace, Space.Newline);
437399
438400 for (block.statements) |statement, i| {
439 try stream.writeByteNTimes(' ', block_indent);
440 try renderStatement(allocator, stream, tree, block_indent, start_col, statement);
401 try renderStatement(allocator, stream, tree, statement);
441402
442403 if (i + 1 < block.statements.len) {
443 try renderExtraNewline(tree, stream, start_col, block.statements[i + 1]);
404 try renderExtraNewline(tree, stream, block.statements[i + 1]);
444405 }
445406 }
446
447 try stream.writeByteNTimes(' ', indent);
448 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
449407 }
408 return renderToken(tree, stream, block.rbrace, space);
450409 },
451410
452411 .Defer => {
453412 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
454413
455 try renderToken(tree, stream, defer_node.defer_token, indent, start_col, Space.Space);
414 try renderToken(tree, stream, defer_node.defer_token, Space.Space);
456415 if (defer_node.payload) |payload| {
457 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
416 try renderExpression(allocator, stream, tree, payload, Space.Space);
458417 }
459 return renderExpression(allocator, stream, tree, indent, start_col, defer_node.expr, space);
418 return renderExpression(allocator, stream, tree, defer_node.expr, space);
460419 },
461420 .Comptime => {
462421 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
463422
464 try renderToken(tree, stream, comptime_node.comptime_token, indent, start_col, Space.Space);
465 return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);
423 try renderToken(tree, stream, comptime_node.comptime_token, Space.Space);
424 return renderExpression(allocator, stream, tree, comptime_node.expr, space);
466425 },
467426 .Nosuspend => {
468427 const nosuspend_node = @fieldParentPtr(ast.Node.Nosuspend, "base", base);
469428 if (mem.eql(u8, tree.tokenSlice(nosuspend_node.nosuspend_token), "noasync")) {
470429 // TODO: remove this
471 try stream.writeAll("nosuspend ");
430 try stream.writer().writeAll("nosuspend ");
472431 } else {
473 try renderToken(tree, stream, nosuspend_node.nosuspend_token, indent, start_col, Space.Space);
432 try renderToken(tree, stream, nosuspend_node.nosuspend_token, Space.Space);
474433 }
475 return renderExpression(allocator, stream, tree, indent, start_col, nosuspend_node.expr, space);
434 return renderExpression(allocator, stream, tree, nosuspend_node.expr, space);
476435 },
477436
478437 .Suspend => {
479438 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
480439
481440 if (suspend_node.body) |body| {
482 try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
483 return renderExpression(allocator, stream, tree, indent, start_col, body, space);
441 try renderToken(tree, stream, suspend_node.suspend_token, Space.Space);
442 return renderExpression(allocator, stream, tree, body, space);
484443 } else {
485 return renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, space);
444 return renderToken(tree, stream, suspend_node.suspend_token, space);
486445 }
487446 },
488447
......@@ -490,26 +449,21 @@ fn renderExpression(
490449 const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base);
491450
492451 const op_space = Space.Space;
493 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
452 try renderExpression(allocator, stream, tree, infix_op_node.lhs, op_space);
494453
495454 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));
497 break :blk if (loc.line == 0) op_space else Space.Newline;
455 const same_line = tree.tokensOnSameLine(infix_op_node.op_token, tree.nextToken(infix_op_node.op_token));
456 break :blk if (same_line) op_space else Space.Newline;
498457 };
499458
500 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, 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 }
459 try renderToken(tree, stream, infix_op_node.op_token, after_op_space);
507460
508461 if (infix_op_node.payload) |payload| {
509 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
462 try renderExpression(allocator, stream, tree, payload, Space.Space);
510463 }
511464
512 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
465 stream.pushIndentOneShot();
466 return renderExpression(allocator, stream, tree, infix_op_node.rhs, space);
513467 },
514468
515469 .Add,
......@@ -561,22 +515,16 @@ fn renderExpression(
561515 .Period, .ErrorUnion, .Range => Space.None,
562516 else => Space.Space,
563517 };
564 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
518 try renderExpression(allocator, stream, tree, infix_op_node.lhs, op_space);
565519
566520 const after_op_space = blk: {
567521 const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
568522 break :blk if (loc.line == 0) op_space else Space.Newline;
569523 };
570524
571 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);
572 if (after_op_space == Space.Newline and
573 tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine)
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);
525 try renderToken(tree, stream, infix_op_node.op_token, after_op_space);
526 stream.pushIndentOneShot();
527 return renderExpression(allocator, stream, tree, infix_op_node.rhs, space);
580528 },
581529
582530 .BitNot,
......@@ -587,8 +535,8 @@ fn renderExpression(
587535 .AddressOf,
588536 => {
589537 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
590 try renderToken(tree, stream, casted_node.op_token, indent, start_col, Space.None);
591 return renderExpression(allocator, stream, tree, indent, start_col, casted_node.rhs, space);
538 try renderToken(tree, stream, casted_node.op_token, Space.None);
539 return renderExpression(allocator, stream, tree, casted_node.rhs, space);
592540 },
593541
594542 .Try,
......@@ -596,8 +544,8 @@ fn renderExpression(
596544 .Await,
597545 => {
598546 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
599 try renderToken(tree, stream, casted_node.op_token, indent, start_col, Space.Space);
600 return renderExpression(allocator, stream, tree, indent, start_col, casted_node.rhs, space);
547 try renderToken(tree, stream, casted_node.op_token, Space.Space);
548 return renderExpression(allocator, stream, tree, casted_node.rhs, space);
601549 },
602550
603551 .ArrayType => {
......@@ -606,8 +554,6 @@ fn renderExpression(
606554 allocator,
607555 stream,
608556 tree,
609 indent,
610 start_col,
611557 array_type.op_token,
612558 array_type.rhs,
613559 array_type.len_expr,
......@@ -621,8 +567,6 @@ fn renderExpression(
621567 allocator,
622568 stream,
623569 tree,
624 indent,
625 start_col,
626570 array_type.op_token,
627571 array_type.rhs,
628572 array_type.len_expr,
......@@ -635,111 +579,111 @@ fn renderExpression(
635579 const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
636580 const op_tok_id = tree.token_ids[ptr_type.op_token];
637581 switch (op_tok_id) {
638 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
582 .Asterisk, .AsteriskAsterisk => try stream.writer().writeByte('*'),
639583 .LBracket => if (tree.token_ids[ptr_type.op_token + 2] == .Identifier)
640 try stream.writeAll("[*c")
584 try stream.writer().writeAll("[*c")
641585 else
642 try stream.writeAll("[*"),
586 try stream.writer().writeAll("[*"),
643587 else => unreachable,
644588 }
645589 if (ptr_type.ptr_info.sentinel) |sentinel| {
646590 const colon_token = tree.prevToken(sentinel.firstToken());
647 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
591 try renderToken(tree, stream, colon_token, Space.None); // :
648592 const sentinel_space = switch (op_tok_id) {
649593 .LBracket => Space.None,
650594 else => Space.Space,
651595 };
652 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, sentinel_space);
596 try renderExpression(allocator, stream, tree, sentinel, sentinel_space);
653597 }
654598 switch (op_tok_id) {
655599 .Asterisk, .AsteriskAsterisk => {},
656 .LBracket => try stream.writeByte(']'),
600 .LBracket => try stream.writer().writeByte(']'),
657601 else => unreachable,
658602 }
659603 if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {
660 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
604 try renderToken(tree, stream, allowzero_token, Space.Space); // allowzero
661605 }
662606 if (ptr_type.ptr_info.align_info) |align_info| {
663607 const lparen_token = tree.prevToken(align_info.node.firstToken());
664608 const align_token = tree.prevToken(lparen_token);
665609
666 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
667 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
610 try renderToken(tree, stream, align_token, Space.None); // align
611 try renderToken(tree, stream, lparen_token, Space.None); // (
668612
669 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
613 try renderExpression(allocator, stream, tree, align_info.node, Space.None);
670614
671615 if (align_info.bit_range) |bit_range| {
672616 const colon1 = tree.prevToken(bit_range.start.firstToken());
673617 const colon2 = tree.prevToken(bit_range.end.firstToken());
674618
675 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
676 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
677 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
678 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
619 try renderToken(tree, stream, colon1, Space.None); // :
620 try renderExpression(allocator, stream, tree, bit_range.start, Space.None);
621 try renderToken(tree, stream, colon2, Space.None); // :
622 try renderExpression(allocator, stream, tree, bit_range.end, Space.None);
679623
680624 const rparen_token = tree.nextToken(bit_range.end.lastToken());
681 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
625 try renderToken(tree, stream, rparen_token, Space.Space); // )
682626 } else {
683627 const rparen_token = tree.nextToken(align_info.node.lastToken());
684 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
628 try renderToken(tree, stream, rparen_token, Space.Space); // )
685629 }
686630 }
687631 if (ptr_type.ptr_info.const_token) |const_token| {
688 try renderToken(tree, stream, const_token, indent, start_col, Space.Space); // const
632 try renderToken(tree, stream, const_token, Space.Space); // const
689633 }
690634 if (ptr_type.ptr_info.volatile_token) |volatile_token| {
691 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile
635 try renderToken(tree, stream, volatile_token, Space.Space); // volatile
692636 }
693 return renderExpression(allocator, stream, tree, indent, start_col, ptr_type.rhs, space);
637 return renderExpression(allocator, stream, tree, ptr_type.rhs, space);
694638 },
695639
696640 .SliceType => {
697641 const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
698 try renderToken(tree, stream, slice_type.op_token, indent, start_col, Space.None); // [
642 try renderToken(tree, stream, slice_type.op_token, Space.None); // [
699643 if (slice_type.ptr_info.sentinel) |sentinel| {
700644 const colon_token = tree.prevToken(sentinel.firstToken());
701 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
702 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
703 try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), indent, start_col, Space.None); // ]
645 try renderToken(tree, stream, colon_token, Space.None); // :
646 try renderExpression(allocator, stream, tree, sentinel, Space.None);
647 try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), Space.None); // ]
704648 } else {
705 try renderToken(tree, stream, tree.nextToken(slice_type.op_token), indent, start_col, Space.None); // ]
649 try renderToken(tree, stream, tree.nextToken(slice_type.op_token), Space.None); // ]
706650 }
707651
708652 if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
709 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
653 try renderToken(tree, stream, allowzero_token, Space.Space); // allowzero
710654 }
711655 if (slice_type.ptr_info.align_info) |align_info| {
712656 const lparen_token = tree.prevToken(align_info.node.firstToken());
713657 const align_token = tree.prevToken(lparen_token);
714658
715 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
716 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
659 try renderToken(tree, stream, align_token, Space.None); // align
660 try renderToken(tree, stream, lparen_token, Space.None); // (
717661
718 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
662 try renderExpression(allocator, stream, tree, align_info.node, Space.None);
719663
720664 if (align_info.bit_range) |bit_range| {
721665 const colon1 = tree.prevToken(bit_range.start.firstToken());
722666 const colon2 = tree.prevToken(bit_range.end.firstToken());
723667
724 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
725 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
726 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
727 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
668 try renderToken(tree, stream, colon1, Space.None); // :
669 try renderExpression(allocator, stream, tree, bit_range.start, Space.None);
670 try renderToken(tree, stream, colon2, Space.None); // :
671 try renderExpression(allocator, stream, tree, bit_range.end, Space.None);
728672
729673 const rparen_token = tree.nextToken(bit_range.end.lastToken());
730 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
674 try renderToken(tree, stream, rparen_token, Space.Space); // )
731675 } else {
732676 const rparen_token = tree.nextToken(align_info.node.lastToken());
733 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
677 try renderToken(tree, stream, rparen_token, Space.Space); // )
734678 }
735679 }
736680 if (slice_type.ptr_info.const_token) |const_token| {
737 try renderToken(tree, stream, const_token, indent, start_col, Space.Space);
681 try renderToken(tree, stream, const_token, Space.Space);
738682 }
739683 if (slice_type.ptr_info.volatile_token) |volatile_token| {
740 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space);
684 try renderToken(tree, stream, volatile_token, Space.Space);
741685 }
742 return renderExpression(allocator, stream, tree, indent, start_col, slice_type.rhs, space);
686 return renderExpression(allocator, stream, tree, slice_type.rhs, space);
743687 },
744688
745689 .ArrayInitializer, .ArrayInitializerDot => {
......@@ -768,27 +712,33 @@ fn renderExpression(
768712
769713 if (exprs.len == 0) {
770714 switch (lhs) {
771 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
772 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
715 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
716 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
717 }
718
719 {
720 stream.pushIndent();
721 defer stream.popIndent();
722 try renderToken(tree, stream, lbrace, Space.None);
773723 }
774 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
775 return renderToken(tree, stream, rtoken, indent, start_col, space);
776 }
777724
778 if (exprs.len == 1 and tree.token_ids[exprs[0].lastToken() + 1] == .RBrace) {
725 return renderToken(tree, stream, rtoken, space);
726 }
727 if (exprs.len == 1 and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
779728 const expr = exprs[0];
729
780730 switch (lhs) {
781 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
782 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
731 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
732 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
783733 }
784 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
785 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
786 return renderToken(tree, stream, rtoken, indent, start_col, space);
734 try renderToken(tree, stream, lbrace, Space.None);
735 try renderExpression(allocator, stream, tree, expr, Space.None);
736 return renderToken(tree, stream, rtoken, space);
787737 }
788738
789739 switch (lhs) {
790 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
791 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
740 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
741 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
792742 }
793743
794744 // scan to find row size
......@@ -832,77 +782,68 @@ fn renderExpression(
832782
833783 // Null stream for counting the printed length of each expression
834784 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
785 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &counting_stream);
835786
836787 for (exprs) |expr, i| {
837788 counting_stream.bytes_written = 0;
838 var dummy_col: usize = 0;
839 try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr, Space.None);
789 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
840790 const width = @intCast(usize, counting_stream.bytes_written);
841791 const col = i % row_size;
842792 column_widths[col] = std.math.max(column_widths[col], width);
843793 expr_widths[i] = width;
844794 }
845795
846 var new_indent = indent + indent_delta;
796 {
797 stream.pushIndentNextLine();
798 defer stream.popIndent();
799 try renderToken(tree, stream, lbrace, Space.Newline);
847800
848 if (tree.token_ids[tree.nextToken(lbrace)] != .MultilineStringLiteralLine) {
849 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
850 try stream.writeByteNTimes(' ', new_indent);
851 } else {
852 new_indent -= indent_delta;
853 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.None);
854 }
801 var col: usize = 1;
802 for (exprs) |expr, i| {
803 if (i + 1 < exprs.len) {
804 const next_expr = exprs[i + 1];
805 try renderExpression(allocator, stream, tree, expr, Space.None);
855806
856 var col: usize = 1;
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);
807 const comma = tree.nextToken(expr.*.lastToken());
861808
862 const comma = tree.nextToken(expr.lastToken());
809 if (col != row_size) {
810 try renderToken(tree, stream, comma, Space.Space); // ,
863811
864 if (col != row_size) {
865 try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // ,
812 const padding = column_widths[i % row_size] - expr_widths[i];
813 try stream.writer().writeByteNTimes(' ', padding);
866814
867 const padding = column_widths[i % row_size] - expr_widths[i];
868 try stream.writeByteNTimes(' ', padding);
815 col += 1;
816 continue;
817 }
818 col = 1;
869819
870 col += 1;
871 continue;
872 }
873 col = 1;
820 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
821 try renderToken(tree, stream, comma, Space.Newline); // ,
822 } else {
823 try renderToken(tree, stream, comma, Space.None); // ,
824 }
874825
875 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
876 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
826 try renderExtraNewline(tree, stream, next_expr);
877827 } else {
878 try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // ,
879 }
880
881 try renderExtraNewline(tree, stream, start_col, next_expr);
882 if (next_expr.tag != .MultilineStringLiteral) {
883 try stream.writeByteNTimes(' ', new_indent);
828 try renderExpression(allocator, stream, tree, expr, Space.Comma); // ,
884829 }
885 } else {
886 try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // ,
887830 }
888831 }
889 if (exprs[exprs.len - 1].tag != .MultilineStringLiteral) {
890 try stream.writeByteNTimes(' ', indent);
891 }
892 return renderToken(tree, stream, rtoken, indent, start_col, space);
832 return renderToken(tree, stream, rtoken, space);
893833 } else {
894 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
834 try renderToken(tree, stream, lbrace, Space.Space);
895835 for (exprs) |expr, i| {
896836 if (i + 1 < exprs.len) {
897 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
898 const comma = tree.nextToken(expr.lastToken());
899 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
837 const next_expr = exprs[i + 1];
838 try renderExpression(allocator, stream, tree, expr, Space.None);
839 const comma = tree.nextToken(expr.*.lastToken());
840 try renderToken(tree, stream, comma, Space.Space); // ,
900841 } else {
901 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.Space);
842 try renderExpression(allocator, stream, tree, expr, Space.Space);
902843 }
903844 }
904845
905 return renderToken(tree, stream, rtoken, indent, start_col, space);
846 return renderToken(tree, stream, rtoken, space);
906847 }
907848 },
908849
......@@ -932,11 +873,17 @@ fn renderExpression(
932873
933874 if (field_inits.len == 0) {
934875 switch (lhs) {
935 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
936 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
876 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
877 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
937878 }
938 try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None);
939 return renderToken(tree, stream, rtoken, indent, start_col, space);
879
880 {
881 stream.pushIndentNextLine();
882 defer stream.popIndent();
883 try renderToken(tree, stream, lbrace, Space.None);
884 }
885
886 return renderToken(tree, stream, rtoken, space);
940887 }
941888
942889 const src_has_trailing_comma = blk: {
......@@ -952,9 +899,10 @@ fn renderExpression(
952899 const expr_outputs_one_line = blk: {
953900 // render field expressions until a LF is found
954901 for (field_inits) |field_init| {
955 var find_stream = FindByteOutStream.init('\n');
956 var dummy_col: usize = 0;
957 try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init, Space.None);
902 var find_stream = std.io.findByteOutStream('\n', &std.io.null_out_stream);
903 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &find_stream);
904
905 try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None);
958906 if (find_stream.byte_found) break :blk false;
959907 }
960908 break :blk true;
......@@ -967,7 +915,6 @@ fn renderExpression(
967915 .StructInitializer,
968916 .StructInitializerDot,
969917 => break :blk,
970
971918 else => {},
972919 }
973920
......@@ -977,76 +924,78 @@ fn renderExpression(
977924 }
978925
979926 switch (lhs) {
980 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
981 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
927 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
928 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
982929 }
983 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
984 try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space);
985 return renderToken(tree, stream, rtoken, indent, start_col, space);
930 try renderToken(tree, stream, lbrace, Space.Space);
931 try renderExpression(allocator, stream, tree, &field_init.base, Space.Space);
932 return renderToken(tree, stream, rtoken, space);
986933 }
987934
988935 if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
989936 // render all on one line, no trailing comma
990937 switch (lhs) {
991 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
992 .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None),
938 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
939 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
993940 }
994 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
941 try renderToken(tree, stream, lbrace, Space.Space);
995942
996943 for (field_inits) |field_init, i| {
997944 if (i + 1 < field_inits.len) {
998 try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.None);
945 try renderExpression(allocator, stream, tree, field_init, Space.None);
999946
1000947 const comma = tree.nextToken(field_init.lastToken());
1001 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
948 try renderToken(tree, stream, comma, Space.Space);
1002949 } else {
1003 try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.Space);
950 try renderExpression(allocator, stream, tree, field_init, Space.Space);
1004951 }
1005952 }
1006953
1007 return renderToken(tree, stream, rtoken, indent, start_col, space);
954 return renderToken(tree, stream, rtoken, space);
1008955 }
1009956
1010 const new_indent = indent + indent_delta;
957 {
958 switch (lhs) {
959 .dot => |dot| try renderToken(tree, stream, dot, Space.None),
960 .node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
961 }
1011962
1012 switch (lhs) {
1013 .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None),
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);
963 stream.pushIndentNextLine();
964 defer stream.popIndent();
1017965
1018 for (field_inits) |field_init, i| {
1019 try stream.writeByteNTimes(' ', new_indent);
966 try renderToken(tree, stream, lbrace, Space.Newline);
1020967
1021 if (i + 1 < field_inits.len) {
1022 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.None);
968 for (field_inits) |field_init, i| {
969 if (i + 1 < field_inits.len) {
970 const next_field_init = field_inits[i + 1];
971 try renderExpression(allocator, stream, tree, field_init, Space.None);
1023972
1024 const comma = tree.nextToken(field_init.lastToken());
1025 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline);
973 const comma = tree.nextToken(field_init.lastToken());
974 try renderToken(tree, stream, comma, Space.Newline);
1026975
1027 try renderExtraNewline(tree, stream, start_col, field_inits[i + 1]);
1028 } else {
1029 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.Comma);
976 try renderExtraNewline(tree, stream, next_field_init);
977 } else {
978 try renderExpression(allocator, stream, tree, field_init, Space.Comma);
979 }
1030980 }
1031981 }
1032982
1033 try stream.writeByteNTimes(' ', indent);
1034 return renderToken(tree, stream, rtoken, indent, start_col, space);
983 return renderToken(tree, stream, rtoken, space);
1035984 },
1036985
1037986 .Call => {
1038987 const call = @fieldParentPtr(ast.Node.Call, "base", base);
1039988 if (call.async_token) |async_token| {
1040 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
989 try renderToken(tree, stream, async_token, Space.Space);
1041990 }
1042991
1043 try renderExpression(allocator, stream, tree, indent, start_col, call.lhs, Space.None);
992 try renderExpression(allocator, stream, tree, call.lhs, Space.None);
1044993
1045994 const lparen = tree.nextToken(call.lhs.lastToken());
1046995
1047996 if (call.params_len == 0) {
1048 try renderToken(tree, stream, lparen, indent, start_col, Space.None);
1049 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
997 try renderToken(tree, stream, lparen, Space.None);
998 return renderToken(tree, stream, call.rtoken, space);
1050999 }
10511000
10521001 const src_has_trailing_comma = blk: {
......@@ -1055,43 +1004,41 @@ fn renderExpression(
10551004 };
10561005
10571006 if (src_has_trailing_comma) {
1058 const new_indent = indent + indent_delta;
1059 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
1007 try renderToken(tree, stream, lparen, Space.Newline);
10601008
10611009 const params = call.params();
10621010 for (params) |param_node, i| {
1063 const param_node_new_indent = if (param_node.tag == .MultilineStringLiteral) blk: {
1064 break :blk indent;
1065 } else blk: {
1066 try stream.writeByteNTimes(' ', new_indent);
1067 break :blk new_indent;
1068 };
1011 stream.pushIndent();
1012 defer stream.popIndent();
10691013
10701014 if (i + 1 < params.len) {
1071 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);
1015 const next_node = params[i + 1];
1016 try renderExpression(allocator, stream, tree, param_node, Space.None);
10721017 const comma = tree.nextToken(param_node.lastToken());
1073 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
1074 try renderExtraNewline(tree, stream, start_col, params[i + 1]);
1018 try renderToken(tree, stream, comma, Space.Newline); // ,
1019 try renderExtraNewline(tree, stream, next_node);
10751020 } else {
1076 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);
1077 try stream.writeByteNTimes(' ', indent);
1078 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
1021 try renderExpression(allocator, stream, tree, param_node, Space.Comma);
10791022 }
10801023 }
1024 return renderToken(tree, stream, call.rtoken, space);
10811025 }
10821026
1083 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1027 try renderToken(tree, stream, lparen, Space.None); // (
10841028
10851029 const params = call.params();
10861030 for (params) |param_node, i| {
1087 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
1031 if (param_node.*.tag == .MultilineStringLiteral) stream.pushIndentOneShot();
1032
1033 try renderExpression(allocator, stream, tree, param_node, Space.None);
10881034
10891035 if (i + 1 < params.len) {
1036 const next_param = params[i + 1];
10901037 const comma = tree.nextToken(param_node.lastToken());
1091 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
1038 try renderToken(tree, stream, comma, Space.Space);
10921039 }
10931040 }
1094 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
1041 return renderToken(tree, stream, call.rtoken, space);
10951042 },
10961043
10971044 .ArrayAccess => {
......@@ -1100,26 +1047,25 @@ fn renderExpression(
11001047 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
11011048 const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());
11021049
1103 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1104 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
1050 try renderExpression(allocator, stream, tree, suffix_op.lhs, Space.None);
1051 try renderToken(tree, stream, lbracket, Space.None); // [
11051052
11061053 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
11071054 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
1108 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
1109 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);
1111 if (starts_with_comment) {
1112 try stream.writeByte('\n');
1113 }
1114 if (ends_with_comment or starts_with_comment) {
1115 try stream.writeByteNTimes(' ', indent);
1055 {
1056 const new_space = if (ends_with_comment) Space.Newline else Space.None;
1057
1058 stream.pushIndent();
1059 defer stream.popIndent();
1060 try renderExpression(allocator, stream, tree, suffix_op.index_expr, new_space);
11161061 }
1117 return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
1062 if (starts_with_comment) try stream.maybeInsertNewline();
1063 return renderToken(tree, stream, rbracket, space); // ]
11181064 },
1065
11191066 .Slice => {
11201067 const suffix_op = base.castTag(.Slice).?;
1121
1122 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1068 try renderExpression(allocator, stream, tree, suffix_op.lhs, Space.None);
11231069
11241070 const lbracket = tree.prevToken(suffix_op.start.firstToken());
11251071 const dotdot = tree.nextToken(suffix_op.start.lastToken());
......@@ -1129,32 +1075,33 @@ fn renderExpression(
11291075 const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
11301076 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); // [
1133 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.start, after_start_space);
1134 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
1078 try renderToken(tree, stream, lbracket, Space.None); // [
1079 try renderExpression(allocator, stream, tree, suffix_op.start, after_start_space);
1080 try renderToken(tree, stream, dotdot, after_op_space); // ..
11351081 if (suffix_op.end) |end| {
11361082 const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;
1137 try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);
1083 try renderExpression(allocator, stream, tree, end, after_end_space);
11381084 }
11391085 if (suffix_op.sentinel) |sentinel| {
11401086 const colon = tree.prevToken(sentinel.firstToken());
1141 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1142 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
1087 try renderToken(tree, stream, colon, Space.None); // :
1088 try renderExpression(allocator, stream, tree, sentinel, Space.None);
11431089 }
1144 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
1090 return renderToken(tree, stream, suffix_op.rtoken, space); // ]
11451091 },
1092
11461093 .Deref => {
11471094 const suffix_op = base.castTag(.Deref).?;
11481095
1149 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1150 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
1096 try renderExpression(allocator, stream, tree, suffix_op.lhs, Space.None);
1097 return renderToken(tree, stream, suffix_op.rtoken, space); // .*
11511098 },
11521099 .UnwrapOptional => {
11531100 const suffix_op = base.castTag(.UnwrapOptional).?;
11541101
1155 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1156 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
1157 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
1102 try renderExpression(allocator, stream, tree, suffix_op.lhs, Space.None);
1103 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), Space.None); // .
1104 return renderToken(tree, stream, suffix_op.rtoken, space); // ?
11581105 },
11591106
11601107 .Break => {
......@@ -1163,145 +1110,152 @@ fn renderExpression(
11631110 const maybe_label = flow_expr.getLabel();
11641111
11651112 if (maybe_label == null and maybe_rhs == null) {
1166 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // break
1113 return renderToken(tree, stream, flow_expr.ltoken, space); // break
11671114 }
11681115
1169 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // break
1116 try renderToken(tree, stream, flow_expr.ltoken, Space.Space); // break
11701117 if (maybe_label) |label| {
11711118 const colon = tree.nextToken(flow_expr.ltoken);
1172 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1119 try renderToken(tree, stream, colon, Space.None); // :
11731120
11741121 if (maybe_rhs == null) {
1175 return renderToken(tree, stream, label, indent, start_col, space); // label
1122 return renderToken(tree, stream, label, space); // label
11761123 }
1177 try renderToken(tree, stream, label, indent, start_col, Space.Space); // label
1124 try renderToken(tree, stream, label, Space.Space); // label
11781125 }
1179 return renderExpression(allocator, stream, tree, indent, start_col, maybe_rhs.?, space);
1126 return renderExpression(allocator, stream, tree, maybe_rhs.?, space);
11801127 },
11811128
11821129 .Continue => {
11831130 const flow_expr = base.castTag(.Continue).?;
11841131 if (flow_expr.getLabel()) |label| {
1185 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // continue
1132 try renderToken(tree, stream, flow_expr.ltoken, Space.Space); // continue
11861133 const colon = tree.nextToken(flow_expr.ltoken);
1187 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1188 return renderToken(tree, stream, label, indent, start_col, space); // label
1134 try renderToken(tree, stream, colon, Space.None); // :
1135 return renderToken(tree, stream, label, space); // label
11891136 } else {
1190 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // continue
1137 return renderToken(tree, stream, flow_expr.ltoken, space); // continue
11911138 }
11921139 },
11931140
11941141 .Return => {
11951142 const flow_expr = base.castTag(.Return).?;
11961143 if (flow_expr.getRHS()) |rhs| {
1197 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space);
1198 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);
1144 try renderToken(tree, stream, flow_expr.ltoken, Space.Space);
1145 return renderExpression(allocator, stream, tree, rhs, space);
11991146 } else {
1200 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space);
1147 return renderToken(tree, stream, flow_expr.ltoken, space);
12011148 }
12021149 },
12031150
12041151 .Payload => {
12051152 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
12061153
1207 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);
1208 try renderExpression(allocator, stream, tree, indent, start_col, payload.error_symbol, Space.None);
1209 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);
1154 try renderToken(tree, stream, payload.lpipe, Space.None);
1155 try renderExpression(allocator, stream, tree, payload.error_symbol, Space.None);
1156 return renderToken(tree, stream, payload.rpipe, space);
12101157 },
12111158
12121159 .PointerPayload => {
12131160 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
12141161
1215 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);
1162 try renderToken(tree, stream, payload.lpipe, Space.None);
12161163 if (payload.ptr_token) |ptr_token| {
1217 try renderToken(tree, stream, ptr_token, indent, start_col, Space.None);
1164 try renderToken(tree, stream, ptr_token, Space.None);
12181165 }
1219 try renderExpression(allocator, stream, tree, indent, start_col, payload.value_symbol, Space.None);
1220 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);
1166 try renderExpression(allocator, stream, tree, payload.value_symbol, Space.None);
1167 return renderToken(tree, stream, payload.rpipe, space);
12211168 },
12221169
12231170 .PointerIndexPayload => {
12241171 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
12251172
1226 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);
1173 try renderToken(tree, stream, payload.lpipe, Space.None);
12271174 if (payload.ptr_token) |ptr_token| {
1228 try renderToken(tree, stream, ptr_token, indent, start_col, Space.None);
1175 try renderToken(tree, stream, ptr_token, Space.None);
12291176 }
1230 try renderExpression(allocator, stream, tree, indent, start_col, payload.value_symbol, Space.None);
1177 try renderExpression(allocator, stream, tree, payload.value_symbol, Space.None);
12311178
12321179 if (payload.index_symbol) |index_symbol| {
12331180 const comma = tree.nextToken(payload.value_symbol.lastToken());
12341181
1235 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
1236 try renderExpression(allocator, stream, tree, indent, start_col, index_symbol, Space.None);
1182 try renderToken(tree, stream, comma, Space.Space);
1183 try renderExpression(allocator, stream, tree, index_symbol, Space.None);
12371184 }
12381185
1239 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);
1186 return renderToken(tree, stream, payload.rpipe, space);
12401187 },
12411188
12421189 .GroupedExpression => {
12431190 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
12441191
1245 try renderToken(tree, stream, grouped_expr.lparen, indent, start_col, Space.None);
1246 try renderExpression(allocator, stream, tree, indent, start_col, grouped_expr.expr, Space.None);
1247 return renderToken(tree, stream, grouped_expr.rparen, indent, start_col, space);
1192 try renderToken(tree, stream, grouped_expr.lparen, Space.None);
1193 {
1194 stream.pushIndentOneShot();
1195 try renderExpression(allocator, stream, tree, grouped_expr.expr, Space.None);
1196 }
1197 return renderToken(tree, stream, grouped_expr.rparen, space);
12481198 },
12491199
12501200 .FieldInitializer => {
12511201 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
12521202
1253 try renderToken(tree, stream, field_init.period_token, indent, start_col, Space.None); // .
1254 try renderToken(tree, stream, field_init.name_token, indent, start_col, Space.Space); // name
1255 try renderToken(tree, stream, tree.nextToken(field_init.name_token), indent, start_col, Space.Space); // =
1256 return renderExpression(allocator, stream, tree, indent, start_col, field_init.expr, space);
1203 try renderToken(tree, stream, field_init.period_token, Space.None); // .
1204 try renderToken(tree, stream, field_init.name_token, Space.Space); // name
1205 try renderToken(tree, stream, tree.nextToken(field_init.name_token), Space.Space); // =
1206 return renderExpression(allocator, stream, tree, field_init.expr, space);
12571207 },
12581208
12591209 .ContainerDecl => {
12601210 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
12611211
12621212 if (container_decl.layout_token) |layout_token| {
1263 try renderToken(tree, stream, layout_token, indent, start_col, Space.Space);
1213 try renderToken(tree, stream, layout_token, Space.Space);
12641214 }
12651215
12661216 switch (container_decl.init_arg_expr) {
12671217 .None => {
1268 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.Space); // union
1218 try renderToken(tree, stream, container_decl.kind_token, Space.Space); // union
12691219 },
12701220 .Enum => |enum_tag_type| {
1271 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union
1221 try renderToken(tree, stream, container_decl.kind_token, Space.None); // union
12721222
12731223 const lparen = tree.nextToken(container_decl.kind_token);
12741224 const enum_token = tree.nextToken(lparen);
12751225
1276 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1277 try renderToken(tree, stream, enum_token, indent, start_col, Space.None); // enum
1226 try renderToken(tree, stream, lparen, Space.None); // (
1227 try renderToken(tree, stream, enum_token, Space.None); // enum
12781228
12791229 if (enum_tag_type) |expr| {
1280 try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.None); // (
1281 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
1230 try renderToken(tree, stream, tree.nextToken(enum_token), Space.None); // (
1231 try renderExpression(allocator, stream, tree, expr, Space.None);
12821232
12831233 const rparen = tree.nextToken(expr.lastToken());
1284 try renderToken(tree, stream, rparen, indent, start_col, Space.None); // )
1285 try renderToken(tree, stream, tree.nextToken(rparen), indent, start_col, Space.Space); // )
1234 try renderToken(tree, stream, rparen, Space.None); // )
1235 try renderToken(tree, stream, tree.nextToken(rparen), Space.Space); // )
12861236 } else {
1287 try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.Space); // )
1237 try renderToken(tree, stream, tree.nextToken(enum_token), Space.Space); // )
12881238 }
12891239 },
12901240 .Type => |type_expr| {
1291 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union
1241 try renderToken(tree, stream, container_decl.kind_token, Space.None); // union
12921242
12931243 const lparen = tree.nextToken(container_decl.kind_token);
12941244 const rparen = tree.nextToken(type_expr.lastToken());
12951245
1296 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1297 try renderExpression(allocator, stream, tree, indent, start_col, type_expr, Space.None);
1298 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1246 try renderToken(tree, stream, lparen, Space.None); // (
1247 try renderExpression(allocator, stream, tree, type_expr, Space.None);
1248 try renderToken(tree, stream, rparen, Space.Space); // )
12991249 },
13001250 }
13011251
13021252 if (container_decl.fields_and_decls_len == 0) {
1303 try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // {
1304 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }
1253 {
1254 stream.pushIndentNextLine();
1255 defer stream.popIndent();
1256 try renderToken(tree, stream, container_decl.lbrace_token, Space.None); // {
1257 }
1258 return renderToken(tree, stream, container_decl.rbrace_token, space); // }
13051259 }
13061260
13071261 const src_has_trailing_comma = blk: {
......@@ -1332,43 +1286,39 @@ fn renderExpression(
13321286
13331287 if (src_has_trailing_comma or !src_has_only_fields) {
13341288 // One declaration per line
1335 const new_indent = indent + indent_delta;
1336 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // {
1289 stream.pushIndentNextLine();
1290 defer stream.popIndent();
1291 try renderToken(tree, stream, container_decl.lbrace_token, .Newline); // {
13371292
13381293 for (fields_and_decls) |decl, i| {
1339 try stream.writeByteNTimes(' ', new_indent);
1340 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, .Newline);
1294 try renderContainerDecl(allocator, stream, tree, decl, .Newline);
13411295
13421296 if (i + 1 < fields_and_decls.len) {
1343 try renderExtraNewline(tree, stream, start_col, fields_and_decls[i + 1]);
1297 try renderExtraNewline(tree, stream, fields_and_decls[i + 1]);
13441298 }
13451299 }
1346
1347 try stream.writeByteNTimes(' ', indent);
13481300 } else if (src_has_newline) {
13491301 // All the declarations on the same line, but place the items on
13501302 // their own line
1351 try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Newline); // {
1303 try renderToken(tree, stream, container_decl.lbrace_token, .Newline); // {
13521304
1353 const new_indent = indent + indent_delta;
1354 try stream.writeByteNTimes(' ', new_indent);
1305 stream.pushIndent();
1306 defer stream.popIndent();
13551307
13561308 for (fields_and_decls) |decl, i| {
13571309 const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space;
1358 try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, space_after_decl);
1310 try renderContainerDecl(allocator, stream, tree, decl, space_after_decl);
13591311 }
1360
1361 try stream.writeByteNTimes(' ', indent);
13621312 } else {
13631313 // All the declarations on the same line
1364 try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // {
1314 try renderToken(tree, stream, container_decl.lbrace_token, .Space); // {
13651315
13661316 for (fields_and_decls) |decl| {
1367 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Space);
1317 try renderContainerDecl(allocator, stream, tree, decl, .Space);
13681318 }
13691319 }
13701320
1371 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }
1321 return renderToken(tree, stream, container_decl.rbrace_token, space); // }
13721322 },
13731323
13741324 .ErrorSetDecl => {
......@@ -1377,9 +1327,9 @@ fn renderExpression(
13771327 const lbrace = tree.nextToken(err_set_decl.error_token);
13781328
13791329 if (err_set_decl.decls_len == 0) {
1380 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);
1381 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
1382 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);
1330 try renderToken(tree, stream, err_set_decl.error_token, Space.None);
1331 try renderToken(tree, stream, lbrace, Space.None);
1332 return renderToken(tree, stream, err_set_decl.rbrace_token, space);
13831333 }
13841334
13851335 if (err_set_decl.decls_len == 1) blk: {
......@@ -1393,13 +1343,13 @@ fn renderExpression(
13931343 break :blk;
13941344 }
13951345
1396 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error
1397 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
1398 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
1399 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }
1346 try renderToken(tree, stream, err_set_decl.error_token, Space.None); // error
1347 try renderToken(tree, stream, lbrace, Space.None); // {
1348 try renderExpression(allocator, stream, tree, node, Space.None);
1349 return renderToken(tree, stream, err_set_decl.rbrace_token, space); // }
14001350 }
14011351
1402 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error
1352 try renderToken(tree, stream, err_set_decl.error_token, Space.None); // error
14031353
14041354 const src_has_trailing_comma = blk: {
14051355 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
......@@ -1407,78 +1357,72 @@ fn renderExpression(
14071357 };
14081358
14091359 if (src_has_trailing_comma) {
1410 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
1411 const new_indent = indent + indent_delta;
1412
1413 const decls = err_set_decl.decls();
1414 for (decls) |node, i| {
1415 try stream.writeByteNTimes(' ', new_indent);
1416
1417 if (i + 1 < decls.len) {
1418 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);
1419 try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // ,
1420
1421 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
1422 } else {
1423 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
1360 {
1361 stream.pushIndent();
1362 defer stream.popIndent();
1363
1364 try renderToken(tree, stream, lbrace, Space.Newline); // {
1365 const decls = err_set_decl.decls();
1366 for (decls) |node, i| {
1367 if (i + 1 < decls.len) {
1368 try renderExpression(allocator, stream, tree, node, Space.None);
1369 try renderToken(tree, stream, tree.nextToken(node.lastToken()), Space.Newline); // ,
1370
1371 try renderExtraNewline(tree, stream, decls[i + 1]);
1372 } else {
1373 try renderExpression(allocator, stream, tree, node, Space.Comma);
1374 }
14241375 }
14251376 }
14261377
1427 try stream.writeByteNTimes(' ', indent);
1428 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }
1378 return renderToken(tree, stream, err_set_decl.rbrace_token, space); // }
14291379 } else {
1430 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {
1380 try renderToken(tree, stream, lbrace, Space.Space); // {
14311381
14321382 const decls = err_set_decl.decls();
14331383 for (decls) |node, i| {
14341384 if (i + 1 < decls.len) {
1435 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
1385 try renderExpression(allocator, stream, tree, node, Space.None);
14361386
14371387 const comma_token = tree.nextToken(node.lastToken());
14381388 assert(tree.token_ids[comma_token] == .Comma);
1439 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1440 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
1389 try renderToken(tree, stream, comma_token, Space.Space); // ,
1390 try renderExtraNewline(tree, stream, decls[i + 1]);
14411391 } else {
1442 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
1392 try renderExpression(allocator, stream, tree, node, Space.Space);
14431393 }
14441394 }
14451395
1446 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }
1396 return renderToken(tree, stream, err_set_decl.rbrace_token, space); // }
14471397 }
14481398 },
14491399
14501400 .ErrorTag => {
14511401 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
14521402
1453 try renderDocComments(tree, stream, tag, tag.doc_comments, indent, start_col);
1454 return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name
1403 try renderDocComments(tree, stream, tag, tag.doc_comments);
1404 return renderToken(tree, stream, tag.name_token, space); // name
14551405 },
14561406
14571407 .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
14601408 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
14611409
1462 var skip_first_indent = true;
1463 if (tree.token_ids[multiline_str_literal.firstToken() - 1] != .LineComment) {
1464 try stream.print("\n", .{});
1465 skip_first_indent = false;
1466 }
1467
1468 for (multiline_str_literal.lines()) |t| {
1469 if (!skip_first_indent) {
1470 try stream.writeByteNTimes(' ', indent + indent_delta);
1410 {
1411 const locked_indents = stream.lockOneShotIndent();
1412 defer {
1413 var i: u8 = 0;
1414 while (i < locked_indents) : (i += 1) stream.popIndent();
14711415 }
1472 try renderToken(tree, stream, t, indent, start_col, Space.None);
1473 skip_first_indent = false;
1416 try stream.maybeInsertNewline();
1417
1418 for (multiline_str_literal.lines()) |t| try renderToken(tree, stream, t, Space.None);
14741419 }
1475 try stream.writeByteNTimes(' ', indent);
14761420 },
14771421
14781422 .BuiltinCall => {
14791423 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
14801424
1481 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
1425 try renderToken(tree, stream, builtin_call.builtin_token, Space.None); // @name
14821426
14831427 const src_params_trailing_comma = blk: {
14841428 if (builtin_call.params_len < 2) break :blk false;
......@@ -1490,31 +1434,30 @@ fn renderExpression(
14901434 const lparen = tree.nextToken(builtin_call.builtin_token);
14911435
14921436 if (!src_params_trailing_comma) {
1493 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1437 try renderToken(tree, stream, lparen, Space.None); // (
14941438
14951439 // render all on one line, no trailing comma
14961440 const params = builtin_call.params();
14971441 for (params) |param_node, i| {
1498 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
1442 try renderExpression(allocator, stream, tree, param_node, Space.None);
14991443
15001444 if (i + 1 < params.len) {
15011445 const comma_token = tree.nextToken(param_node.lastToken());
1502 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1446 try renderToken(tree, stream, comma_token, Space.Space); // ,
15031447 }
15041448 }
15051449 } else {
15061450 // one param per line
1507 const new_indent = indent + indent_delta;
1508 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
1451 stream.pushIndent();
1452 defer stream.popIndent();
1453 try renderToken(tree, stream, lparen, Space.Newline); // (
15091454
15101455 for (builtin_call.params()) |param_node| {
1511 try stream.writeByteNTimes(' ', new_indent);
1512 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);
1456 try renderExpression(allocator, stream, tree, param_node, Space.Comma);
15131457 }
1514 try stream.writeByteNTimes(' ', indent);
15151458 }
15161459
1517 return renderToken(tree, stream, builtin_call.rparen_token, indent, start_col, space); // )
1460 return renderToken(tree, stream, builtin_call.rparen_token, space); // )
15181461 },
15191462
15201463 .FnProto => {
......@@ -1524,24 +1467,24 @@ fn renderExpression(
15241467 const visib_token = tree.token_ids[visib_token_index];
15251468 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
15261469
1527 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
1470 try renderToken(tree, stream, visib_token_index, Space.Space); // pub
15281471 }
15291472
15301473 if (fn_proto.getTrailer("extern_export_inline_token")) |extern_export_inline_token| {
15311474 if (fn_proto.getTrailer("is_extern_prototype") == null)
1532 try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline
1475 try renderToken(tree, stream, extern_export_inline_token, Space.Space); // extern/export/inline
15331476 }
15341477
15351478 if (fn_proto.getTrailer("lib_name")) |lib_name| {
1536 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);
1479 try renderExpression(allocator, stream, tree, lib_name, Space.Space);
15371480 }
15381481
15391482 const lparen = if (fn_proto.getTrailer("name_token")) |name_token| blk: {
1540 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
1541 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
1483 try renderToken(tree, stream, fn_proto.fn_token, Space.Space); // fn
1484 try renderToken(tree, stream, name_token, Space.None); // name
15421485 break :blk tree.nextToken(name_token);
15431486 } else blk: {
1544 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
1487 try renderToken(tree, stream, fn_proto.fn_token, Space.Space); // fn
15451488 break :blk tree.nextToken(fn_proto.fn_token);
15461489 };
15471490 assert(tree.token_ids[lparen] == .LParen);
......@@ -1568,47 +1511,45 @@ fn renderExpression(
15681511 };
15691512
15701513 if (!src_params_trailing_comma) {
1571 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1514 try renderToken(tree, stream, lparen, Space.None); // (
15721515
15731516 // render all on one line, no trailing comma
15741517 for (fn_proto.params()) |param_decl, i| {
1575 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);
1518 try renderParamDecl(allocator, stream, tree, param_decl, Space.None);
15761519
15771520 if (i + 1 < fn_proto.params_len or fn_proto.getTrailer("var_args_token") != null) {
15781521 const comma = tree.nextToken(param_decl.lastToken());
1579 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
1522 try renderToken(tree, stream, comma, Space.Space); // ,
15801523 }
15811524 }
15821525 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1583 try renderToken(tree, stream, var_args_token, indent, start_col, Space.None);
1526 try renderToken(tree, stream, var_args_token, Space.None);
15841527 }
15851528 } else {
15861529 // one param per line
1587 const new_indent = indent + indent_delta;
1588 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
1530 stream.pushIndent();
1531 defer stream.popIndent();
1532 try renderToken(tree, stream, lparen, Space.Newline); // (
15891533
15901534 for (fn_proto.params()) |param_decl| {
1591 try stream.writeByteNTimes(' ', new_indent);
1592 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
1535 try renderParamDecl(allocator, stream, tree, param_decl, Space.Comma);
15931536 }
15941537 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1595 try stream.writeByteNTimes(' ', new_indent);
1596 try renderToken(tree, stream, var_args_token, new_indent, start_col, Space.Comma);
1538 try renderToken(tree, stream, var_args_token, Space.Comma);
15971539 }
1598 try stream.writeByteNTimes(' ', indent);
15991540 }
16001541
1601 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1542 try renderToken(tree, stream, rparen, Space.Space); // )
16021543
16031544 if (fn_proto.getTrailer("align_expr")) |align_expr| {
16041545 const align_rparen = tree.nextToken(align_expr.lastToken());
16051546 const align_lparen = tree.prevToken(align_expr.firstToken());
16061547 const align_kw = tree.prevToken(align_lparen);
16071548
1608 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
1609 try renderToken(tree, stream, align_lparen, indent, start_col, Space.None); // (
1610 try renderExpression(allocator, stream, tree, indent, start_col, align_expr, Space.None);
1611 try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )
1549 try renderToken(tree, stream, align_kw, Space.None); // align
1550 try renderToken(tree, stream, align_lparen, Space.None); // (
1551 try renderExpression(allocator, stream, tree, align_expr, Space.None);
1552 try renderToken(tree, stream, align_rparen, Space.Space); // )
16121553 }
16131554
16141555 if (fn_proto.getTrailer("section_expr")) |section_expr| {
......@@ -1616,10 +1557,10 @@ fn renderExpression(
16161557 const section_lparen = tree.prevToken(section_expr.firstToken());
16171558 const section_kw = tree.prevToken(section_lparen);
16181559
1619 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // section
1620 try renderToken(tree, stream, section_lparen, indent, start_col, Space.None); // (
1621 try renderExpression(allocator, stream, tree, indent, start_col, section_expr, Space.None);
1622 try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )
1560 try renderToken(tree, stream, section_kw, Space.None); // section
1561 try renderToken(tree, stream, section_lparen, Space.None); // (
1562 try renderExpression(allocator, stream, tree, section_expr, Space.None);
1563 try renderToken(tree, stream, section_rparen, Space.Space); // )
16231564 }
16241565
16251566 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
......@@ -1627,23 +1568,23 @@ fn renderExpression(
16271568 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
16281569 const callconv_kw = tree.prevToken(callconv_lparen);
16291570
1630 try renderToken(tree, stream, callconv_kw, indent, start_col, Space.None); // callconv
1631 try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (
1632 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
1633 try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )
1571 try renderToken(tree, stream, callconv_kw, Space.None); // callconv
1572 try renderToken(tree, stream, callconv_lparen, Space.None); // (
1573 try renderExpression(allocator, stream, tree, callconv_expr, Space.None);
1574 try renderToken(tree, stream, callconv_rparen, Space.Space); // )
16341575 } else if (fn_proto.getTrailer("is_extern_prototype") != null) {
1635 try stream.writeAll("callconv(.C) ");
1576 try stream.writer().writeAll("callconv(.C) ");
16361577 } else if (fn_proto.getTrailer("is_async") != null) {
1637 try stream.writeAll("callconv(.Async) ");
1578 try stream.writer().writeAll("callconv(.Async) ");
16381579 }
16391580
16401581 switch (fn_proto.return_type) {
16411582 .Explicit => |node| {
1642 return renderExpression(allocator, stream, tree, indent, start_col, node, space);
1583 return renderExpression(allocator, stream, tree, node, space);
16431584 },
16441585 .InferErrorSet => |node| {
1645 try renderToken(tree, stream, tree.prevToken(node.firstToken()), indent, start_col, Space.None); // !
1646 return renderExpression(allocator, stream, tree, indent, start_col, node, space);
1586 try renderToken(tree, stream, tree.prevToken(node.firstToken()), Space.None); // !
1587 return renderExpression(allocator, stream, tree, node, space);
16471588 },
16481589 .Invalid => unreachable,
16491590 }
......@@ -1653,11 +1594,11 @@ fn renderExpression(
16531594 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
16541595
16551596 if (anyframe_type.result) |result| {
1656 try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe
1657 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->
1658 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);
1597 try renderToken(tree, stream, anyframe_type.anyframe_token, Space.None); // anyframe
1598 try renderToken(tree, stream, result.arrow_token, Space.None); // ->
1599 return renderExpression(allocator, stream, tree, result.return_type, space);
16591600 } else {
1660 return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe
1601 return renderToken(tree, stream, anyframe_type.anyframe_token, space); // anyframe
16611602 }
16621603 },
16631604
......@@ -1666,38 +1607,38 @@ fn renderExpression(
16661607 .Switch => {
16671608 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
16681609
1669 try renderToken(tree, stream, switch_node.switch_token, indent, start_col, Space.Space); // switch
1670 try renderToken(tree, stream, tree.nextToken(switch_node.switch_token), indent, start_col, Space.None); // (
1610 try renderToken(tree, stream, switch_node.switch_token, Space.Space); // switch
1611 try renderToken(tree, stream, tree.nextToken(switch_node.switch_token), Space.None); // (
16711612
16721613 const rparen = tree.nextToken(switch_node.expr.lastToken());
16731614 const lbrace = tree.nextToken(rparen);
16741615
16751616 if (switch_node.cases_len == 0) {
1676 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
1677 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1678 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
1679 return renderToken(tree, stream, switch_node.rbrace, indent, start_col, space); // }
1617 try renderExpression(allocator, stream, tree, switch_node.expr, Space.None);
1618 try renderToken(tree, stream, rparen, Space.Space); // )
1619 try renderToken(tree, stream, lbrace, Space.None); // {
1620 return renderToken(tree, stream, switch_node.rbrace, space); // }
16801621 }
16811622
1682 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
1683
1684 const new_indent = indent + indent_delta;
1623 try renderExpression(allocator, stream, tree, switch_node.expr, Space.None);
1624 try renderToken(tree, stream, rparen, Space.Space); // )
16851625
1686 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1687 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {
1626 {
1627 stream.pushIndentNextLine();
1628 defer stream.popIndent();
1629 try renderToken(tree, stream, lbrace, Space.Newline); // {
16881630
1689 const cases = switch_node.cases();
1690 for (cases) |node, i| {
1691 try stream.writeByteNTimes(' ', new_indent);
1692 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
1631 const cases = switch_node.cases();
1632 for (cases) |node, i| {
1633 try renderExpression(allocator, stream, tree, node, Space.Comma);
16931634
1694 if (i + 1 < cases.len) {
1695 try renderExtraNewline(tree, stream, start_col, cases[i + 1]);
1635 if (i + 1 < cases.len) {
1636 try renderExtraNewline(tree, stream, cases[i + 1]);
1637 }
16961638 }
16971639 }
16981640
1699 try stream.writeByteNTimes(' ', indent);
1700 return renderToken(tree, stream, switch_node.rbrace, indent, start_col, space); // }
1641 return renderToken(tree, stream, switch_node.rbrace, space); // }
17011642 },
17021643
17031644 .SwitchCase => {
......@@ -1714,43 +1655,41 @@ fn renderExpression(
17141655 const items = switch_case.items();
17151656 for (items) |node, i| {
17161657 if (i + 1 < items.len) {
1717 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
1658 try renderExpression(allocator, stream, tree, node, Space.None);
17181659
17191660 const comma_token = tree.nextToken(node.lastToken());
1720 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1721 try renderExtraNewline(tree, stream, start_col, items[i + 1]);
1661 try renderToken(tree, stream, comma_token, Space.Space); // ,
1662 try renderExtraNewline(tree, stream, items[i + 1]);
17221663 } else {
1723 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
1664 try renderExpression(allocator, stream, tree, node, Space.Space);
17241665 }
17251666 }
17261667 } else {
17271668 const items = switch_case.items();
17281669 for (items) |node, i| {
17291670 if (i + 1 < items.len) {
1730 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
1671 try renderExpression(allocator, stream, tree, node, Space.None);
17311672
17321673 const comma_token = tree.nextToken(node.lastToken());
1733 try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // ,
1734 try renderExtraNewline(tree, stream, start_col, items[i + 1]);
1735 try stream.writeByteNTimes(' ', indent);
1674 try renderToken(tree, stream, comma_token, Space.Newline); // ,
1675 try renderExtraNewline(tree, stream, items[i + 1]);
17361676 } else {
1737 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Comma);
1738 try stream.writeByteNTimes(' ', indent);
1677 try renderExpression(allocator, stream, tree, node, Space.Comma);
17391678 }
17401679 }
17411680 }
17421681
1743 try renderToken(tree, stream, switch_case.arrow_token, indent, start_col, Space.Space); // =>
1682 try renderToken(tree, stream, switch_case.arrow_token, Space.Space); // =>
17441683
17451684 if (switch_case.payload) |payload| {
1746 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
1685 try renderExpression(allocator, stream, tree, payload, Space.Space);
17471686 }
17481687
1749 return renderExpression(allocator, stream, tree, indent, start_col, switch_case.expr, space);
1688 return renderExpression(allocator, stream, tree, switch_case.expr, space);
17501689 },
17511690 .SwitchElse => {
17521691 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
1753 return renderToken(tree, stream, switch_else.token, indent, start_col, space);
1692 return renderToken(tree, stream, switch_else.token, space);
17541693 },
17551694 .Else => {
17561695 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
......@@ -1759,37 +1698,37 @@ fn renderExpression(
17591698 const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken());
17601699
17611700 const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline;
1762 try renderToken(tree, stream, else_node.else_token, indent, start_col, after_else_space);
1701 try renderToken(tree, stream, else_node.else_token, after_else_space);
17631702
17641703 if (else_node.payload) |payload| {
17651704 const payload_space = if (same_line) Space.Space else Space.Newline;
1766 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);
1705 try renderExpression(allocator, stream, tree, payload, payload_space);
17671706 }
17681707
17691708 if (same_line) {
1770 return renderExpression(allocator, stream, tree, indent, start_col, else_node.body, space);
1709 return renderExpression(allocator, stream, tree, else_node.body, space);
1710 } else {
1711 stream.pushIndent();
1712 defer stream.popIndent();
1713 return renderExpression(allocator, stream, tree, else_node.body, space);
17711714 }
1772
1773 try stream.writeByteNTimes(' ', indent + indent_delta);
1774 start_col.* = indent + indent_delta;
1775 return renderExpression(allocator, stream, tree, indent, start_col, else_node.body, space);
17761715 },
17771716
17781717 .While => {
17791718 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
17801719
17811720 if (while_node.label) |label| {
1782 try renderToken(tree, stream, label, indent, start_col, Space.None); // label
1783 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); // :
1721 try renderToken(tree, stream, label, Space.None); // label
1722 try renderToken(tree, stream, tree.nextToken(label), Space.Space); // :
17841723 }
17851724
17861725 if (while_node.inline_token) |inline_token| {
1787 try renderToken(tree, stream, inline_token, indent, start_col, Space.Space); // inline
1726 try renderToken(tree, stream, inline_token, Space.Space); // inline
17881727 }
17891728
1790 try renderToken(tree, stream, while_node.while_token, indent, start_col, Space.Space); // while
1791 try renderToken(tree, stream, tree.nextToken(while_node.while_token), indent, start_col, Space.None); // (
1792 try renderExpression(allocator, stream, tree, indent, start_col, while_node.condition, Space.None);
1729 try renderToken(tree, stream, while_node.while_token, Space.Space); // while
1730 try renderToken(tree, stream, tree.nextToken(while_node.while_token), Space.None); // (
1731 try renderExpression(allocator, stream, tree, while_node.condition, Space.None);
17931732
17941733 const cond_rparen = tree.nextToken(while_node.condition.lastToken());
17951734
......@@ -1811,12 +1750,12 @@ fn renderExpression(
18111750
18121751 {
18131752 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;
1814 try renderToken(tree, stream, cond_rparen, indent, start_col, rparen_space); // )
1753 try renderToken(tree, stream, cond_rparen, rparen_space); // )
18151754 }
18161755
18171756 if (while_node.payload) |payload| {
1818 const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
1819 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);
1757 const payload_space = Space.Space; //if (while_node.continue_expr != null) Space.Space else block_start_space;
1758 try renderExpression(allocator, stream, tree, payload, payload_space);
18201759 }
18211760
18221761 if (while_node.continue_expr) |continue_expr| {
......@@ -1824,29 +1763,22 @@ fn renderExpression(
18241763 const lparen = tree.prevToken(continue_expr.firstToken());
18251764 const colon = tree.prevToken(lparen);
18261765
1827 try renderToken(tree, stream, colon, indent, start_col, Space.Space); // :
1828 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1766 try renderToken(tree, stream, colon, Space.Space); // :
1767 try renderToken(tree, stream, lparen, Space.None); // (
18291768
1830 try renderExpression(allocator, stream, tree, indent, start_col, continue_expr, Space.None);
1769 try renderExpression(allocator, stream, tree, continue_expr, Space.None);
18311770
1832 try renderToken(tree, stream, rparen, indent, start_col, block_start_space); // )
1771 try renderToken(tree, stream, rparen, block_start_space); // )
18331772 }
18341773
1835 var new_indent = indent;
1836 if (block_start_space == Space.Newline) {
1837 new_indent += indent_delta;
1838 try stream.writeByteNTimes(' ', new_indent);
1839 start_col.* = new_indent;
1774 {
1775 if (!body_is_block) stream.pushIndent();
1776 defer if (!body_is_block) stream.popIndent();
1777 try renderExpression(allocator, stream, tree, while_node.body, after_body_space);
18401778 }
18411779
1842 try renderExpression(allocator, stream, tree, indent, start_col, while_node.body, after_body_space);
1843
18441780 if (while_node.@"else") |@"else"| {
1845 if (after_body_space == Space.Newline) {
1846 try stream.writeByteNTimes(' ', indent);
1847 start_col.* = indent;
1848 }
1849 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);
1781 return renderExpression(allocator, stream, tree, &@"else".base, space);
18501782 }
18511783 },
18521784
......@@ -1854,17 +1786,17 @@ fn renderExpression(
18541786 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
18551787
18561788 if (for_node.label) |label| {
1857 try renderToken(tree, stream, label, indent, start_col, Space.None); // label
1858 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); // :
1789 try renderToken(tree, stream, label, Space.None); // label
1790 try renderToken(tree, stream, tree.nextToken(label), Space.Space); // :
18591791 }
18601792
18611793 if (for_node.inline_token) |inline_token| {
1862 try renderToken(tree, stream, inline_token, indent, start_col, Space.Space); // inline
1794 try renderToken(tree, stream, inline_token, Space.Space); // inline
18631795 }
18641796
1865 try renderToken(tree, stream, for_node.for_token, indent, start_col, Space.Space); // for
1866 try renderToken(tree, stream, tree.nextToken(for_node.for_token), indent, start_col, Space.None); // (
1867 try renderExpression(allocator, stream, tree, indent, start_col, for_node.array_expr, Space.None);
1797 try renderToken(tree, stream, for_node.for_token, Space.Space); // for
1798 try renderToken(tree, stream, tree.nextToken(for_node.for_token), Space.None); // (
1799 try renderExpression(allocator, stream, tree, for_node.array_expr, Space.None);
18681800
18691801 const rparen = tree.nextToken(for_node.array_expr.lastToken());
18701802
......@@ -1872,10 +1804,10 @@ fn renderExpression(
18721804 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
18731805 const body_on_same_line = body_is_block or src_one_line_to_body;
18741806
1875 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1807 try renderToken(tree, stream, rparen, Space.Space); // )
18761808
18771809 const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;
1878 try renderExpression(allocator, stream, tree, indent, start_col, for_node.payload, space_after_payload); // |x|
1810 try renderExpression(allocator, stream, tree, for_node.payload, space_after_payload); // |x|
18791811
18801812 const space_after_body = blk: {
18811813 if (for_node.@"else") |@"else"| {
......@@ -1890,13 +1822,14 @@ fn renderExpression(
18901822 }
18911823 };
18921824
1893 const body_indent = if (body_on_same_line) indent else indent + indent_delta;
1894 if (!body_on_same_line) try stream.writeByteNTimes(' ', body_indent);
1895 try renderExpression(allocator, stream, tree, body_indent, start_col, for_node.body, space_after_body); // { body }
1825 {
1826 if (!body_on_same_line) stream.pushIndent();
1827 defer if (!body_on_same_line) stream.popIndent();
1828 try renderExpression(allocator, stream, tree, for_node.body, space_after_body); // { body }
1829 }
18961830
18971831 if (for_node.@"else") |@"else"| {
1898 if (space_after_body == Space.Newline) try stream.writeByteNTimes(' ', indent);
1899 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space); // else
1832 return renderExpression(allocator, stream, tree, &@"else".base, space); // else
19001833 }
19011834 },
19021835
......@@ -1906,29 +1839,29 @@ fn renderExpression(
19061839 const lparen = tree.nextToken(if_node.if_token);
19071840 const rparen = tree.nextToken(if_node.condition.lastToken());
19081841
1909 try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if
1910 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1842 try renderToken(tree, stream, if_node.if_token, Space.Space); // if
1843 try renderToken(tree, stream, lparen, Space.None); // (
19111844
1912 try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition
1845 try renderExpression(allocator, stream, tree, if_node.condition, Space.None); // condition
19131846
19141847 const body_is_if_block = if_node.body.tag == .If;
19151848 const body_is_block = nodeIsBlock(if_node.body);
19161849
19171850 if (body_is_if_block) {
1918 try renderExtraNewline(tree, stream, start_col, if_node.body);
1851 try renderExtraNewline(tree, stream, if_node.body);
19191852 } else if (body_is_block) {
19201853 const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;
1921 try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )
1854 try renderToken(tree, stream, rparen, after_rparen_space); // )
19221855
19231856 if (if_node.payload) |payload| {
1924 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.BlockStart); // |x|
1857 try renderExpression(allocator, stream, tree, payload, Space.BlockStart); // |x|
19251858 }
19261859
19271860 if (if_node.@"else") |@"else"| {
1928 try renderExpression(allocator, stream, tree, indent, start_col, if_node.body, Space.SpaceOrOutdent);
1929 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);
1861 try renderExpression(allocator, stream, tree, if_node.body, Space.SpaceOrOutdent);
1862 return renderExpression(allocator, stream, tree, &@"else".base, space);
19301863 } else {
1931 return renderExpression(allocator, stream, tree, indent, start_col, if_node.body, space);
1864 return renderExpression(allocator, stream, tree, if_node.body, space);
19321865 }
19331866 }
19341867
......@@ -1936,186 +1869,181 @@ fn renderExpression(
19361869
19371870 if (src_has_newline) {
19381871 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
1939 try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )
1872 try renderToken(tree, stream, rparen, after_rparen_space); // )
19401873
19411874 if (if_node.payload) |payload| {
1942 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Newline);
1875 try renderExpression(allocator, stream, tree, payload, Space.Newline);
19431876 }
19441877
1945 const new_indent = indent + indent_delta;
1946 try stream.writeByteNTimes(' ', new_indent);
1947
19481878 if (if_node.@"else") |@"else"| {
19491879 const else_is_block = nodeIsBlock(@"else".body);
1950 try renderExpression(allocator, stream, tree, new_indent, start_col, if_node.body, Space.Newline);
1951 try stream.writeByteNTimes(' ', indent);
1880
1881 {
1882 stream.pushIndent();
1883 defer stream.popIndent();
1884 try renderExpression(allocator, stream, tree, if_node.body, Space.Newline);
1885 }
19521886
19531887 if (else_is_block) {
1954 try renderToken(tree, stream, @"else".else_token, indent, start_col, Space.Space); // else
1888 try renderToken(tree, stream, @"else".else_token, Space.Space); // else
19551889
19561890 if (@"else".payload) |payload| {
1957 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
1891 try renderExpression(allocator, stream, tree, payload, Space.Space);
19581892 }
19591893
1960 return renderExpression(allocator, stream, tree, indent, start_col, @"else".body, space);
1894 return renderExpression(allocator, stream, tree, @"else".body, space);
19611895 } else {
19621896 const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space;
1963 try renderToken(tree, stream, @"else".else_token, indent, start_col, after_else_space); // else
1897 try renderToken(tree, stream, @"else".else_token, after_else_space); // else
19641898
19651899 if (@"else".payload) |payload| {
1966 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Newline);
1900 try renderExpression(allocator, stream, tree, payload, Space.Newline);
19671901 }
1968 try stream.writeByteNTimes(' ', new_indent);
19691902
1970 return renderExpression(allocator, stream, tree, new_indent, start_col, @"else".body, space);
1903 stream.pushIndent();
1904 defer stream.popIndent();
1905 return renderExpression(allocator, stream, tree, @"else".body, space);
19711906 }
19721907 } else {
1973 return renderExpression(allocator, stream, tree, new_indent, start_col, if_node.body, space);
1908 stream.pushIndent();
1909 defer stream.popIndent();
1910 return renderExpression(allocator, stream, tree, if_node.body, space);
19741911 }
19751912 }
19761913
1977 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1914 // Single line if statement
1915
1916 try renderToken(tree, stream, rparen, Space.Space); // )
19781917
19791918 if (if_node.payload) |payload| {
1980 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
1919 try renderExpression(allocator, stream, tree, payload, Space.Space);
19811920 }
19821921
19831922 if (if_node.@"else") |@"else"| {
1984 try renderExpression(allocator, stream, tree, indent, start_col, if_node.body, Space.Space);
1985 try renderToken(tree, stream, @"else".else_token, indent, start_col, Space.Space);
1923 try renderExpression(allocator, stream, tree, if_node.body, Space.Space);
1924 try renderToken(tree, stream, @"else".else_token, Space.Space);
19861925
19871926 if (@"else".payload) |payload| {
1988 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
1927 try renderExpression(allocator, stream, tree, payload, Space.Space);
19891928 }
19901929
1991 return renderExpression(allocator, stream, tree, indent, start_col, @"else".body, space);
1930 return renderExpression(allocator, stream, tree, @"else".body, space);
19921931 } else {
1993 return renderExpression(allocator, stream, tree, indent, start_col, if_node.body, space);
1932 return renderExpression(allocator, stream, tree, if_node.body, space);
19941933 }
19951934 },
19961935
19971936 .Asm => {
19981937 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
19991938
2000 try renderToken(tree, stream, asm_node.asm_token, indent, start_col, Space.Space); // asm
1939 try renderToken(tree, stream, asm_node.asm_token, Space.Space); // asm
20011940
20021941 if (asm_node.volatile_token) |volatile_token| {
2003 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile
2004 try renderToken(tree, stream, tree.nextToken(volatile_token), indent, start_col, Space.None); // (
1942 try renderToken(tree, stream, volatile_token, Space.Space); // volatile
1943 try renderToken(tree, stream, tree.nextToken(volatile_token), Space.None); // (
20051944 } else {
2006 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (
1945 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), Space.None); // (
20071946 }
20081947
2009 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
2010 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);
2011 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
2012 }
1948 asmblk: {
1949 stream.pushIndent();
1950 defer stream.popIndent();
20131951
2014 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.Newline);
1952 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1953 try renderExpression(allocator, stream, tree, asm_node.template, Space.None);
1954 break :asmblk;
1955 }
20151956
2016 const indent_once = indent + indent_delta;
1957 try renderExpression(allocator, stream, tree, asm_node.template, Space.Newline);
20171958
2018 if (asm_node.template.tag == .MultilineStringLiteral) {
2019 // After rendering a multiline string literal the cursor is
2020 // already offset by indent
2021 try stream.writeByteNTimes(' ', indent_delta);
2022 } else {
2023 try stream.writeByteNTimes(' ', indent_once);
2024 }
1959 const colon1 = tree.nextToken(asm_node.template.lastToken());
20251960
2026 const colon1 = tree.nextToken(asm_node.template.lastToken());
2027 const indent_extra = indent_once + 2;
1961 const colon2 = if (asm_node.outputs.len == 0) blk: {
1962 try renderToken(tree, stream, colon1, Space.Newline); // :
20281963
2029 const colon2 = if (asm_node.outputs.len == 0) blk: {
2030 try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :
2031 try stream.writeByteNTimes(' ', indent_once);
1964 break :blk tree.nextToken(colon1);
1965 } else blk: {
1966 try renderToken(tree, stream, colon1, Space.Space); // :
20321967
2033 break :blk tree.nextToken(colon1);
2034 } else blk: {
2035 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
2036
2037 for (asm_node.outputs) |*asm_output, i| {
2038 if (i + 1 < asm_node.outputs.len) {
2039 const next_asm_output = asm_node.outputs[i + 1];
2040 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None);
2041
2042 const comma = tree.prevToken(next_asm_output.firstToken());
2043 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
2044 try renderExtraNewlineToken(tree, stream, start_col, next_asm_output.firstToken());
2045
2046 try stream.writeByteNTimes(' ', indent_extra);
2047 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
2048 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
2049 try stream.writeByteNTimes(' ', indent);
2050 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
2051 } else {
2052 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
2053 try stream.writeByteNTimes(' ', indent_once);
2054 const comma_or_colon = tree.nextToken(asm_output.lastToken());
2055 break :blk switch (tree.token_ids[comma_or_colon]) {
2056 .Comma => tree.nextToken(comma_or_colon),
2057 else => comma_or_colon,
2058 };
2059 }
2060 }
2061 unreachable;
2062 };
1968 stream.pushIndentN(2);
1969 defer stream.popIndent();
20631970
2064 const colon3 = if (asm_node.inputs.len == 0) blk: {
2065 try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :
2066 try stream.writeByteNTimes(' ', indent_once);
1971 for (asm_node.outputs) |*asm_output, i| {
1972 if (i + 1 < asm_node.outputs.len) {
1973 const next_asm_output = asm_node.outputs[i + 1];
1974 try renderAsmOutput(allocator, stream, tree, asm_output, Space.None);
20671975
2068 break :blk tree.nextToken(colon2);
2069 } else blk: {
2070 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :
2071
2072 for (asm_node.inputs) |*asm_input, i| {
2073 if (i + 1 < asm_node.inputs.len) {
2074 const next_asm_input = &asm_node.inputs[i + 1];
2075 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None);
2076
2077 const comma = tree.prevToken(next_asm_input.firstToken());
2078 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
2079 try renderExtraNewlineToken(tree, stream, start_col, next_asm_input.firstToken());
2080
2081 try stream.writeByteNTimes(' ', indent_extra);
2082 } else if (asm_node.clobbers.len == 0) {
2083 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
2084 try stream.writeByteNTimes(' ', indent);
2085 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
2086 } else {
2087 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
2088 try stream.writeByteNTimes(' ', indent_once);
2089 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2090 break :blk switch (tree.token_ids[comma_or_colon]) {
2091 .Comma => tree.nextToken(comma_or_colon),
2092 else => comma_or_colon,
2093 };
1976 const comma = tree.prevToken(next_asm_output.firstToken());
1977 try renderToken(tree, stream, comma, Space.Newline); // ,
1978 try renderExtraNewlineToken(tree, stream, next_asm_output.firstToken());
1979 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1980 try renderAsmOutput(allocator, stream, tree, asm_output, Space.Newline);
1981 break :asmblk;
1982 } else {
1983 try renderAsmOutput(allocator, stream, tree, asm_output, Space.Newline);
1984 const comma_or_colon = tree.nextToken(asm_output.lastToken());
1985 break :blk switch (tree.token_ids[comma_or_colon]) {
1986 .Comma => tree.nextToken(comma_or_colon),
1987 else => comma_or_colon,
1988 };
1989 }
20941990 }
2095 }
2096 unreachable;
2097 };
1991 unreachable;
1992 };
20981993
2099 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :
1994 const colon3 = if (asm_node.inputs.len == 0) blk: {
1995 try renderToken(tree, stream, colon2, Space.Newline); // :
1996 break :blk tree.nextToken(colon2);
1997 } else blk: {
1998 try renderToken(tree, stream, colon2, Space.Space); // :
1999 stream.pushIndentN(2);
2000 defer stream.popIndent();
2001 for (asm_node.inputs) |*asm_input, i| {
2002 if (i + 1 < asm_node.inputs.len) {
2003 const next_asm_input = &asm_node.inputs[i + 1];
2004 try renderAsmInput(allocator, stream, tree, asm_input, Space.None);
2005
2006 const comma = tree.prevToken(next_asm_input.firstToken());
2007 try renderToken(tree, stream, comma, Space.Newline); // ,
2008 try renderExtraNewlineToken(tree, stream, next_asm_input.firstToken());
2009 } else if (asm_node.clobbers.len == 0) {
2010 try renderAsmInput(allocator, stream, tree, asm_input, Space.Newline);
2011 break :asmblk;
2012 } else {
2013 try renderAsmInput(allocator, stream, tree, asm_input, Space.Newline);
2014 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2015 break :blk switch (tree.token_ids[comma_or_colon]) {
2016 .Comma => tree.nextToken(comma_or_colon),
2017 else => comma_or_colon,
2018 };
2019 }
2020 }
2021 unreachable;
2022 };
21002023
2101 for (asm_node.clobbers) |clobber_node, i| {
2102 if (i + 1 >= asm_node.clobbers.len) {
2103 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);
2104 try stream.writeByteNTimes(' ', indent);
2105 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
2106 } else {
2107 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.None);
2108 const comma = tree.nextToken(clobber_node.lastToken());
2109 try renderToken(tree, stream, comma, indent_once, start_col, Space.Space); // ,
2024 try renderToken(tree, stream, colon3, Space.Space); // :
2025 stream.pushIndentN(2);
2026 defer stream.popIndent();
2027 for (asm_node.clobbers) |clobber_node, i| {
2028 if (i + 1 >= asm_node.clobbers.len) {
2029 try renderExpression(allocator, stream, tree, clobber_node, Space.Newline);
2030 break :asmblk;
2031 } else {
2032 try renderExpression(allocator, stream, tree, clobber_node, Space.None);
2033 const comma = tree.nextToken(clobber_node.lastToken());
2034 try renderToken(tree, stream, comma, Space.Space); // ,
2035 }
21102036 }
21112037 }
2038
2039 return renderToken(tree, stream, asm_node.rparen, space);
21122040 },
21132041
21142042 .EnumLiteral => {
21152043 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
21162044
2117 try renderToken(tree, stream, enum_literal.dot, indent, start_col, Space.None); // .
2118 return renderToken(tree, stream, enum_literal.name, indent, start_col, space); // name
2045 try renderToken(tree, stream, enum_literal.dot, Space.None); // .
2046 return renderToken(tree, stream, enum_literal.name, space); // name
21192047 },
21202048
21212049 .ContainerField,
......@@ -2131,116 +2059,113 @@ fn renderArrayType(
21312059 allocator: *mem.Allocator,
21322060 stream: anytype,
21332061 tree: *ast.Tree,
2134 indent: usize,
2135 start_col: *usize,
21362062 lbracket: ast.TokenIndex,
21372063 rhs: *ast.Node,
21382064 len_expr: *ast.Node,
21392065 opt_sentinel: ?*ast.Node,
21402066 space: Space,
2141) (@TypeOf(stream).Error || Error)!void {
2067) (@TypeOf(stream.*).Error || Error)!void {
21422068 const rbracket = tree.nextToken(if (opt_sentinel) |sentinel|
21432069 sentinel.lastToken()
21442070 else
21452071 len_expr.lastToken());
21462072
2147 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
2148
21492073 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
21502074 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
2151 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
21522075 const new_space = if (ends_with_comment) Space.Newline else Space.None;
2153 try renderExpression(allocator, stream, tree, new_indent, start_col, len_expr, new_space);
2154 if (starts_with_comment) {
2155 try stream.writeByte('\n');
2156 }
2157 if (ends_with_comment or starts_with_comment) {
2158 try stream.writeByteNTimes(' ', indent);
2159 }
2160 if (opt_sentinel) |sentinel| {
2161 const colon_token = tree.prevToken(sentinel.firstToken());
2162 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
2163 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
2076 {
2077 const do_indent = (starts_with_comment or ends_with_comment);
2078 if (do_indent) stream.pushIndent();
2079 defer if (do_indent) stream.popIndent();
2080
2081 try renderToken(tree, stream, lbracket, Space.None); // [
2082 try renderExpression(allocator, stream, tree, len_expr, new_space);
2083
2084 if (starts_with_comment) {
2085 try stream.maybeInsertNewline();
2086 }
2087 if (opt_sentinel) |sentinel| {
2088 const colon_token = tree.prevToken(sentinel.firstToken());
2089 try renderToken(tree, stream, colon_token, Space.None); // :
2090 try renderExpression(allocator, stream, tree, sentinel, Space.None);
2091 }
2092 if (starts_with_comment) {
2093 try stream.maybeInsertNewline();
2094 }
21642095 }
2165 try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]
2096 try renderToken(tree, stream, rbracket, Space.None); // ]
21662097
2167 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);
2098 return renderExpression(allocator, stream, tree, rhs, space);
21682099}
21692100
21702101fn renderAsmOutput(
21712102 allocator: *mem.Allocator,
21722103 stream: anytype,
21732104 tree: *ast.Tree,
2174 indent: usize,
2175 start_col: *usize,
21762105 asm_output: *const ast.Node.Asm.Output,
21772106 space: Space,
2178) (@TypeOf(stream).Error || Error)!void {
2179 try stream.writeAll("[");
2180 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
2181 try stream.writeAll("] ");
2182 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
2183 try stream.writeAll(" (");
2107) (@TypeOf(stream.*).Error || Error)!void {
2108 try stream.writer().writeAll("[");
2109 try renderExpression(allocator, stream, tree, asm_output.symbolic_name, Space.None);
2110 try stream.writer().writeAll("] ");
2111 try renderExpression(allocator, stream, tree, asm_output.constraint, Space.None);
2112 try stream.writer().writeAll(" (");
21842113
21852114 switch (asm_output.kind) {
21862115 ast.Node.Asm.Output.Kind.Variable => |variable_name| {
2187 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
2116 try renderExpression(allocator, stream, tree, &variable_name.base, Space.None);
21882117 },
21892118 ast.Node.Asm.Output.Kind.Return => |return_type| {
2190 try stream.writeAll("-> ");
2191 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
2119 try stream.writer().writeAll("-> ");
2120 try renderExpression(allocator, stream, tree, return_type, Space.None);
21922121 },
21932122 }
21942123
2195 return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )
2124 return renderToken(tree, stream, asm_output.lastToken(), space); // )
21962125}
21972126
21982127fn renderAsmInput(
21992128 allocator: *mem.Allocator,
22002129 stream: anytype,
22012130 tree: *ast.Tree,
2202 indent: usize,
2203 start_col: *usize,
22042131 asm_input: *const ast.Node.Asm.Input,
22052132 space: Space,
2206) (@TypeOf(stream).Error || Error)!void {
2207 try stream.writeAll("[");
2208 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
2209 try stream.writeAll("] ");
2210 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
2211 try stream.writeAll(" (");
2212 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
2213 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
2133) (@TypeOf(stream.*).Error || Error)!void {
2134 try stream.writer().writeAll("[");
2135 try renderExpression(allocator, stream, tree, asm_input.symbolic_name, Space.None);
2136 try stream.writer().writeAll("] ");
2137 try renderExpression(allocator, stream, tree, asm_input.constraint, Space.None);
2138 try stream.writer().writeAll(" (");
2139 try renderExpression(allocator, stream, tree, asm_input.expr, Space.None);
2140 return renderToken(tree, stream, asm_input.lastToken(), space); // )
22142141}
22152142
22162143fn renderVarDecl(
22172144 allocator: *mem.Allocator,
22182145 stream: anytype,
22192146 tree: *ast.Tree,
2220 indent: usize,
2221 start_col: *usize,
22222147 var_decl: *ast.Node.VarDecl,
2223) (@TypeOf(stream).Error || Error)!void {
2148) (@TypeOf(stream.*).Error || Error)!void {
22242149 if (var_decl.getTrailer("visib_token")) |visib_token| {
2225 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
2150 try renderToken(tree, stream, visib_token, Space.Space); // pub
22262151 }
22272152
22282153 if (var_decl.getTrailer("extern_export_token")) |extern_export_token| {
2229 try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern
2154 try renderToken(tree, stream, extern_export_token, Space.Space); // extern
22302155
22312156 if (var_decl.getTrailer("lib_name")) |lib_name| {
2232 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"
2157 try renderExpression(allocator, stream, tree, lib_name, Space.Space); // "lib"
22332158 }
22342159 }
22352160
22362161 if (var_decl.getTrailer("comptime_token")) |comptime_token| {
2237 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime
2162 try renderToken(tree, stream, comptime_token, Space.Space); // comptime
22382163 }
22392164
22402165 if (var_decl.getTrailer("thread_local_token")) |thread_local_token| {
2241 try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal
2166 try renderToken(tree, stream, thread_local_token, Space.Space); // threadlocal
22422167 }
2243 try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var
2168 try renderToken(tree, stream, var_decl.mut_token, Space.Space); // var
22442169
22452170 const name_space = if (var_decl.getTrailer("type_node") == null and
22462171 (var_decl.getTrailer("align_node") != null or
......@@ -2249,70 +2174,69 @@ fn renderVarDecl(
22492174 Space.Space
22502175 else
22512176 Space.None;
2252 try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);
2177 try renderToken(tree, stream, var_decl.name_token, name_space);
22532178
22542179 if (var_decl.getTrailer("type_node")) |type_node| {
2255 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);
2180 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), Space.Space);
22562181 const s = if (var_decl.getTrailer("align_node") != null or
22572182 var_decl.getTrailer("section_node") != null or
22582183 var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2259 try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);
2184 try renderExpression(allocator, stream, tree, type_node, s);
22602185 }
22612186
22622187 if (var_decl.getTrailer("align_node")) |align_node| {
22632188 const lparen = tree.prevToken(align_node.firstToken());
22642189 const align_kw = tree.prevToken(lparen);
22652190 const rparen = tree.nextToken(align_node.lastToken());
2266 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
2267 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
2268 try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);
2191 try renderToken(tree, stream, align_kw, Space.None); // align
2192 try renderToken(tree, stream, lparen, Space.None); // (
2193 try renderExpression(allocator, stream, tree, align_node, Space.None);
22692194 const s = if (var_decl.getTrailer("section_node") != null or var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2270 try renderToken(tree, stream, rparen, indent, start_col, s); // )
2195 try renderToken(tree, stream, rparen, s); // )
22712196 }
22722197
22732198 if (var_decl.getTrailer("section_node")) |section_node| {
22742199 const lparen = tree.prevToken(section_node.firstToken());
22752200 const section_kw = tree.prevToken(lparen);
22762201 const rparen = tree.nextToken(section_node.lastToken());
2277 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection
2278 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
2279 try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None);
2202 try renderToken(tree, stream, section_kw, Space.None); // linksection
2203 try renderToken(tree, stream, lparen, Space.None); // (
2204 try renderExpression(allocator, stream, tree, section_node, Space.None);
22802205 const s = if (var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
2281 try renderToken(tree, stream, rparen, indent, start_col, s); // )
2206 try renderToken(tree, stream, rparen, s); // )
22822207 }
22832208
22842209 if (var_decl.getTrailer("init_node")) |init_node| {
22852210 const s = if (init_node.tag == .MultilineStringLiteral) Space.None else Space.Space;
2286 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // =
2287 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
2211 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, s); // =
2212 stream.pushIndentOneShot();
2213 try renderExpression(allocator, stream, tree, init_node, Space.None);
22882214 }
22892215
2290 try renderToken(tree, stream, var_decl.semicolon_token, indent, start_col, Space.Newline);
2216 try renderToken(tree, stream, var_decl.semicolon_token, Space.Newline);
22912217}
22922218
22932219fn renderParamDecl(
22942220 allocator: *mem.Allocator,
22952221 stream: anytype,
22962222 tree: *ast.Tree,
2297 indent: usize,
2298 start_col: *usize,
22992223 param_decl: ast.Node.FnProto.ParamDecl,
23002224 space: Space,
2301) (@TypeOf(stream).Error || Error)!void {
2302 try renderDocComments(tree, stream, param_decl, param_decl.doc_comments, indent, start_col);
2225) (@TypeOf(stream.*).Error || Error)!void {
2226 try renderDocComments(tree, stream, param_decl, param_decl.doc_comments);
23032227
23042228 if (param_decl.comptime_token) |comptime_token| {
2305 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);
2229 try renderToken(tree, stream, comptime_token, Space.Space);
23062230 }
23072231 if (param_decl.noalias_token) |noalias_token| {
2308 try renderToken(tree, stream, noalias_token, indent, start_col, Space.Space);
2232 try renderToken(tree, stream, noalias_token, Space.Space);
23092233 }
23102234 if (param_decl.name_token) |name_token| {
2311 try renderToken(tree, stream, name_token, indent, start_col, Space.None);
2312 try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :
2235 try renderToken(tree, stream, name_token, Space.None);
2236 try renderToken(tree, stream, tree.nextToken(name_token), Space.Space); // :
23132237 }
23142238 switch (param_decl.param_type) {
2315 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),
2239 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, node, space),
23162240 }
23172241}
23182242
......@@ -2320,24 +2244,22 @@ fn renderStatement(
23202244 allocator: *mem.Allocator,
23212245 stream: anytype,
23222246 tree: *ast.Tree,
2323 indent: usize,
2324 start_col: *usize,
23252247 base: *ast.Node,
2326) (@TypeOf(stream).Error || Error)!void {
2248) (@TypeOf(stream.*).Error || Error)!void {
23272249 switch (base.tag) {
23282250 .VarDecl => {
23292251 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
2330 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
2252 try renderVarDecl(allocator, stream, tree, var_decl);
23312253 },
23322254 else => {
23332255 if (base.requireSemiColon()) {
2334 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);
2256 try renderExpression(allocator, stream, tree, base, Space.None);
23352257
23362258 const semicolon_index = tree.nextToken(base.lastToken());
23372259 assert(tree.token_ids[semicolon_index] == .Semicolon);
2338 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);
2260 try renderToken(tree, stream, semicolon_index, Space.Newline);
23392261 } else {
2340 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);
2262 try renderExpression(allocator, stream, tree, base, Space.Newline);
23412263 }
23422264 },
23432265 }
......@@ -2358,22 +2280,17 @@ fn renderTokenOffset(
23582280 tree: *ast.Tree,
23592281 stream: anytype,
23602282 token_index: ast.TokenIndex,
2361 indent: usize,
2362 start_col: *usize,
23632283 space: Space,
23642284 token_skip_bytes: usize,
2365) (@TypeOf(stream).Error || Error)!void {
2285) (@TypeOf(stream.*).Error || Error)!void {
23662286 if (space == Space.BlockStart) {
2367 if (start_col.* < indent + indent_delta)
2368 return renderToken(tree, stream, token_index, indent, start_col, Space.Space);
2369 try renderToken(tree, stream, token_index, indent, start_col, Space.Newline);
2370 try stream.writeByteNTimes(' ', indent);
2371 start_col.* = indent;
2372 return;
2287 // If placing the lbrace on the current line would cause an uggly gap then put the lbrace on the next line
2288 const new_space = if (stream.isLineOverIndented()) Space.Newline else Space.Space;
2289 return renderToken(tree, stream, token_index, new_space);
23732290 }
23742291
23752292 var token_loc = tree.token_locs[token_index];
2376 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));
2293 try stream.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));
23772294
23782295 if (space == Space.NoComment)
23792296 return;
......@@ -2382,20 +2299,20 @@ fn renderTokenOffset(
23822299 var next_token_loc = tree.token_locs[token_index + 1];
23832300
23842301 if (space == Space.Comma) switch (next_token_id) {
2385 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),
2302 .Comma => return renderToken(tree, stream, token_index + 1, Space.Newline),
23862303 .LineComment => {
2387 try stream.writeAll(", ");
2388 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);
2304 try stream.writer().writeAll(", ");
2305 return renderToken(tree, stream, token_index + 1, Space.Newline);
23892306 },
23902307 else => {
23912308 if (token_index + 2 < tree.token_ids.len and
23922309 tree.token_ids[token_index + 2] == .MultilineStringLiteralLine)
23932310 {
2394 try stream.writeAll(",");
2311 try stream.writer().writeAll(",");
23952312 return;
23962313 } else {
2397 try stream.writeAll(",\n");
2398 start_col.* = 0;
2314 try stream.writer().writeAll(",");
2315 try stream.insertNewline();
23992316 return;
24002317 }
24012318 },
......@@ -2419,15 +2336,14 @@ fn renderTokenOffset(
24192336 if (next_token_id == .MultilineStringLiteralLine) {
24202337 return;
24212338 } else {
2422 try stream.writeAll("\n");
2423 start_col.* = 0;
2339 try stream.insertNewline();
24242340 return;
24252341 }
24262342 },
24272343 Space.Space, Space.SpaceOrOutdent => {
24282344 if (next_token_id == .MultilineStringLiteralLine)
24292345 return;
2430 try stream.writeByte(' ');
2346 try stream.writer().writeByte(' ');
24312347 return;
24322348 },
24332349 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
......@@ -2444,8 +2360,7 @@ fn renderTokenOffset(
24442360 next_token_id = tree.token_ids[token_index + offset];
24452361 next_token_loc = tree.token_locs[token_index + offset];
24462362 if (next_token_id != .LineComment) {
2447 try stream.writeByte('\n');
2448 start_col.* = 0;
2363 try stream.insertNewline();
24492364 return;
24502365 }
24512366 },
......@@ -2458,7 +2373,7 @@ fn renderTokenOffset(
24582373
24592374 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
24602375 if (loc.line == 0) {
2461 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});
2376 try stream.writer().print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});
24622377 offset = 2;
24632378 token_loc = next_token_loc;
24642379 next_token_loc = tree.token_locs[token_index + offset];
......@@ -2466,26 +2381,16 @@ fn renderTokenOffset(
24662381 if (next_token_id != .LineComment) {
24672382 switch (space) {
24682383 Space.None, Space.Space => {
2469 try stream.writeByte('\n');
2470 const after_comment_token = tree.token_ids[token_index + offset];
2471 const next_line_indent = switch (after_comment_token) {
2472 .RParen, .RBrace, .RBracket => indent,
2473 else => indent + indent_delta,
2474 };
2475 try stream.writeByteNTimes(' ', next_line_indent);
2476 start_col.* = next_line_indent;
2384 try stream.insertNewline();
24772385 },
24782386 Space.SpaceOrOutdent => {
2479 try stream.writeByte('\n');
2480 try stream.writeByteNTimes(' ', indent);
2481 start_col.* = indent;
2387 try stream.insertNewline();
24822388 },
24832389 Space.Newline => {
24842390 if (next_token_id == .MultilineStringLiteralLine) {
24852391 return;
24862392 } else {
2487 try stream.writeAll("\n");
2488 start_col.* = 0;
2393 try stream.insertNewline();
24892394 return;
24902395 }
24912396 },
......@@ -2501,10 +2406,9 @@ fn renderTokenOffset(
25012406 // translate-c doesn't generate correct newlines
25022407 // in generated code (loc.line == 0) so treat that case
25032408 // as though there was meant to be a newline between the tokens
2504 const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);
2505 try stream.writeByteNTimes('\n', newline_count);
2506 try stream.writeByteNTimes(' ', indent);
2507 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
2409 var newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);
2410 while (newline_count > 0) : (newline_count -= 1) try stream.insertNewline();
2411 try stream.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
25082412
25092413 offset += 1;
25102414 token_loc = next_token_loc;
......@@ -2516,32 +2420,15 @@ fn renderTokenOffset(
25162420 if (next_token_id == .MultilineStringLiteralLine) {
25172421 return;
25182422 } else {
2519 try stream.writeAll("\n");
2520 start_col.* = 0;
2423 try stream.insertNewline();
25212424 return;
25222425 }
25232426 },
25242427 Space.None, Space.Space => {
2525 try stream.writeByte('\n');
2526
2527 const after_comment_token = tree.token_ids[token_index + offset];
2528 const next_line_indent = switch (after_comment_token) {
2529 .RParen, .RBrace, .RBracket => blk: {
2530 if (indent > indent_delta) {
2531 break :blk indent - indent_delta;
2532 } else {
2533 break :blk 0;
2534 }
2535 },
2536 else => indent,
2537 };
2538 try stream.writeByteNTimes(' ', next_line_indent);
2539 start_col.* = next_line_indent;
2428 try stream.insertNewline();
25402429 },
25412430 Space.SpaceOrOutdent => {
2542 try stream.writeByte('\n');
2543 try stream.writeByteNTimes(' ', indent);
2544 start_col.* = indent;
2431 try stream.insertNewline();
25452432 },
25462433 Space.NoNewline => {},
25472434 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
......@@ -2556,11 +2443,9 @@ fn renderToken(
25562443 tree: *ast.Tree,
25572444 stream: anytype,
25582445 token_index: ast.TokenIndex,
2559 indent: usize,
2560 start_col: *usize,
25612446 space: Space,
2562) (@TypeOf(stream).Error || Error)!void {
2563 return renderTokenOffset(tree, stream, token_index, indent, start_col, space, 0);
2447) (@TypeOf(stream.*).Error || Error)!void {
2448 return renderTokenOffset(tree, stream, token_index, space, 0);
25642449}
25652450
25662451fn renderDocComments(
......@@ -2568,11 +2453,9 @@ fn renderDocComments(
25682453 stream: anytype,
25692454 node: anytype,
25702455 doc_comments: ?*ast.Node.DocComment,
2571 indent: usize,
2572 start_col: *usize,
2573) (@TypeOf(stream).Error || Error)!void {
2456) (@TypeOf(stream.*).Error || Error)!void {
25742457 const comment = doc_comments orelse return;
2575 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);
2458 return renderDocCommentsToken(tree, stream, comment, node.firstToken());
25762459}
25772460
25782461fn renderDocCommentsToken(
......@@ -2580,20 +2463,16 @@ fn renderDocCommentsToken(
25802463 stream: anytype,
25812464 comment: *ast.Node.DocComment,
25822465 first_token: ast.TokenIndex,
2583 indent: usize,
2584 start_col: *usize,
2585) (@TypeOf(stream).Error || Error)!void {
2466) (@TypeOf(stream.*).Error || Error)!void {
25862467 var tok_i = comment.first_line;
25872468 while (true) : (tok_i += 1) {
25882469 switch (tree.token_ids[tok_i]) {
25892470 .DocComment, .ContainerDocComment => {
25902471 if (comment.first_line < first_token) {
2591 try renderToken(tree, stream, tok_i, indent, start_col, Space.Newline);
2592 try stream.writeByteNTimes(' ', indent);
2472 try renderToken(tree, stream, tok_i, Space.Newline);
25932473 } else {
2594 try renderToken(tree, stream, tok_i, indent, start_col, Space.NoComment);
2595 try stream.writeAll("\n");
2596 try stream.writeByteNTimes(' ', indent);
2474 try renderToken(tree, stream, tok_i, Space.NoComment);
2475 try stream.insertNewline();
25972476 }
25982477 },
25992478 .LineComment => continue,
......@@ -2665,41 +2544,10 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
26652544 };
26662545}
26672546
2668/// A `std.io.OutStream` that returns whether the given character has been written to it.
2669/// The contents are not written to anything.
2670const FindByteOutStream = struct {
2671 byte_found: bool,
2672 byte: u8,
2673
2674 pub const Error = error{};
2675 pub const OutStream = std.io.OutStream(*FindByteOutStream, Error, write);
2676
2677 pub fn init(byte: u8) FindByteOutStream {
2678 return FindByteOutStream{
2679 .byte = byte,
2680 .byte_found = false,
2681 };
2682 }
2683
2684 pub fn write(self: *FindByteOutStream, bytes: []const u8) Error!usize {
2685 if (self.byte_found) return bytes.len;
2686 self.byte_found = blk: {
2687 for (bytes) |b|
2688 if (b == self.byte) break :blk true;
2689 break :blk false;
2690 };
2691 return bytes.len;
2692 }
2693
2694 pub fn outStream(self: *FindByteOutStream) OutStream {
2695 return .{ .context = self };
2696 }
2697};
2698
2699fn copyFixingWhitespace(stream: anytype, slice: []const u8) @TypeOf(stream).Error!void {
2547fn copyFixingWhitespace(stream: anytype, slice: []const u8) @TypeOf(stream.*).Error!void {
27002548 for (slice) |byte| switch (byte) {
2701 '\t' => try stream.writeAll(" "),
2549 '\t' => try stream.writer().writeAll(" "),
27022550 '\r' => {},
2703 else => try stream.writeByte(byte),
2551 else => try stream.writer().writeByte(byte),
27042552 };
27052553}
src-self-hosted/main.zig+5-4
......@@ -682,13 +682,13 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
682682 process.exit(1);
683683 }
684684 if (check_flag) {
685 const anything_changed = try std.zig.render(gpa, io.null_out_stream, tree);
685 const anything_changed = try std.zig.render(gpa, &io.null_out_stream, tree);
686686 const code = if (anything_changed) @as(u8, 1) else @as(u8, 0);
687687 process.exit(code);
688688 }
689689
690690 const stdout = io.getStdOut().outStream();
691 _ = try std.zig.render(gpa, stdout, tree);
691 _ = try std.zig.render(gpa, &stdout, tree);
692692 return;
693693 }
694694
......@@ -830,7 +830,7 @@ fn fmtPathFile(
830830 }
831831
832832 if (check_mode) {
833 const anything_changed = try std.zig.render(fmt.gpa, io.null_out_stream, tree);
833 const anything_changed = try std.zig.render(fmt.gpa, &io.null_out_stream, tree);
834834 if (anything_changed) {
835835 std.debug.print("{}\n", .{file_path});
836836 fmt.any_error = true;
......@@ -839,7 +839,8 @@ fn fmtPathFile(
839839 // As a heuristic, we make enough capacity for the same as the input source.
840840 try fmt.out_buffer.ensureCapacity(source_code.len);
841841 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);
843844 if (!anything_changed)
844845 return; // Good thing we didn't waste any file system access on this.
845846
src-self-hosted/stage2.zig+1-1
......@@ -151,7 +151,7 @@ export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, error
151151
152152export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
153153 const c_out_stream = std.io.cOutStream(output_file);
154 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
154 _ = std.zig.render(std.heap.c_allocator, &c_out_stream, tree) catch |e| switch (e) {
155155 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
156156 error.NotOpenForWriting => unreachable,
157157 error.SystemResources => return .SystemResources,