diff options
| -rw-r--r-- | lib/std/zig/parser_test.zig | 1083 | ||||
| -rw-r--r-- | lib/std/zig/render.zig | 166 |
2 files changed, 592 insertions, 657 deletions
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index c6ee4f6bd9..aad9ad3ed6 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -663,7 +663,9 @@ test "zig fmt: anon list literal 3 element comma" { \\test { \\ const x = .{ \\ a, + \\ // foo \\ b, + \\ \\ c, \\ }; \\} @@ -874,20 +876,20 @@ test "zig fmt: enum literal" { ); } -//test "zig fmt: enum literal inside array literal" { -// try testCanonical( -// \\test "enums in arrays" { -// \\ var colors = []Color{.Green}; -// \\ colors = []Colors{ .Green, .Cyan }; -// \\ colors = []Colors{ -// \\ .Grey, -// \\ .Green, -// \\ .Cyan, -// \\ }; -// \\} -// \\ -// ); -//} +test "zig fmt: enum literal inside array literal" { + try testCanonical( + \\test "enums in arrays" { + \\ var colors = []Color{.Green}; + \\ colors = []Colors{ .Green, .Cyan }; + \\ colors = []Colors{ + \\ .Grey, + \\ .Green, + \\ .Cyan, + \\ }; + \\} + \\ + ); +} test "zig fmt: character literal larger than u8" { try testCanonical( @@ -954,56 +956,56 @@ test "zig fmt: linksection" { // \\ // ); //} -// -//test "zig fmt: correctly space struct fields with doc comments" { -// try testTransform( -// \\pub const S = struct { -// \\ /// A -// \\ a: u8, -// \\ /// B -// \\ /// B (cont) -// \\ b: u8, -// \\ -// \\ -// \\ /// C -// \\ c: u8, -// \\}; -// \\ -// , -// \\pub const S = struct { -// \\ /// A -// \\ a: u8, -// \\ /// B -// \\ /// B (cont) -// \\ b: u8, -// \\ -// \\ /// C -// \\ c: u8, -// \\}; -// \\ -// ); -//} -// -//test "zig fmt: doc comments on param decl" { -// try testCanonical( -// \\pub const Allocator = struct { -// \\ shrinkFn: fn ( -// \\ self: *Allocator, -// \\ /// Guaranteed to be the same as what was returned from most recent call to -// \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. -// \\ old_mem: []u8, -// \\ /// Guaranteed to be the same as what was returned from most recent call to -// \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. -// \\ old_alignment: u29, -// \\ /// Guaranteed to be less than or equal to `old_mem.len`. -// \\ new_byte_count: usize, -// \\ /// Guaranteed to be less than or equal to `old_alignment`. -// \\ new_alignment: u29, -// \\ ) []u8, -// \\}; -// \\ -// ); -//} + +test "zig fmt: correctly space struct fields with doc comments" { + try testTransform( + \\pub const S = struct { + \\ /// A + \\ a: u8, + \\ /// B + \\ /// B (cont) + \\ b: u8, + \\ + \\ + \\ /// C + \\ c: u8, + \\}; + \\ + , + \\pub const S = struct { + \\ /// A + \\ a: u8, + \\ /// B + \\ /// B (cont) + \\ b: u8, + \\ + \\ /// C + \\ c: u8, + \\}; + \\ + ); +} + +test "zig fmt: doc comments on param decl" { + try testCanonical( + \\pub const Allocator = struct { + \\ shrinkFn: fn ( + \\ self: *Allocator, + \\ /// Guaranteed to be the same as what was returned from most recent call to + \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. + \\ old_mem: []u8, + \\ /// Guaranteed to be the same as what was returned from most recent call to + \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. + \\ old_alignment: u29, + \\ /// Guaranteed to be less than or equal to `old_mem.len`. + \\ new_byte_count: usize, + \\ /// Guaranteed to be less than or equal to `old_alignment`. + \\ new_alignment: u29, + \\ ) []u8, + \\}; + \\ + ); +} test "zig fmt: aligned struct field" { try testCanonical( @@ -1142,13 +1144,13 @@ test "zig fmt: aligned struct field" { // \\ // ); //} -// -//test "zig fmt: pointer of unknown length" { -// try testCanonical( -// \\fn foo(ptr: [*]u8) void {} -// \\ -// ); -//} + +test "zig fmt: pointer of unknown length" { + try testCanonical( + \\fn foo(ptr: [*]u8) void {} + \\ + ); +} test "zig fmt: spaces around slice operator" { try testCanonical( @@ -1370,25 +1372,25 @@ test "zig fmt: async call in if condition" { // \\ // ); //} -// -//test "zig fmt: if-else with comment before else" { -// try testCanonical( -// \\comptime { -// \\ // cexp(finite|nan +- i inf|nan) = nan + i nan -// \\ if ((hx & 0x7fffffff) != 0x7f800000) { -// \\ return Complex(f32).new(y - y, y - y); -// \\ } // cexp(-inf +- i inf|nan) = 0 + i0 -// \\ else if (hx & 0x80000000 != 0) { -// \\ return Complex(f32).new(0, 0); -// \\ } // cexp(+inf +- i inf|nan) = inf + i nan -// \\ else { -// \\ return Complex(f32).new(x, y - y); -// \\ } -// \\} -// \\ -// ); -//} -// + +test "zig fmt: if-else with comment before else" { + try testCanonical( + \\comptime { + \\ // cexp(finite|nan +- i inf|nan) = nan + i nan + \\ if ((hx & 0x7fffffff) != 0x7f800000) { + \\ return Complex(f32).new(y - y, y - y); + \\ } // cexp(-inf +- i inf|nan) = 0 + i0 + \\ else if (hx & 0x80000000 != 0) { + \\ return Complex(f32).new(0, 0); + \\ } // cexp(+inf +- i inf|nan) = inf + i nan + \\ else { + \\ return Complex(f32).new(x, y - y); + \\ } + \\} + \\ + ); +} + //test "zig fmt: if nested" { // try testCanonical( // \\pub fn foo() void { @@ -1467,17 +1469,17 @@ test "zig fmt: enum decl with no trailing comma" { ); } -//test "zig fmt: switch comment before prong" { -// try testCanonical( -// \\comptime { -// \\ switch (a) { -// \\ // hi -// \\ 0 => {}, -// \\ } -// \\} -// \\ -// ); -//} +test "zig fmt: switch comment before prong" { + try testCanonical( + \\comptime { + \\ switch (a) { + \\ // hi + \\ 0 => {}, + \\ } + \\} + \\ + ); +} test "zig fmt: struct literal no trailing comma" { try testTransform( @@ -1709,17 +1711,17 @@ test "zig fmt: multi line arguments without last comma" { ); } -//test "zig fmt: empty block with only comment" { -// try testCanonical( -// \\comptime { -// \\ { -// \\ // comment -// \\ } -// \\} -// \\ -// ); -//} -// +test "zig fmt: empty block with only comment" { + try testCanonical( + \\comptime { + \\ { + \\ // comment + \\ } + \\} + \\ + ); +} + //test "zig fmt: no trailing comma on struct decl" { // try testCanonical( // \\const RoundParam = struct { @@ -1781,15 +1783,15 @@ test "zig fmt: extra newlines at the end" { // \\ // ); //} -// -//test "zig fmt: nested struct literal with one item" { -// try testCanonical( -// \\const a = foo{ -// \\ .item = bar{ .a = b }, -// \\}; -// \\ -// ); -//} + +test "zig fmt: nested struct literal with one item" { + try testCanonical( + \\const a = foo{ + \\ .item = bar{ .a = b }, + \\}; + \\ + ); +} test "zig fmt: switch cases trailing comma" { try testTransform( @@ -1848,26 +1850,26 @@ test "zig fmt: slice align" { // \\ // ); //} -// -//test "zig fmt: first thing in file is line comment" { -// try testCanonical( -// \\// Introspection and determination of system libraries needed by zig. -// \\ -// \\// Introspection and determination of system libraries needed by zig. -// \\ -// \\const std = @import("std"); -// \\ -// ); -//} -// -//test "zig fmt: line comment after doc comment" { -// try testCanonical( -// \\/// doc comment -// \\// line comment -// \\fn foo() void {} -// \\ -// ); -//} + +test "zig fmt: first thing in file is line comment" { + try testCanonical( + \\// Introspection and determination of system libraries needed by zig. + \\ + \\// Introspection and determination of system libraries needed by zig. + \\ + \\const std = @import("std"); + \\ + ); +} + +test "zig fmt: line comment after doc comment" { + try testCanonical( + \\/// doc comment + \\// line comment + \\fn foo() void {} + \\ + ); +} test "zig fmt: bit field alignment" { try testCanonical( @@ -1928,27 +1930,27 @@ test "zig fmt: nested blocks" { ); } -//test "zig fmt: block with same line comment after end brace" { -// try testCanonical( -// \\comptime { -// \\ { -// \\ b(); -// \\ } // comment -// \\} -// \\ -// ); -//} -// -//test "zig fmt: statements with comment between" { -// try testCanonical( -// \\comptime { -// \\ a = b; -// \\ // comment -// \\ a = b; -// \\} -// \\ -// ); -//} +test "zig fmt: block with same line comment after end brace" { + try testCanonical( + \\comptime { + \\ { + \\ b(); + \\ } // comment + \\} + \\ + ); +} + +test "zig fmt: statements with comment between" { + try testCanonical( + \\comptime { + \\ a = b; + \\ // comment + \\ a = b; + \\} + \\ + ); +} test "zig fmt: statements with empty line between" { try testCanonical( @@ -1969,60 +1971,60 @@ test "zig fmt: ptr deref operator and unwrap optional operator" { ); } -//test "zig fmt: comment after if before another if" { -// try testCanonical( -// \\test "aoeu" { -// \\ // comment -// \\ if (x) { -// \\ bar(); -// \\ } -// \\} -// \\ -// \\test "aoeu" { -// \\ if (x) { -// \\ foo(); -// \\ } -// \\ // comment -// \\ if (x) { -// \\ bar(); -// \\ } -// \\} -// \\ -// ); -//} -// -//test "zig fmt: line comment between if block and else keyword" { -// try testCanonical( -// \\test "aoeu" { -// \\ // cexp(finite|nan +- i inf|nan) = nan + i nan -// \\ if ((hx & 0x7fffffff) != 0x7f800000) { -// \\ return Complex(f32).new(y - y, y - y); -// \\ } -// \\ // cexp(-inf +- i inf|nan) = 0 + i0 -// \\ else if (hx & 0x80000000 != 0) { -// \\ return Complex(f32).new(0, 0); -// \\ } -// \\ // cexp(+inf +- i inf|nan) = inf + i nan -// \\ // another comment -// \\ else { -// \\ return Complex(f32).new(x, y - y); -// \\ } -// \\} -// \\ -// ); -//} -// -//test "zig fmt: same line comments in expression" { -// try testCanonical( -// \\test "aoeu" { -// \\ const x = ( // a -// \\ 0 // b -// \\ ); // c -// \\} -// \\ -// ); -//} -// +test "zig fmt: comment after if before another if" { + try testCanonical( + \\test "aoeu" { + \\ // comment + \\ if (x) { + \\ bar(); + \\ } + \\} + \\ + \\test "aoeu" { + \\ if (x) { + \\ foo(); + \\ } + \\ // comment + \\ if (x) { + \\ bar(); + \\ } + \\} + \\ + ); +} + +test "zig fmt: line comment between if block and else keyword" { + try testCanonical( + \\test "aoeu" { + \\ // cexp(finite|nan +- i inf|nan) = nan + i nan + \\ if ((hx & 0x7fffffff) != 0x7f800000) { + \\ return Complex(f32).new(y - y, y - y); + \\ } + \\ // cexp(-inf +- i inf|nan) = 0 + i0 + \\ else if (hx & 0x80000000 != 0) { + \\ return Complex(f32).new(0, 0); + \\ } + \\ // cexp(+inf +- i inf|nan) = inf + i nan + \\ // another comment + \\ else { + \\ return Complex(f32).new(x, y - y); + \\ } + \\} + \\ + ); +} + +test "zig fmt: same line comments in expression" { + try testCanonical( + \\test "aoeu" { + \\ const x = ( // a + \\ 0 // b + \\ ); // c + \\} + \\ + ); +} + //test "zig fmt: add comma on last switch prong" { // try testTransform( // \\test "aoeu" { @@ -2051,70 +2053,70 @@ test "zig fmt: ptr deref operator and unwrap optional operator" { // \\ // ); //} -// -//test "zig fmt: same-line comment after a statement" { -// try testCanonical( -// \\test "" { -// \\ a = b; -// \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption -// \\ a = b; -// \\} -// \\ -// ); -//} -// -//test "zig fmt: same-line comment after var decl in struct" { -// try testCanonical( -// \\pub const vfs_cap_data = extern struct { -// \\ const Data = struct {}; // when on disk. -// \\}; -// \\ -// ); -//} -// -//test "zig fmt: same-line comment after field decl" { -// try testCanonical( -// \\pub const dirent = extern struct { -// \\ d_name: u8, -// \\ d_name: u8, // comment 1 -// \\ d_name: u8, -// \\ d_name: u8, // comment 2 -// \\ d_name: u8, -// \\}; -// \\ -// ); -//} -// -//test "zig fmt: same-line comment after switch prong" { -// try testCanonical( -// \\test "" { -// \\ switch (err) { -// \\ error.PathAlreadyExists => {}, // comment 2 -// \\ else => return err, // comment 1 -// \\ } -// \\} -// \\ -// ); -//} -// -//test "zig fmt: same-line comment after non-block if expression" { -// try testCanonical( -// \\comptime { -// \\ if (sr > n_uword_bits - 1) // d > r -// \\ return 0; -// \\} -// \\ -// ); -//} -// -//test "zig fmt: same-line comment on comptime expression" { -// try testCanonical( -// \\test "" { -// \\ comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt -// \\} -// \\ -// ); -//} + +test "zig fmt: same-line comment after a statement" { + try testCanonical( + \\test "" { + \\ a = b; + \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption + \\ a = b; + \\} + \\ + ); +} + +test "zig fmt: same-line comment after var decl in struct" { + try testCanonical( + \\pub const vfs_cap_data = extern struct { + \\ const Data = struct {}; // when on disk. + \\}; + \\ + ); +} + +test "zig fmt: same-line comment after field decl" { + try testCanonical( + \\pub const dirent = extern struct { + \\ d_name: u8, + \\ d_name: u8, // comment 1 + \\ d_name: u8, + \\ d_name: u8, // comment 2 + \\ d_name: u8, + \\}; + \\ + ); +} + +test "zig fmt: same-line comment after switch prong" { + try testCanonical( + \\test "" { + \\ switch (err) { + \\ error.PathAlreadyExists => {}, // comment 2 + \\ else => return err, // comment 1 + \\ } + \\} + \\ + ); +} + +test "zig fmt: same-line comment after non-block if expression" { + try testCanonical( + \\comptime { + \\ if (sr > n_uword_bits - 1) // d > r + \\ return 0; + \\} + \\ + ); +} + +test "zig fmt: same-line comment on comptime expression" { + try testCanonical( + \\test "" { + \\ comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt + \\} + \\ + ); +} test "zig fmt: switch with empty body" { try testCanonical( @@ -2125,53 +2127,52 @@ test "zig fmt: switch with empty body" { ); } -//test "zig fmt: line comments in struct initializer" { -// try testCanonical( -// \\fn foo() void { -// \\ return Self{ -// \\ .a = b, -// \\ -// \\ // Initialize these two fields to buffer_size so that -// \\ // in `readFn` we treat the state as being able to read -// \\ .start_index = buffer_size, -// \\ .end_index = buffer_size, -// \\ -// \\ // middle -// \\ -// \\ .a = b, -// \\ -// \\ // end -// \\ }; -// \\} -// \\ -// ); -//} -// -//test "zig fmt: first line comment in struct initializer" { -// try testCanonical( -// \\pub fn acquire(self: *Self) HeldLock { -// \\ return HeldLock{ -// \\ // guaranteed allocation elision -// \\ .held = self.lock.acquire(), -// \\ .value = &self.private_data, -// \\ }; -// \\} -// \\ -// ); -//} -// -//test "zig fmt: doc comments before struct field" { -// try testCanonical( -// \\pub const Allocator = struct { -// \\ /// Allocate byte_count bytes and return them in a slice, with the -// \\ /// slice's pointer aligned at least to alignment bytes. -// \\ allocFn: fn () void, -// \\}; -// \\ -// ); -//} +test "zig fmt: line comments in struct initializer" { + try testCanonical( + \\fn foo() void { + \\ return Self{ + \\ .a = b, + \\ + \\ // Initialize these two fields to buffer_size so that + \\ // in `readFn` we treat the state as being able to read + \\ .start_index = buffer_size, + \\ .end_index = buffer_size, + \\ + \\ // middle + \\ + \\ .a = b, + \\ + \\ // end + \\ }; + \\} + \\ + ); +} + +test "zig fmt: first line comment in struct initializer" { + try testCanonical( + \\pub fn acquire(self: *Self) HeldLock { + \\ return HeldLock{ + \\ // guaranteed allocation elision + \\ .held = self.lock.acquire(), + \\ .value = &self.private_data, + \\ }; + \\} + \\ + ); +} + +test "zig fmt: doc comments before struct field" { + try testCanonical( + \\pub const Allocator = struct { + \\ /// Allocate byte_count bytes and return them in a slice, with the + \\ /// slice's pointer aligned at least to alignment bytes. + \\ allocFn: fn () void, + \\}; + \\ + ); +} -// TODO: replace this with the next test case when possible test "zig fmt: error set declaration" { try testCanonical( \\const E = error{ @@ -2180,58 +2181,30 @@ test "zig fmt: error set declaration" { \\ \\ C, \\}; + \\ \\const Error = error{ \\ /// no more memory \\ OutOfMemory, \\}; + \\ \\const Error = error{ \\ /// no more memory \\ OutOfMemory, \\ \\ /// another \\ Another, - \\ /// and one more - \\ Another, + \\ + \\ // end \\}; + \\ \\const Error = error{OutOfMemory}; \\const Error = error{}; + \\ \\const Error = error{ OutOfMemory, OutOfTime }; \\ ); } -//test "zig fmt: error set declaration" { -// try testCanonical( -// \\const E = error{ -// \\ A, -// \\ B, -// \\ -// \\ C, -// \\}; -// \\ -// \\const Error = error{ -// \\ /// no more memory -// \\ OutOfMemory, -// \\}; -// \\ -// \\const Error = error{ -// \\ /// no more memory -// \\ OutOfMemory, -// \\ -// \\ /// another -// \\ Another, -// \\ -// \\ // end -// \\}; -// \\ -// \\const Error = error{OutOfMemory}; -// \\const Error = error{}; -// \\ -// \\const Error = error{ OutOfMemory, OutOfTime }; -// \\ -// ); -//} - test "zig fmt: union(enum(u32)) with assigned enum values" { try testCanonical( \\const MultipleChoice = union(enum(u32)) { @@ -2255,110 +2228,110 @@ test "zig fmt: resume from suspend block" { ); } -//test "zig fmt: comments before error set decl" { -// try testCanonical( -// \\const UnexpectedError = error{ -// \\ /// The Operating System returned an undocumented error code. -// \\ Unexpected, -// \\ // another -// \\ Another, -// \\ -// \\ // in between -// \\ -// \\ // at end -// \\}; -// \\ -// ); -//} -// -//test "zig fmt: comments before switch prong" { -// try testCanonical( -// \\test "" { -// \\ switch (err) { -// \\ error.PathAlreadyExists => continue, -// \\ -// \\ // comment 1 -// \\ -// \\ // comment 2 -// \\ else => return err, -// \\ // at end -// \\ } -// \\} -// \\ -// ); -//} -// -//test "zig fmt: comments before var decl in struct" { -// try testCanonical( -// \\pub const vfs_cap_data = extern struct { -// \\ // All of these are mandated as little endian -// \\ // when on disk. -// \\ const Data = struct { -// \\ permitted: u32, -// \\ inheritable: u32, -// \\ }; -// \\ -// \\ // in between -// \\ -// \\ /// All of these are mandated as little endian -// \\ /// when on disk. -// \\ const Data = struct { -// \\ permitted: u32, -// \\ inheritable: u32, -// \\ }; -// \\ -// \\ // at end -// \\}; -// \\ -// ); -//} -// -//test "zig fmt: array literal with 1 item on 1 line" { -// try testCanonical( -// \\var s = []const u64{0} ** 25; -// \\ -// ); -//} -// -//test "zig fmt: comments before global variables" { -// try testCanonical( -// \\/// Foo copies keys and values before they go into the map, and -// \\/// frees them when they get removed. -// \\pub const Foo = struct {}; -// \\ -// ); -//} -// -//test "zig fmt: comments in statements" { -// try testCanonical( -// \\test "std" { -// \\ // statement comment -// \\ _ = @import("foo/bar.zig"); -// \\ -// \\ // middle -// \\ // middle2 -// \\ -// \\ // end -// \\} -// \\ -// ); -//} -// -//test "zig fmt: comments before test decl" { -// try testCanonical( -// \\/// top level doc comment -// \\test "hi" {} -// \\ -// \\// top level normal comment -// \\test "hi" {} -// \\ -// \\// middle -// \\ -// \\// end -// \\ -// ); -//} -// +test "zig fmt: comments before error set decl" { + try testCanonical( + \\const UnexpectedError = error{ + \\ /// The Operating System returned an undocumented error code. + \\ Unexpected, + \\ // another + \\ Another, + \\ + \\ // in between + \\ + \\ // at end + \\}; + \\ + ); +} + +test "zig fmt: comments before switch prong" { + try testCanonical( + \\test "" { + \\ switch (err) { + \\ error.PathAlreadyExists => continue, + \\ + \\ // comment 1 + \\ + \\ // comment 2 + \\ else => return err, + \\ // at end + \\ } + \\} + \\ + ); +} + +test "zig fmt: comments before var decl in struct" { + try testCanonical( + \\pub const vfs_cap_data = extern struct { + \\ // All of these are mandated as little endian + \\ // when on disk. + \\ const Data = struct { + \\ permitted: u32, + \\ inheritable: u32, + \\ }; + \\ + \\ // in between + \\ + \\ /// All of these are mandated as little endian + \\ /// when on disk. + \\ const Data = struct { + \\ permitted: u32, + \\ inheritable: u32, + \\ }; + \\ + \\ // at end + \\}; + \\ + ); +} + +test "zig fmt: array literal with 1 item on 1 line" { + try testCanonical( + \\var s = []const u64{0} ** 25; + \\ + ); +} + +test "zig fmt: comments before global variables" { + try testCanonical( + \\/// Foo copies keys and values before they go into the map, and + \\/// frees them when they get removed. + \\pub const Foo = struct {}; + \\ + ); +} + +test "zig fmt: comments in statements" { + try testCanonical( + \\test "std" { + \\ // statement comment + \\ _ = @import("foo/bar.zig"); + \\ + \\ // middle + \\ // middle2 + \\ + \\ // end + \\} + \\ + ); +} + +test "zig fmt: comments before test decl" { + try testCanonical( + \\/// top level doc comment + \\test "hi" {} + \\ + \\// top level normal comment + \\test "hi" {} + \\ + \\// middle + \\ + \\// end + \\ + ); +} + //test "zig fmt: preserve spacing" { // try testCanonical( // \\const std = @import("std"); @@ -2373,7 +2346,7 @@ test "zig fmt: resume from suspend block" { // \\ // ); //} -// + //test "zig fmt: return types" { // try testCanonical( // \\pub fn main() !void {} @@ -2798,43 +2771,43 @@ test "zig fmt: union declaration" { ); } -//test "zig fmt: arrays" { -// try testCanonical( -// \\test "test array" { -// \\ const a: [2]u8 = [2]u8{ -// \\ 1, -// \\ 2, -// \\ }; -// \\ const a: [2]u8 = []u8{ -// \\ 1, -// \\ 2, -// \\ }; -// \\ const a: [0]u8 = []u8{}; -// \\ const x: [4:0]u8 = undefined; -// \\} -// \\ -// ); -//} +test "zig fmt: arrays" { + try testCanonical( + \\test "test array" { + \\ const a: [2]u8 = [2]u8{ + \\ 1, + \\ 2, + \\ }; + \\ const a: [2]u8 = []u8{ + \\ 1, + \\ 2, + \\ }; + \\ const a: [0]u8 = []u8{}; + \\ const x: [4:0]u8 = undefined; + \\} + \\ + ); +} -//test "zig fmt: container initializers" { -// try testCanonical( -// \\const a0 = []u8{}; -// \\const a1 = []u8{1}; -// \\const a2 = []u8{ -// \\ 1, -// \\ 2, -// \\ 3, -// \\ 4, -// \\}; -// \\const s0 = S{}; -// \\const s1 = S{ .a = 1 }; -// \\const s2 = S{ -// \\ .a = 1, -// \\ .b = 2, -// \\}; -// \\ -// ); -//} +test "zig fmt: container initializers" { + try testCanonical( + \\const a0 = []u8{}; + \\const a1 = []u8{1}; + \\const a2 = []u8{ + \\ 1, + \\ 2, + \\ 3, + \\ 4, + \\}; + \\const s0 = S{}; + \\const s1 = S{ .a = 1 }; + \\const s2 = S{ + \\ .a = 1, + \\ .b = 2, + \\}; + \\ + ); +} test "zig fmt: catch" { try testCanonical( @@ -3563,62 +3536,62 @@ test "zig fmt: integer literals with underscore separators" { ); } -//test "zig fmt: hex literals with underscore separators" { -// try testTransform( -// \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 { -// \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000; -// \\ for (c [ 0_0 .. ]) |_, i| { -// \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; -// \\ } -// \\ return c; -// \\} -// \\ -// \\ -// , -// \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 { -// \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000; -// \\ for (c[0_0..]) |_, i| { -// \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; -// \\ } -// \\ return c; -// \\} -// \\ -// ); -//} +test "zig fmt: hex literals with underscore separators" { + try testTransform( + \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 { + \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000; + \\ for (c [ 0_0 .. ]) |_, i| { + \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; + \\ } + \\ return c; + \\} + \\ + \\ + , + \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 { + \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000; + \\ for (c[0_0..]) |_, i| { + \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; + \\ } + \\ return c; + \\} + \\ + ); +} -//test "zig fmt: decimal float literals with underscore separators" { -// try testTransform( -// \\pub fn main() void { -// \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4; -// \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2; -// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); -// \\} -// , -// \\pub fn main() void { -// \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4; -// \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2; -// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); -// \\} -// \\ -// ); -//} +test "zig fmt: decimal float literals with underscore separators" { + try testTransform( + \\pub fn main() void { + \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4; + \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + , + \\pub fn main() void { + \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4; + \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + \\ + ); +} -//test "zig fmt: hexadeciaml float literals with underscore separators" { -// try testTransform( -// \\pub fn main() void { -// \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16; -// \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4; -// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); -// \\} -// , -// \\pub fn main() void { -// \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16; -// \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4; -// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); -// \\} -// \\ -// ); -//} +test "zig fmt: hexadeciaml float literals with underscore separators" { + try testTransform( + \\pub fn main() void { + \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16; + \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + , + \\pub fn main() void { + \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16; + \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + \\ + ); +} //test "zig fmt: C var args" { // try testCanonical( diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 051b3f46b1..4ffbaeff19 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -37,66 +37,56 @@ pub fn render(gpa: *mem.Allocator, tree: ast.Tree) Error![]u8 { return buffer.toOwnedSlice(); } -/// Assumes there are no tokens in between start and end. -fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize, prefix: []const u8) Error!usize { +/// Assumes that start is the first byte past the previous token and +/// that end is the last byte before the next token. +fn renderCommentsAndNewlines(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!bool { var index: usize = start; - var count: usize = 0; - while (true) { - const comment_start = index + - (mem.indexOf(u8, tree.source[index..end], "//") orelse return count); + while (mem.indexOf(u8, tree.source[index..end], "//")) |offset| { + const comment_start = index + offset; const newline = comment_start + mem.indexOfScalar(u8, tree.source[comment_start..end], '\n').?; const untrimmed_comment = tree.source[comment_start..newline]; const trimmed_comment = mem.trimRight(u8, untrimmed_comment, " \r\t"); - if (count == 0) { - count += 1; - try ais.writer().writeAll(prefix); - } else { - // If another newline occurs between prev comment and this one - // we honor it, but not any additional ones. - if (mem.indexOfScalar(u8, tree.source[index..comment_start], '\n') != null) { - try ais.insertNewline(); - } + + // Leave up to one empty line before the comment + if (index == start and mem.containsAtLeast(u8, tree.source[index..comment_start], 2, "\n")) { + try ais.insertNewline(); + try ais.insertNewline(); + } else if (mem.indexOfScalar(u8, tree.source[index..comment_start], '\n') != null) { + // Respect the newline directly before the comment. This allows an + // empty line between comments + try ais.insertNewline(); + } else if (index == start and start != 0) { + // If the comment is on the same line as the token before it, + // prefix it with a single space + try ais.writer().writeByte(' '); } + try ais.writer().print("{s}\n", .{trimmed_comment}); index = newline + 1; } + + // Leave up to one empty line if present in the source + if (index > start) index -= 1; + if (end != tree.source.len and mem.containsAtLeast(u8, tree.source[index..end], 2, "\n")) { + try ais.insertNewline(); + } + + return index != start; } fn renderRoot(ais: *Ais, tree: ast.Tree) Error!void { // Render all the line comments at the beginning of the file. const src_start: usize = if (mem.startsWith(u8, tree.source, "\xEF\xBB\xBF")) 3 else 0; const comment_end_loc: usize = tree.tokens.items(.start)[0]; - _ = try renderComments(ais, tree, src_start, comment_end_loc, ""); + _ = try renderCommentsAndNewlines(ais, tree, src_start, comment_end_loc); // Root is always index 0. const nodes_data = tree.nodes.items(.data); const root_decls = tree.extra_data[nodes_data[0].lhs..nodes_data[0].rhs]; - return renderAllMembers(ais, tree, root_decls); -} - -fn renderAllMembers(ais: *Ais, tree: ast.Tree, members: []const ast.Node.Index) Error!void { - if (members.len == 0) return; - - const first_member = members[0]; - try renderMember(ais, tree, first_member, .Newline); - - for (members[1..]) |member| { - try renderExtraNewline(ais, tree, member); - try renderMember(ais, tree, member, .Newline); - } -} - -fn renderExtraNewline(ais: *Ais, tree: ast.Tree, node: ast.Node.Index) Error!void { - return renderExtraNewlineToken(ais, tree, tree.firstToken(node)); -} - -fn renderExtraNewlineToken(ais: *Ais, tree: ast.Tree, first_token: ast.TokenIndex) Error!void { - if (first_token == 0) return; - const token_starts = tree.tokens.items(.start); - if (tree.tokenLocation(token_starts[first_token - 1], first_token).line >= 2) { - return ais.insertNewline(); + for (root_decls) |decl| { + try renderMember(ais, tree, decl, .Newline); } } @@ -499,9 +489,11 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac }, .GroupedExpression => { - try renderToken(ais, tree, main_tokens[node], .None); + ais.pushIndentNextLine(); + try renderToken(ais, tree, main_tokens[node], .None); // lparen try renderExpression(ais, tree, datas[node].lhs, .None); - return renderToken(ais, tree, datas[node].rhs, space); + ais.popIndent(); + return renderToken(ais, tree, datas[node].rhs, space); // rparen }, .ContainerDecl, @@ -552,7 +544,6 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac ais.pushIndent(); var i = lbrace + 1; while (i < rbrace) : (i += 1) { - try renderExtraNewlineToken(ais, tree, i); switch (token_tags[i]) { .DocComment => try renderToken(ais, tree, i, .Newline), .Identifier => try renderToken(ais, tree, i, .Comma), @@ -635,11 +626,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac try renderToken(ais, tree, rparen + 1, .None); // lbrace return renderToken(ais, tree, rparen + 2, space); // rbrace } + ais.pushIndentNextLine(); try renderToken(ais, tree, rparen + 1, .Newline); // lbrace - ais.pushIndent(); - try renderExpression(ais, tree, cases[0], .Comma); - for (cases[1..]) |case| { - try renderExtraNewline(ais, tree, case); + for (cases) |case| { try renderExpression(ais, tree, case, .Comma); } ais.popIndent(); @@ -1469,9 +1458,7 @@ fn renderSwitchCase( try renderExpression(ais, tree, switch_case.ast.values[0], .Space); } else if (trailing_comma) { // Render each value on a new line - try renderExpression(ais, tree, switch_case.ast.values[0], .Comma); - for (switch_case.ast.values[1..]) |value_expr| { - try renderExtraNewline(ais, tree, value_expr); + for (switch_case.ast.values) |value_expr| { try renderExpression(ais, tree, value_expr, .Comma); } } else { @@ -1519,12 +1506,14 @@ fn renderBlock( } if (statements.len == 0) { + ais.pushIndentNextLine(); try renderToken(ais, tree, lbrace, .None); + ais.popIndent(); return renderToken(ais, tree, lbrace + 1, space); // rbrace } + ais.pushIndentNextLine(); try renderToken(ais, tree, lbrace, .Newline); - ais.pushIndent(); for (statements) |stmt, i| { switch (node_tags[stmt]) { .GlobalVarDecl => try renderVarDecl(ais, tree, tree.globalVarDecl(stmt)), @@ -1533,9 +1522,6 @@ fn renderBlock( .AlignedVarDecl => try renderVarDecl(ais, tree, tree.alignedVarDecl(stmt)), else => try renderExpression(ais, tree, stmt, .Semicolon), } - if (i + 1 < statements.len) { - try renderExtraNewline(ais, tree, statements[i + 1]); - } } ais.popIndent(); @@ -1566,18 +1552,14 @@ fn renderStructInit( ais.pushIndent(); try renderToken(ais, tree, struct_init.ast.lbrace, .Newline); - try renderToken(ais, tree, struct_init.ast.lbrace + 1, .None); // . - try renderToken(ais, tree, struct_init.ast.lbrace + 2, .Space); // name - try renderToken(ais, tree, struct_init.ast.lbrace + 3, .Space); // = - try renderExpression(ais, tree, struct_init.ast.fields[0], .Comma); - - for (struct_init.ast.fields[1..]) |field_init| { + for (struct_init.ast.fields) |field_init| { const init_token = tree.firstToken(field_init); try renderToken(ais, tree, init_token - 3, .None); // . try renderToken(ais, tree, init_token - 2, .Space); // name try renderToken(ais, tree, init_token - 1, .Space); // = - try renderExpressionNewlined(ais, tree, field_init, .Comma); + try renderExpression(ais, tree, field_init, .Comma); } + ais.popIndent(); return renderToken(ais, tree, last_field_token + 2, space); // rbrace } else { @@ -1620,9 +1602,8 @@ fn renderArrayInit( ais.pushIndent(); try renderToken(ais, tree, array_init.ast.lbrace, .Newline); - try renderExpression(ais, tree, array_init.ast.elements[0], .Comma); - for (array_init.ast.elements[1..]) |elem| { - try renderExpressionNewlined(ais, tree, elem, .Comma); + for (array_init.ast.elements) |elem| { + try renderExpression(ais, tree, elem, .Comma); } ais.popIndent(); @@ -1693,7 +1674,7 @@ fn renderContainerDecl( const last_member_token = tree.lastToken(last_member); const rbrace = switch (token_tags[last_member_token + 1]) { .DocComment => last_member_token + 2, - .Comma => switch (token_tags[last_member_token + 2]) { + .Comma, .Semicolon => switch (token_tags[last_member_token + 2]) { .DocComment => last_member_token + 3, .RBrace => last_member_token + 2, else => unreachable, @@ -1719,7 +1700,9 @@ fn renderContainerDecl( // One member per line. ais.pushIndent(); try renderToken(ais, tree, lbrace, .Newline); // lbrace - try renderAllMembers(ais, tree, container_decl.ast.members); + for (container_decl.ast.members) |member| { + try renderMember(ais, tree, member, .Newline); + } ais.popIndent(); return renderToken(ais, tree, rbrace, space); // rbrace @@ -1781,7 +1764,6 @@ fn renderAsm( const comma = tree.firstToken(next_asm_output) - 1; try renderToken(ais, tree, comma, .Newline); // , - try renderExtraNewlineToken(ais, tree, tree.firstToken(next_asm_output)); } else if (asm_node.inputs.len == 0 and asm_node.first_clobber == null) { try renderAsmOutput(ais, tree, asm_output, .Newline); ais.popIndent(); @@ -1813,7 +1795,6 @@ fn renderAsm( const first_token = tree.firstToken(next_asm_input); try renderToken(ais, tree, first_token - 1, .Newline); // , - try renderExtraNewlineToken(ais, tree, first_token); } else if (asm_node.first_clobber == null) { try renderAsmInput(ais, tree, asm_input, .Newline); ais.popIndent(); @@ -1894,8 +1875,6 @@ fn renderCall( try renderToken(ais, tree, comma, Space.Newline); // , if (is_multiline_string) ais.pushIndent(); - - try renderExtraNewline(ais, tree, params[i + 1]); } else { try renderExpression(ais, tree, param_node, Space.Comma); } @@ -1929,22 +1908,6 @@ fn renderExpressionComma(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: } } -/// Render an expression, but first insert an extra newline if the previous token is 2 or -/// more lines away. -fn renderExpressionNewlined( - ais: *Ais, - tree: ast.Tree, - node: ast.Node.Index, - space: Space, -) Error!void { - const token_starts = tree.tokens.items(.start); - const first_token = tree.firstToken(node); - if (tree.tokenLocation(token_starts[first_token - 1], first_token).line >= 2) { - try ais.insertNewline(); - } - return renderExpression(ais, tree, node, space); -} - fn renderTokenComma(ais: *Ais, tree: ast.Tree, token: ast.TokenIndex, space: Space) Error!void { const token_tags = tree.tokens.items(.tag); const maybe_comma = token + 1; @@ -1996,40 +1959,39 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp switch (space) { .NoComment => {}, - .None => {}, + .None => _ = try renderCommentsAndNewlines(ais, tree, token_start + lexeme.len, token_starts[token_index + 1]), .Comma => { - const count = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ", "); - if (count == 0 and token_tags[token_index + 1] == .Comma) { - return renderToken(ais, tree, token_index + 1, Space.Newline); - } - try ais.writer().writeAll(","); - - if (token_tags[token_index + 2] != .MultilineStringLiteralLine) { - try ais.insertNewline(); + const comment = try renderCommentsAndNewlines(ais, tree, token_start + lexeme.len, token_starts[token_index + 1]); + if (token_tags[token_index + 1] == .Comma) { + return renderToken(ais, tree, token_index + 1, .Newline); + } else if (!comment) { + return ais.insertNewline(); } }, .CommaSpace => { - _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ""); + const comment = try renderCommentsAndNewlines(ais, tree, token_start + lexeme.len, token_starts[token_index + 1]); if (token_tags[token_index + 1] == .Comma) { return renderToken(ais, tree, token_index + 1, .Space); - } else { + } else if (!comment) { return ais.writer().writeByte(' '); } }, .Semicolon => { - _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ""); + const comment = try renderCommentsAndNewlines(ais, tree, token_start + lexeme.len, token_starts[token_index + 1]); if (token_tags[token_index + 1] == .Semicolon) { return renderToken(ais, tree, token_index + 1, .Newline); - } else { + } else if (!comment) { return ais.insertNewline(); } }, .Space => { - _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ""); - return ais.writer().writeByte(' '); + const comment = try renderCommentsAndNewlines(ais, tree, token_start + lexeme.len, token_starts[token_index + 1]); + if (!comment) { + return ais.writer().writeByte(' '); + } }, .Newline => { - if (token_tags[token_index + 1] != .MultilineStringLiteralLine) { + if (!try renderCommentsAndNewlines(ais, tree, token_start + lexeme.len, token_starts[token_index + 1])) { try ais.insertNewline(); } }, |
