diff options
Diffstat (limited to 'lib/std')
39 files changed, 876 insertions, 853 deletions
diff --git a/lib/std/Thread/Condition.zig b/lib/std/Thread/Condition.zig index ecbc25fdb0..898fc14520 100644 --- a/lib/std/Thread/Condition.zig +++ b/lib/std/Thread/Condition.zig @@ -324,8 +324,6 @@ test "Condition - wait and signal" { return error.SkipZigTest; } - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const num_threads = 4; const MultiWait = struct { @@ -371,8 +369,6 @@ test "Condition - signal" { return error.SkipZigTest; } - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const num_threads = 4; const SignalTest = struct { @@ -440,8 +436,6 @@ test "Condition - multi signal" { return error.SkipZigTest; } - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const num_threads = 4; const num_iterations = 4; @@ -504,8 +498,6 @@ test "Condition - broadcasting" { return error.SkipZigTest; } - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const num_threads = 10; const BroadcastTest = struct { @@ -573,8 +565,6 @@ test "Condition - broadcasting - wake all threads" { return error.SkipZigTest; } - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var num_runs: usize = 1; const num_threads = 10; diff --git a/lib/std/Thread/Mutex.zig b/lib/std/Thread/Mutex.zig index c6416113b5..0f618516b5 100644 --- a/lib/std/Thread/Mutex.zig +++ b/lib/std/Thread/Mutex.zig @@ -289,8 +289,6 @@ test "Mutex - many contended" { return error.SkipZigTest; } - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const num_threads = 4; const num_increments = 1000; diff --git a/lib/std/Thread/RwLock.zig b/lib/std/Thread/RwLock.zig index 2cd101f913..e77db10abb 100644 --- a/lib/std/Thread/RwLock.zig +++ b/lib/std/Thread/RwLock.zig @@ -297,8 +297,6 @@ test "RwLock - concurrent access" { if (builtin.single_threaded) return; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const num_writers: usize = 2; const num_readers: usize = 4; const num_writes: usize = 10000; diff --git a/lib/std/Thread/Semaphore.zig b/lib/std/Thread/Semaphore.zig index 0c04e8a859..1b182d4c2a 100644 --- a/lib/std/Thread/Semaphore.zig +++ b/lib/std/Thread/Semaphore.zig @@ -39,8 +39,6 @@ test "Thread.Semaphore" { return error.SkipZigTest; } - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const TestContext = struct { sem: *Semaphore, n: *i32, diff --git a/lib/std/atomic/Atomic.zig b/lib/std/atomic/Atomic.zig index 2abe7fc4ca..e38ada0c20 100644 --- a/lib/std/atomic/Atomic.zig +++ b/lib/std/atomic/Atomic.zig @@ -467,8 +467,6 @@ test "Atomic.fetchSub" { } test "Atomic.fetchMin" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - inline for (atomicIntTypes()) |Int| { inline for (atomic_rmw_orderings) |ordering| { var x = Atomic(Int).init(5); diff --git a/lib/std/atomic/queue.zig b/lib/std/atomic/queue.zig index c28daead1b..e8d37507d3 100644 --- a/lib/std/atomic/queue.zig +++ b/lib/std/atomic/queue.zig @@ -175,8 +175,6 @@ const puts_per_thread = 500; const put_thread_count = 3; test "std.atomic.Queue" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var plenty_of_memory = try std.heap.page_allocator.alloc(u8, 300 * 1024); defer std.heap.page_allocator.free(plenty_of_memory); diff --git a/lib/std/base64.zig b/lib/std/base64.zig index bca829de38..8d0effd05b 100644 --- a/lib/std/base64.zig +++ b/lib/std/base64.zig @@ -355,8 +355,6 @@ pub const Base64DecoderWithIgnore = struct { }; test "base64" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - @setEvalBranchQuota(8000); try testBase64(); try comptime testAllApis(standard, "comptime", "Y29tcHRpbWU="); @@ -377,8 +375,6 @@ test "base64 padding dest overflow" { } test "base64 url_safe_no_pad" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - @setEvalBranchQuota(8000); try testBase64UrlSafeNoPad(); try comptime testAllApis(url_safe_no_pad, "comptime", "Y29tcHRpbWU"); diff --git a/lib/std/bit_set.zig b/lib/std/bit_set.zig index d87c1d26f6..a27c5b28a3 100644 --- a/lib/std/bit_set.zig +++ b/lib/std/bit_set.zig @@ -859,6 +859,18 @@ pub const DynamicBitSetUnmanaged = struct { self.masks[maskIndex(index)] &= ~maskBit(index); } + /// Set all bits to 0. + pub fn unsetAll(self: *Self) void { + const masks_len = numMasks(self.bit_length); + @memset(self.masks[0..masks_len], 0); + } + + /// Set all bits to 1. + pub fn setAll(self: *Self) void { + const masks_len = numMasks(self.bit_length); + @memset(self.masks[0..masks_len], std.math.maxInt(MaskInt)); + } + /// Flips a specific bit in the bit set pub fn toggle(self: *Self, index: usize) void { assert(index < self.bit_length); @@ -1638,7 +1650,6 @@ fn testStaticBitSet(comptime Set: type) !void { test "IntegerBitSet" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; try testStaticBitSet(IntegerBitSet(0)); try testStaticBitSet(IntegerBitSet(1)); @@ -1651,8 +1662,6 @@ test "IntegerBitSet" { } test "ArrayBitSet" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - inline for (.{ 0, 1, 2, 31, 32, 33, 63, 64, 65, 254, 500, 3000 }) |size| { try testStaticBitSet(ArrayBitSet(u8, size)); try testStaticBitSet(ArrayBitSet(u16, size)); diff --git a/lib/std/compress/zstandard.zig b/lib/std/compress/zstandard.zig index 10eb878a1c..401496ca28 100644 --- a/lib/std/compress/zstandard.zig +++ b/lib/std/compress/zstandard.zig @@ -264,8 +264,6 @@ fn testReader(data: []const u8, comptime expected: []const u8) !void { } test "zstandard decompression" { - if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest; - const uncompressed = @embedFile("testdata/rfc8478.txt"); const compressed3 = @embedFile("testdata/rfc8478.txt.zst.3"); const compressed19 = @embedFile("testdata/rfc8478.txt.zst.19"); diff --git a/lib/std/crypto/25519/ed25519.zig b/lib/std/crypto/25519/ed25519.zig index faeab59a0b..c00ce4387e 100644 --- a/lib/std/crypto/25519/ed25519.zig +++ b/lib/std/crypto/25519/ed25519.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const builtin = @import("builtin"); const crypto = std.crypto; const debug = std.debug; const fmt = std.fmt; @@ -276,8 +275,8 @@ pub const Ed25519 = struct { pub fn fromSecretKey(secret_key: SecretKey) (NonCanonicalError || EncodingError || IdentityElementError)!KeyPair { // It is critical for EdDSA to use the correct public key. // In order to enforce this, a SecretKey implicitly includes a copy of the public key. - // In Debug mode, we can still afford checking that the public key is correct for extra safety. - if (builtin.mode == .Debug) { + // With runtime safety, we can still afford checking that the public key is correct. + if (std.debug.runtime_safety) { const pk_p = try Curve.fromBytes(secret_key.publicKeyBytes()); const recomputed_kp = try create(secret_key.seed()); debug.assert(mem.eql(u8, &recomputed_kp.public_key.toBytes(), &pk_p.toBytes())); @@ -493,8 +492,6 @@ test "ed25519 key pair creation" { } test "ed25519 signature" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var seed: [32]u8 = undefined; _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); const key_pair = try Ed25519.KeyPair.create(seed); @@ -507,8 +504,6 @@ test "ed25519 signature" { } test "ed25519 batch verification" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var i: usize = 0; while (i < 100) : (i += 1) { const key_pair = try Ed25519.KeyPair.create(null); @@ -538,8 +533,6 @@ test "ed25519 batch verification" { } test "ed25519 test vectors" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const Vec = struct { msg_hex: *const [64:0]u8, public_key_hex: *const [64:0]u8, @@ -642,8 +635,6 @@ test "ed25519 test vectors" { } test "ed25519 with blind keys" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const BlindKeyPair = Ed25519.key_blinding.BlindKeyPair; // Create a standard Ed25519 key pair @@ -667,8 +658,6 @@ test "ed25519 with blind keys" { } test "ed25519 signatures with streaming" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const kp = try Ed25519.KeyPair.create(null); var signer = try kp.signer(null); diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index b7d24de0d6..9303e3c522 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -614,18 +614,18 @@ const Date = struct { }; pub fn parseTimeDigits(text: *const [2]u8, min: u8, max: u8) !u8 { - const nn: @Vector(2, u16) = .{ text[0], text[1] }; - const zero: @Vector(2, u16) = .{ '0', '0' }; - const mm: @Vector(2, u16) = .{ 10, 1 }; - const result = @reduce(.Add, (nn -% zero) *% mm); + const result = if (use_vectors) result: { + const nn: @Vector(2, u16) = .{ text[0], text[1] }; + const zero: @Vector(2, u16) = .{ '0', '0' }; + const mm: @Vector(2, u16) = .{ 10, 1 }; + break :result @reduce(.Add, (nn -% zero) *% mm); + } else std.fmt.parseInt(u8, text, 10) catch return error.CertificateTimeInvalid; if (result < min) return error.CertificateTimeInvalid; if (result > max) return error.CertificateTimeInvalid; return @truncate(result); } test parseTimeDigits { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const expectEqual = std.testing.expectEqual; try expectEqual(@as(u8, 0), try parseTimeDigits("00", 0, 99)); try expectEqual(@as(u8, 99), try parseTimeDigits("99", 0, 99)); @@ -638,17 +638,17 @@ test parseTimeDigits { } pub fn parseYear4(text: *const [4]u8) !u16 { - const nnnn: @Vector(4, u32) = .{ text[0], text[1], text[2], text[3] }; - const zero: @Vector(4, u32) = .{ '0', '0', '0', '0' }; - const mmmm: @Vector(4, u32) = .{ 1000, 100, 10, 1 }; - const result = @reduce(.Add, (nnnn -% zero) *% mmmm); + const result = if (use_vectors) result: { + const nnnn: @Vector(4, u32) = .{ text[0], text[1], text[2], text[3] }; + const zero: @Vector(4, u32) = .{ '0', '0', '0', '0' }; + const mmmm: @Vector(4, u32) = .{ 1000, 100, 10, 1 }; + break :result @reduce(.Add, (nnnn -% zero) *% mmmm); + } else std.fmt.parseInt(u16, text, 10) catch return error.CertificateTimeInvalid; if (result > 9999) return error.CertificateTimeInvalid; return @truncate(result); } test parseYear4 { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const expectEqual = std.testing.expectEqual; try expectEqual(@as(u16, 0), try parseYear4("0000")); try expectEqual(@as(u16, 9999), try parseYear4("9999")); @@ -1124,4 +1124,4 @@ pub const rsa = struct { } }; -const builtin = @import("builtin"); +const use_vectors = @import("builtin").zig_backend != .stage2_x86_64; diff --git a/lib/std/crypto/Certificate/Bundle.zig b/lib/std/crypto/Certificate/Bundle.zig index 1bffa325bd..b5a3832115 100644 --- a/lib/std/crypto/Certificate/Bundle.zig +++ b/lib/std/crypto/Certificate/Bundle.zig @@ -318,8 +318,6 @@ const MapContext = struct { test "scan for OS-provided certificates" { if (builtin.os.tag == .wasi) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var bundle: Bundle = .{}; defer bundle.deinit(std.testing.allocator); diff --git a/lib/std/crypto/aes.zig b/lib/std/crypto/aes.zig index c4f709d631..d043099f50 100644 --- a/lib/std/crypto/aes.zig +++ b/lib/std/crypto/aes.zig @@ -28,8 +28,6 @@ pub const Aes128 = impl.Aes128; pub const Aes256 = impl.Aes256; test "ctr" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - // NIST SP 800-38A pp 55-58 const ctr = @import("modes.zig").ctr; diff --git a/lib/std/crypto/aes_gcm.zig b/lib/std/crypto/aes_gcm.zig index e276c9dfd8..980a234c54 100644 --- a/lib/std/crypto/aes_gcm.zig +++ b/lib/std/crypto/aes_gcm.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const builtin = @import("builtin"); const assert = std.debug.assert; const crypto = std.crypto; const debug = std.debug; @@ -42,7 +41,7 @@ fn AesGcm(comptime Aes: anytype) type { mac.pad(); mem.writeInt(u32, j[nonce_length..][0..4], 2, .big); - modes.ctr(@TypeOf(aes), aes, c, m, j, std.builtin.Endian.big); + modes.ctr(@TypeOf(aes), aes, c, m, j, .big); mac.update(c[0..m.len][0..]); mac.pad(); @@ -104,7 +103,7 @@ fn AesGcm(comptime Aes: anytype) type { } mem.writeInt(u32, j[nonce_length..][0..4], 2, .big); - modes.ctr(@TypeOf(aes), aes, m, c, j, std.builtin.Endian.big); + modes.ctr(@TypeOf(aes), aes, m, c, j, .big); } }; } @@ -113,8 +112,6 @@ const htest = @import("test.zig"); const testing = std.testing; test "Aes256Gcm - Empty message and no associated data" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key: [Aes256Gcm.key_length]u8 = [_]u8{0x69} ** Aes256Gcm.key_length; const nonce: [Aes256Gcm.nonce_length]u8 = [_]u8{0x42} ** Aes256Gcm.nonce_length; const ad = ""; @@ -127,8 +124,6 @@ test "Aes256Gcm - Empty message and no associated data" { } test "Aes256Gcm - Associated data only" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key: [Aes256Gcm.key_length]u8 = [_]u8{0x69} ** Aes256Gcm.key_length; const nonce: [Aes256Gcm.nonce_length]u8 = [_]u8{0x42} ** Aes256Gcm.nonce_length; const m = ""; @@ -141,8 +136,6 @@ test "Aes256Gcm - Associated data only" { } test "Aes256Gcm - Message only" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key: [Aes256Gcm.key_length]u8 = [_]u8{0x69} ** Aes256Gcm.key_length; const nonce: [Aes256Gcm.nonce_length]u8 = [_]u8{0x42} ** Aes256Gcm.nonce_length; const m = "Test with message only"; @@ -160,8 +153,6 @@ test "Aes256Gcm - Message only" { } test "Aes256Gcm - Message and associated data" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key: [Aes256Gcm.key_length]u8 = [_]u8{0x69} ** Aes256Gcm.key_length; const nonce: [Aes256Gcm.nonce_length]u8 = [_]u8{0x42} ** Aes256Gcm.nonce_length; const m = "Test with message"; diff --git a/lib/std/crypto/argon2.zig b/lib/std/crypto/argon2.zig index 500bebd09c..4e6d391799 100644 --- a/lib/std/crypto/argon2.zig +++ b/lib/std/crypto/argon2.zig @@ -896,8 +896,6 @@ test "kdf" { } test "phc format hasher" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const allocator = std.testing.allocator; const password = "testpass"; @@ -913,8 +911,6 @@ test "phc format hasher" { } test "password hash and password verify" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const allocator = std.testing.allocator; const password = "testpass"; diff --git a/lib/std/crypto/bcrypt.zig b/lib/std/crypto/bcrypt.zig index 9fc2ecb63b..720f264d16 100644 --- a/lib/std/crypto/bcrypt.zig +++ b/lib/std/crypto/bcrypt.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const builtin = @import("builtin"); const base64 = std.base64; const crypto = std.crypto; const debug = std.debug; @@ -754,8 +753,6 @@ pub fn strVerify( } test "bcrypt codec" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var salt: [salt_length]u8 = undefined; crypto.random.bytes(&salt); var salt_str: [salt_str_length]u8 = undefined; @@ -766,8 +763,6 @@ test "bcrypt codec" { } test "bcrypt crypt format" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var hash_options = HashOptions{ .params = .{ .rounds_log = 5 }, .encoding = .crypt, @@ -808,8 +803,6 @@ test "bcrypt crypt format" { } test "bcrypt phc format" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var hash_options = HashOptions{ .params = .{ .rounds_log = 5 }, .encoding = .phc, diff --git a/lib/std/crypto/cmac.zig b/lib/std/crypto/cmac.zig index 32ba7f4b99..902bac591c 100644 --- a/lib/std/crypto/cmac.zig +++ b/lib/std/crypto/cmac.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const builtin = @import("builtin"); const crypto = std.crypto; const mem = std.mem; @@ -94,8 +93,6 @@ pub fn Cmac(comptime BlockCipher: type) type { const testing = std.testing; test "CmacAes128 - Example 1: len = 0" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, }; @@ -109,8 +106,6 @@ test "CmacAes128 - Example 1: len = 0" { } test "CmacAes128 - Example 2: len = 16" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, }; @@ -126,8 +121,6 @@ test "CmacAes128 - Example 2: len = 16" { } test "CmacAes128 - Example 3: len = 40" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, }; @@ -145,8 +138,6 @@ test "CmacAes128 - Example 3: len = 40" { } test "CmacAes128 - Example 4: len = 64" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, }; diff --git a/lib/std/crypto/ecdsa.zig b/lib/std/crypto/ecdsa.zig index e705fcf79b..6f8a32ea21 100644 --- a/lib/std/crypto/ecdsa.zig +++ b/lib/std/crypto/ecdsa.zig @@ -373,7 +373,6 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { test "ECDSA - Basic operations over EcdsaP384Sha384" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const Scheme = EcdsaP384Sha384; const kp = try Scheme.KeyPair.create(null); @@ -407,7 +406,6 @@ test "ECDSA - Basic operations over Secp256k1" { test "ECDSA - Basic operations over EcdsaP384Sha256" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); const kp = try Scheme.KeyPair.create(null); @@ -424,7 +422,6 @@ test "ECDSA - Basic operations over EcdsaP384Sha256" { test "ECDSA - Verifying a existing signature with EcdsaP384Sha256" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); // zig fmt: off @@ -469,7 +466,6 @@ const TestVector = struct { test "ECDSA - Test vectors from Project Wycheproof" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const vectors = [_]TestVector{ .{ .key = "042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", .msg = "313233343030", .sig = "304402202ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1802204cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76", .result = .valid }, @@ -884,7 +880,6 @@ fn tvTry(vector: TestVector) !void { test "ECDSA - Sec1 encoding/decoding" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const Scheme = EcdsaP384Sha384; const kp = try Scheme.KeyPair.create(null); diff --git a/lib/std/crypto/ghash_polyval.zig b/lib/std/crypto/ghash_polyval.zig index 6949553ad5..6ccbf1f228 100644 --- a/lib/std/crypto/ghash_polyval.zig +++ b/lib/std/crypto/ghash_polyval.zig @@ -422,8 +422,6 @@ fn Hash(comptime endian: std.builtin.Endian, comptime shift_key: bool) type { const htest = @import("test.zig"); test "ghash" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const key = [_]u8{0x42} ** 16; const m = [_]u8{0x69} ** 256; @@ -441,8 +439,6 @@ test "ghash" { } test "ghash2" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var key: [16]u8 = undefined; var i: usize = 0; while (i < key.len) : (i += 1) { diff --git a/lib/std/crypto/pcurves/p256.zig b/lib/std/crypto/pcurves/p256.zig index 37f16715f4..ec176f78c5 100644 --- a/lib/std/crypto/pcurves/p256.zig +++ b/lib/std/crypto/pcurves/p256.zig @@ -478,7 +478,5 @@ pub const AffineCoordinates = struct { }; test { - if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest; - _ = @import("tests/p256.zig"); } diff --git a/lib/std/crypto/phc_encoding.zig b/lib/std/crypto/phc_encoding.zig index 6ac8f66bb4..fecd7f1239 100644 --- a/lib/std/crypto/phc_encoding.zig +++ b/lib/std/crypto/phc_encoding.zig @@ -1,7 +1,6 @@ // https://github.com/P-H-C/phc-string-format const std = @import("std"); -const builtin = @import("builtin"); const fmt = std.fmt; const io = std.io; const mem = std.mem; @@ -264,8 +263,6 @@ fn kvSplit(str: []const u8) !struct { key: []const u8, value: []const u8 } { } test "phc format - encoding/decoding" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const Input = struct { str: []const u8, HashResult: type, diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index 31884c7381..10909cfaec 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -238,7 +238,7 @@ fn Sha2x32(comptime params: Sha2Params32) type { return; }, // C backend doesn't currently support passing vectors to inline asm. - .x86_64 => if (builtin.zig_backend != .stage2_c and comptime std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sha, .avx2 })) { + .x86_64 => if (builtin.zig_backend != .stage2_c and builtin.zig_backend != .stage2_x86_64 and comptime std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sha, .avx2 })) { var x: v4u32 = [_]u32{ d.s[5], d.s[4], d.s[1], d.s[0] }; var y: v4u32 = [_]u32{ d.s[7], d.s[6], d.s[3], d.s[2] }; const s_v = @as(*[16]v4u32, @ptrCast(&s)); diff --git a/lib/std/fmt/parse_float.zig b/lib/std/fmt/parse_float.zig index 00d19ea1c9..cdd11a6c59 100644 --- a/lib/std/fmt/parse_float.zig +++ b/lib/std/fmt/parse_float.zig @@ -83,8 +83,6 @@ test "fmt.parseFloat #11169" { } test "fmt.parseFloat hex.special" { - if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testing.expect(math.isNan(try parseFloat(f32, "nAn"))); try testing.expect(math.isPositiveInf(try parseFloat(f32, "iNf"))); try testing.expect(math.isPositiveInf(try parseFloat(f32, "+Inf"))); diff --git a/lib/std/hash/xxhash.zig b/lib/std/hash/xxhash.zig index 2e4c11e333..eef9c9654a 100644 --- a/lib/std/hash/xxhash.zig +++ b/lib/std/hash/xxhash.zig @@ -2,6 +2,7 @@ const std = @import("std"); const builtin = @import("builtin"); const mem = std.mem; const expectEqual = std.testing.expectEqual; +const native_endian = builtin.cpu.arch.endian(); const rotl = std.math.rotl; @@ -472,7 +473,7 @@ pub const XxHash3 = struct { } inline fn swap(x: anytype) @TypeOf(x) { - return if (builtin.cpu.arch.endian() == .big) @byteSwap(x) else x; + return if (native_endian == .big) @byteSwap(x) else x; } inline fn disableAutoVectorization(x: anytype) void { diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig index e8e0363c2e..eb9896d40a 100644 --- a/lib/std/http/Client.zig +++ b/lib/std/http/Client.zig @@ -9,6 +9,7 @@ const net = std.net; const Uri = std.Uri; const Allocator = mem.Allocator; const assert = std.debug.assert; +const use_vectors = builtin.zig_backend != .stage2_x86_64; const Client = @This(); const proto = @import("protocol.zig"); @@ -408,7 +409,7 @@ pub const Response = struct { else => return error.HttpHeadersInvalid, }; if (first_line[8] != ' ') return error.HttpHeadersInvalid; - const status = @as(http.Status, @enumFromInt(parseInt3(first_line[9..12].*))); + const status: http.Status = @enumFromInt(parseInt3(first_line[9..12])); const reason = mem.trimLeft(u8, first_line[12..], " "); res.version = version; @@ -481,20 +482,24 @@ pub const Response = struct { } inline fn int64(array: *const [8]u8) u64 { - return @as(u64, @bitCast(array.*)); + return @bitCast(array.*); } - fn parseInt3(nnn: @Vector(3, u8)) u10 { - const zero: @Vector(3, u8) = .{ '0', '0', '0' }; - const mmm: @Vector(3, u10) = .{ 100, 10, 1 }; - return @reduce(.Add, @as(@Vector(3, u10), nnn -% zero) *% mmm); + fn parseInt3(text: *const [3]u8) u10 { + if (use_vectors) { + const nnn: @Vector(3, u8) = text.*; + const zero: @Vector(3, u8) = .{ '0', '0', '0' }; + const mmm: @Vector(3, u10) = .{ 100, 10, 1 }; + return @reduce(.Add, @as(@Vector(3, u10), nnn -% zero) *% mmm); + } + return std.fmt.parseInt(u10, text, 10) catch unreachable; } test parseInt3 { const expectEqual = testing.expectEqual; - try expectEqual(@as(u10, 0), parseInt3("000".*)); - try expectEqual(@as(u10, 418), parseInt3("418".*)); - try expectEqual(@as(u10, 999), parseInt3("999".*)); + try expectEqual(@as(u10, 0), parseInt3("000")); + try expectEqual(@as(u10, 418), parseInt3("418")); + try expectEqual(@as(u10, 999), parseInt3("999")); } version: http.Version, @@ -1588,7 +1593,8 @@ test { if (builtin.os.tag == .wasi) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and + !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .avx)) return error.SkipZigTest; std.testing.refAllDecls(@This()); } diff --git a/lib/std/http/Server.zig b/lib/std/http/Server.zig index 055d16eb8a..6928606b1b 100644 --- a/lib/std/http/Server.zig +++ b/lib/std/http/Server.zig @@ -736,8 +736,6 @@ test "HTTP server handles a chunked transfer coding request" { return error.SkipZigTest; } - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const native_endian = comptime builtin.cpu.arch.endian(); if (builtin.zig_backend == .stage2_llvm and native_endian == .big) { // https://github.com/ziglang/zig/issues/13782 diff --git a/lib/std/http/protocol.zig b/lib/std/http/protocol.zig index 8e458ed09c..4fe9c80380 100644 --- a/lib/std/http/protocol.zig +++ b/lib/std/http/protocol.zig @@ -1,8 +1,10 @@ const std = @import("../std.zig"); +const builtin = @import("builtin"); const testing = std.testing; const mem = std.mem; const assert = std.debug.assert; +const use_vectors = builtin.zig_backend != .stage2_x86_64; pub const State = enum { /// Begin header parsing states. @@ -83,7 +85,7 @@ pub const HeadersParser = struct { /// first byte of content is located at `bytes[result]`. pub fn findHeadersEnd(r: *HeadersParser, bytes: []const u8) u32 { const vector_len: comptime_int = @max(std.simd.suggestVectorSize(u8) orelse 1, 8); - const len = @as(u32, @intCast(bytes.len)); + const len: u32 = @intCast(bytes.len); var index: u32 = 0; while (true) { @@ -175,18 +177,27 @@ pub const HeadersParser = struct { continue; }, else => { - const Vector = @Vector(vector_len, u8); - // const BoolVector = @Vector(vector_len, bool); - const BitVector = @Vector(vector_len, u1); - const SizeVector = @Vector(vector_len, u8); - const chunk = bytes[index..][0..vector_len]; - const v: Vector = chunk.*; - const matches_r = @as(BitVector, @bitCast(v == @as(Vector, @splat('\r')))); - const matches_n = @as(BitVector, @bitCast(v == @as(Vector, @splat('\n')))); - const matches_or: SizeVector = matches_r | matches_n; - - const matches = @reduce(.Add, matches_or); + const matches = if (use_vectors) matches: { + const Vector = @Vector(vector_len, u8); + // const BoolVector = @Vector(vector_len, bool); + const BitVector = @Vector(vector_len, u1); + const SizeVector = @Vector(vector_len, u8); + + const v: Vector = chunk.*; + const matches_r: BitVector = @bitCast(v == @as(Vector, @splat('\r'))); + const matches_n: BitVector = @bitCast(v == @as(Vector, @splat('\n'))); + const matches_or: SizeVector = matches_r | matches_n; + + break :matches @reduce(.Add, matches_or); + } else matches: { + var matches: u8 = 0; + for (chunk) |byte| switch (byte) { + '\r', '\n' => matches += 1, + else => {}, + }; + break :matches matches; + }; switch (matches) { 0 => {}, 1 => switch (chunk[vector_len - 1]) { diff --git a/lib/std/math.zig b/lib/std/math.zig index f110efa0af..b18d5bc3ed 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -492,8 +492,6 @@ pub fn shl(comptime T: type, a: T, shift_amt: anytype) T { } test "shl" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // https://github.com/ziglang/zig/issues/12012 return error.SkipZigTest; @@ -539,8 +537,6 @@ pub fn shr(comptime T: type, a: T, shift_amt: anytype) T { } test "shr" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // https://github.com/ziglang/zig/issues/12012 return error.SkipZigTest; @@ -587,8 +583,6 @@ pub fn rotr(comptime T: type, x: T, r: anytype) T { } test "rotr" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // https://github.com/ziglang/zig/issues/12012 return error.SkipZigTest; @@ -634,8 +628,6 @@ pub fn rotl(comptime T: type, x: T, r: anytype) T { } test "rotl" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // https://github.com/ziglang/zig/issues/12012 return error.SkipZigTest; @@ -764,8 +756,6 @@ pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { } test "divTrunc" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testDivTrunc(); try comptime testDivTrunc(); } @@ -790,8 +780,6 @@ pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T { } test "divFloor" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testDivFloor(); try comptime testDivFloor(); } @@ -829,8 +817,6 @@ pub fn divCeil(comptime T: type, numerator: T, denominator: T) !T { } test "divCeil" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testDivCeil(); try comptime testDivCeil(); } @@ -875,8 +861,6 @@ pub fn divExact(comptime T: type, numerator: T, denominator: T) !T { } test "divExact" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testDivExact(); try comptime testDivExact(); } @@ -903,8 +887,6 @@ pub fn mod(comptime T: type, numerator: T, denominator: T) !T { } test "mod" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testMod(); try comptime testMod(); } @@ -931,8 +913,6 @@ pub fn rem(comptime T: type, numerator: T, denominator: T) !T { } test "rem" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testRem(); try comptime testRem(); } @@ -1285,7 +1265,8 @@ pub fn lerp(a: anytype, b: anytype, t: anytype) @TypeOf(a, b, t) { } test "lerp" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and + !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .fma)) return error.SkipZigTest; try testing.expectEqual(@as(f64, 75), lerp(50, 100, 0.5)); try testing.expectEqual(@as(f32, 43.75), lerp(50, 25, 0.25)); diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 4051a8cd31..ce73c0c648 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -1318,7 +1318,7 @@ pub const Mutable = struct { /// /// `limbs_buffer` is used for temporary storage. /// The amount required is given by `calcPowLimbsBufferLen`. - pub fn pow(r: *Mutable, a: Const, b: u32, limbs_buffer: []Limb) !void { + pub fn pow(r: *Mutable, a: Const, b: u32, limbs_buffer: []Limb) void { assert(r.limbs.ptr != a.limbs.ptr); // illegal aliasing // Handle all the trivial cases first @@ -3213,7 +3213,7 @@ pub const Managed = struct { var m = try Managed.initCapacity(rma.allocator, needed_limbs); errdefer m.deinit(); var m_mut = m.toMutable(); - try m_mut.pow(a.toConst(), b, limbs_buffer); + m_mut.pow(a.toConst(), b, limbs_buffer); m.setMetadata(m_mut.positive, m_mut.len); rma.deinit(); @@ -3221,7 +3221,7 @@ pub const Managed = struct { } else { try rma.ensureCapacity(needed_limbs); var rma_mut = rma.toMutable(); - try rma_mut.pow(a.toConst(), b, limbs_buffer); + rma_mut.pow(a.toConst(), b, limbs_buffer); rma.setMetadata(rma_mut.positive, rma_mut.len); } } diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index 4a3bf10fcd..da8fb98c5c 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -2568,8 +2568,6 @@ test "big.int const to managed" { } test "big.int pow" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - { var a = try Managed.initSet(testing.allocator, -3); defer a.deinit(); @@ -2763,8 +2761,6 @@ fn popCountTest(val: *const Managed, bit_count: usize, expected: usize) !void { } test "big int conversion read/write twos complement" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, (1 << 493) - 1); defer a.deinit(); var b = try Managed.initSet(testing.allocator, (1 << 493) - 1); @@ -2863,8 +2859,6 @@ test "big int write twos complement +/- zero" { } test "big int conversion write twos complement with padding" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x01_ffffffff_ffffffff_ffffffff); defer a.deinit(); diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 420e461ae5..73fe2e7757 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -315,8 +315,6 @@ pub fn zeroes(comptime T: type) T { } test "zeroes" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const C_struct = extern struct { x: u32, y: u32 align(128), @@ -4342,8 +4340,6 @@ pub fn alignInSlice(slice: anytype, comptime new_alignment: usize) ?AlignedSlice } test "read/write(Var)PackedInt" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - switch (builtin.cpu.arch) { // This test generates too much code to execute on WASI. // LLVM backend fails with "too many locals: locals exceed maximum" diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index 11dec78036..5ff5144028 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -106,7 +106,7 @@ pub fn MultiArrayList(comptime T: type) type { } pub fn toMultiArrayList(self: Slice) Self { - if (self.ptrs.len == 0) { + if (self.ptrs.len == 0 or self.capacity == 0) { return .{}; } const unaligned_ptr = self.ptrs[sizes.fields[0]]; diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig index fd92c64f35..0fe53a7b9f 100644 --- a/lib/std/net/test.zig +++ b/lib/std/net/test.zig @@ -60,7 +60,7 @@ test "parse and render IPv6 addresses" { } test "invalid but parseable IPv6 scope ids" { - if (builtin.os.tag != .linux or comptime !builtin.os.tag.isDarwin()) { + if (builtin.os.tag != .linux and comptime !builtin.os.tag.isDarwin()) { // Currently, resolveIp6 with alphanumerical scope IDs only works on Linux. // TODO Make this test pass on other operating systems. return error.SkipZigTest; diff --git a/lib/std/once.zig b/lib/std/once.zig index 87f81ee59c..f012e017dd 100644 --- a/lib/std/once.zig +++ b/lib/std/once.zig @@ -46,8 +46,6 @@ fn incr() void { } test "Once executes its function just once" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.single_threaded) { global_once.call(); global_once.call(); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index b7c1b7b675..f4a67f1035 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -375,8 +375,6 @@ fn testThreadIdFn(thread_id: *Thread.Id) void { test "std.Thread.getCurrentId" { if (builtin.single_threaded) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var thread_current_id: Thread.Id = undefined; const thread = try Thread.spawn(.{}, testThreadIdFn, .{&thread_current_id}); thread.join(); @@ -420,8 +418,6 @@ test "cpu count" { test "thread local storage" { if (builtin.single_threaded) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - const thread1 = try Thread.spawn(.{}, testTls, .{}); const thread2 = try Thread.spawn(.{}, testTls, .{}); try testTls(); diff --git a/lib/std/rand/test.zig b/lib/std/rand/test.zig index e8a1d4de8a..d02c016357 100644 --- a/lib/std/rand/test.zig +++ b/lib/std/rand/test.zig @@ -1,5 +1,4 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); const math = std.math; const DefaultPrng = std.rand.DefaultPrng; const Random = std.rand.Random; @@ -200,8 +199,6 @@ fn testRandomIntLessThan() !void { } test "Random intAtMost" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - @setEvalBranchQuota(10000); try testRandomIntAtMost(); try comptime testRandomIntAtMost(); @@ -242,8 +239,6 @@ fn testRandomIntAtMost() !void { } test "Random Biased" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var prng = DefaultPrng.init(0); const random = prng.random(); // Not thoroughly checking the logic here. @@ -452,8 +447,6 @@ test "CSPRNG" { } test "Random weightedIndex" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - // Make sure weightedIndex works for various integers and floats inline for (.{ u64, i4, f32, f64 }) |T| { var prng = DefaultPrng.init(0); diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index c918f8a980..c1e054036f 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -113,12 +113,14 @@ pub fn render(tree: Ast, gpa: Allocator) RenderError![]u8 { var buffer = std.ArrayList(u8).init(gpa); defer buffer.deinit(); - try tree.renderToArrayList(&buffer); + try tree.renderToArrayList(&buffer, .{}); return buffer.toOwnedSlice(); } -pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void { - return @import("./render.zig").renderTree(buffer, tree); +pub const Fixups = private_render.Fixups; + +pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8), fixups: Fixups) RenderError!void { + return @import("./render.zig").renderTree(buffer, tree, fixups); } /// Returns an extra offset for column and byte offset of errors that @@ -3530,6 +3532,7 @@ const Token = std.zig.Token; const Ast = @This(); const Allocator = std.mem.Allocator; const Parse = @import("Parse.zig"); +const private_render = @import("./render.zig"); test { testing.refAllDecls(@This()); diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index a7a03c1f8d..45aaf1bd28 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -14,49 +14,96 @@ pub const Error = Ast.RenderError; const Ais = AutoIndentingStream(std.ArrayList(u8).Writer); -pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast) Error!void { +pub const Fixups = struct { + /// The key is the mut token (`var`/`const`) of the variable declaration + /// that should have a `_ = foo;` inserted afterwards. + unused_var_decls: std.AutoHashMapUnmanaged(Ast.TokenIndex, void) = .{}, + /// The functions in this unordered set of AST fn decl nodes will render + /// with a function body of `@trap()` instead, with all parameters + /// discarded. + gut_functions: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, + /// These global declarations will be omitted. + omit_nodes: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, + /// These expressions will be replaced with `undefined`. + replace_nodes: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, + + pub fn count(f: Fixups) usize { + return f.unused_var_decls.count() + + f.gut_functions.count() + + f.omit_nodes.count() + + f.replace_nodes.count(); + } + + pub fn clearRetainingCapacity(f: *Fixups) void { + f.unused_var_decls.clearRetainingCapacity(); + f.gut_functions.clearRetainingCapacity(); + f.omit_nodes.clearRetainingCapacity(); + f.replace_nodes.clearRetainingCapacity(); + } + + pub fn deinit(f: *Fixups, gpa: Allocator) void { + f.unused_var_decls.deinit(gpa); + f.gut_functions.deinit(gpa); + f.omit_nodes.deinit(gpa); + f.replace_nodes.deinit(gpa); + f.* = undefined; + } +}; + +const Render = struct { + gpa: Allocator, + ais: *Ais, + tree: Ast, + fixups: Fixups, +}; + +pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast, fixups: Fixups) Error!void { assert(tree.errors.len == 0); // Cannot render an invalid tree. var auto_indenting_stream = Ais{ .indent_delta = indent_delta, .underlying_writer = buffer.writer(), }; - const ais = &auto_indenting_stream; + var r: Render = .{ + .gpa = buffer.allocator, + .ais = &auto_indenting_stream, + .tree = tree, + .fixups = fixups, + }; // Render all the line comments at the beginning of the file. const comment_end_loc = tree.tokens.items(.start)[0]; - _ = try renderComments(ais, tree, 0, comment_end_loc); + _ = try renderComments(&r, 0, comment_end_loc); if (tree.tokens.items(.tag)[0] == .container_doc_comment) { - try renderContainerDocComments(ais, tree, 0); + try renderContainerDocComments(&r, 0); } if (tree.mode == .zon) { try renderExpression( - buffer.allocator, - ais, - tree, + &r, tree.nodes.items(.data)[0].lhs, .newline, ); } else { - try renderMembers(buffer.allocator, ais, tree, tree.rootDecls()); + try renderMembers(&r, tree.rootDecls()); } - if (ais.disabled_offset) |disabled_offset| { - try writeFixingWhitespace(ais.underlying_writer, tree.source[disabled_offset..]); + if (auto_indenting_stream.disabled_offset) |disabled_offset| { + try writeFixingWhitespace(auto_indenting_stream.underlying_writer, tree.source[disabled_offset..]); } } /// Render all members in the given slice, keeping empty lines where appropriate -fn renderMembers(gpa: Allocator, ais: *Ais, tree: Ast, members: []const Ast.Node.Index) Error!void { +fn renderMembers(r: *Render, members: []const Ast.Node.Index) Error!void { + const tree = r.tree; if (members.len == 0) return; const container: Container = for (members) |member| { if (tree.fullContainerField(member)) |field| if (!field.ast.tuple_like) break .other; } else .tuple; - try renderMember(gpa, ais, tree, container, members[0], .newline); + try renderMember(r, container, members[0], .newline); for (members[1..]) |member| { - try renderExtraNewline(ais, tree, member); - try renderMember(gpa, ais, tree, container, member, .newline); + try renderExtraNewline(r, member); + try renderMember(r, container, member, .newline); } } @@ -67,17 +114,18 @@ const Container = enum { }; fn renderMember( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, container: Container, decl: Ast.Node.Index, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); const main_tokens = tree.nodes.items(.main_token); const datas = tree.nodes.items(.data); - try renderDocComments(ais, tree, tree.firstToken(decl)); + if (r.fixups.omit_nodes.contains(decl)) return; + try renderDocComments(r, tree.firstToken(decl)); switch (tree.nodes.items(.tag)[decl]) { .fn_decl => { // Some examples: @@ -105,7 +153,7 @@ fn renderMember( } } while (i < fn_token) : (i += 1) { - try renderToken(ais, tree, i, .space); + try renderToken(r, i, .space); } switch (tree.nodes.items(.tag)[fn_proto]) { .fn_proto_one, .fn_proto => { @@ -123,8 +171,20 @@ fn renderMember( else => unreachable, } assert(datas[decl].rhs != 0); - try renderExpression(gpa, ais, tree, fn_proto, .space); - return renderExpression(gpa, ais, tree, datas[decl].rhs, space); + try renderExpression(r, fn_proto, .space); + const body_node = datas[decl].rhs; + if (r.fixups.gut_functions.contains(decl)) { + ais.pushIndent(); + const lbrace = tree.nodes.items(.main_token)[body_node]; + try renderToken(r, lbrace, .newline); + try discardAllParams(r, fn_proto); + try ais.writer().writeAll("@trap();"); + ais.popIndent(); + try ais.insertNewline(); + try renderToken(r, tree.lastToken(body_node), space); // rbrace + } else { + return renderExpression(r, body_node, space); + } }, .fn_proto_simple, .fn_proto_multi, @@ -153,47 +213,47 @@ fn renderMember( } } while (i < fn_token) : (i += 1) { - try renderToken(ais, tree, i, .space); + try renderToken(r, i, .space); } - try renderExpression(gpa, ais, tree, decl, .none); - return renderToken(ais, tree, tree.lastToken(decl) + 1, space); // semicolon + try renderExpression(r, decl, .none); + return renderToken(r, tree.lastToken(decl) + 1, space); // semicolon }, .@"usingnamespace" => { const main_token = main_tokens[decl]; const expr = datas[decl].lhs; if (main_token > 0 and token_tags[main_token - 1] == .keyword_pub) { - try renderToken(ais, tree, main_token - 1, .space); // pub + try renderToken(r, main_token - 1, .space); // pub } - try renderToken(ais, tree, main_token, .space); // usingnamespace - try renderExpression(gpa, ais, tree, expr, .none); - return renderToken(ais, tree, tree.lastToken(expr) + 1, space); // ; + try renderToken(r, main_token, .space); // usingnamespace + try renderExpression(r, expr, .none); + return renderToken(r, tree.lastToken(expr) + 1, space); // ; }, .global_var_decl, .local_var_decl, .simple_var_decl, .aligned_var_decl, - => return renderVarDecl(gpa, ais, tree, tree.fullVarDecl(decl).?, false, .semicolon), + => return renderVarDecl(r, tree.fullVarDecl(decl).?, false, .semicolon), .test_decl => { const test_token = main_tokens[decl]; - try renderToken(ais, tree, test_token, .space); + try renderToken(r, test_token, .space); const test_name_tag = token_tags[test_token + 1]; switch (test_name_tag) { - .string_literal => try renderToken(ais, tree, test_token + 1, .space), - .identifier => try renderIdentifier(ais, tree, test_token + 1, .space, .preserve_when_shadowing), + .string_literal => try renderToken(r, test_token + 1, .space), + .identifier => try renderIdentifier(r, test_token + 1, .space, .preserve_when_shadowing), else => {}, } - try renderExpression(gpa, ais, tree, datas[decl].rhs, space); + try renderExpression(r, datas[decl].rhs, space); }, .container_field_init, .container_field_align, .container_field, - => return renderContainerField(gpa, ais, tree, container, tree.fullContainerField(decl).?, space), + => return renderContainerField(r, container, tree.fullContainerField(decl).?, space), - .@"comptime" => return renderExpression(gpa, ais, tree, decl, space), + .@"comptime" => return renderExpression(r, decl, space), .root => unreachable, else => unreachable, @@ -201,24 +261,31 @@ fn renderMember( } /// Render all expressions in the slice, keeping empty lines where appropriate -fn renderExpressions(gpa: Allocator, ais: *Ais, tree: Ast, expressions: []const Ast.Node.Index, space: Space) Error!void { +fn renderExpressions(r: *Render, expressions: []const Ast.Node.Index, space: Space) Error!void { if (expressions.len == 0) return; - try renderExpression(gpa, ais, tree, expressions[0], space); + try renderExpression(r, expressions[0], space); for (expressions[1..]) |expression| { - try renderExtraNewline(ais, tree, expression); - try renderExpression(gpa, ais, tree, expression, space); + try renderExtraNewline(r, expression); + try renderExpression(r, expression, space); } } -fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void { +fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); const main_tokens = tree.nodes.items(.main_token); const node_tags = tree.nodes.items(.tag); const datas = tree.nodes.items(.data); + if (r.fixups.replace_nodes.contains(node)) { + try ais.writer().writeAll("undefined"); + try renderOnlySpace(r, space); + return; + } switch (node_tags[node]) { .identifier => { const token_index = main_tokens[node]; - return renderIdentifier(ais, tree, token_index, space, .preserve_when_shadowing); + return renderIdentifier(r, token_index, space, .preserve_when_shadowing); }, .number_literal, @@ -226,29 +293,29 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .unreachable_literal, .anyframe_literal, .string_literal, - => return renderToken(ais, tree, main_tokens[node], space), + => return renderToken(r, main_tokens[node], space), .multiline_string_literal => { var locked_indents = ais.lockOneShotIndent(); try ais.maybeInsertNewline(); var i = datas[node].lhs; - while (i <= datas[node].rhs) : (i += 1) try renderToken(ais, tree, i, .newline); + while (i <= datas[node].rhs) : (i += 1) try renderToken(r, i, .newline); while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent(); switch (space) { .none, .space, .newline, .skip => {}, - .semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline), - .comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline), - .comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space), + .semicolon => if (token_tags[i] == .semicolon) try renderToken(r, i, .newline), + .comma => if (token_tags[i] == .comma) try renderToken(r, i, .newline), + .comma_space => if (token_tags[i] == .comma) try renderToken(r, i, .space), } }, .error_value => { - try renderToken(ais, tree, main_tokens[node], .none); - try renderToken(ais, tree, main_tokens[node] + 1, .none); - return renderIdentifier(ais, tree, main_tokens[node] + 2, space, .eagerly_unquote); + try renderToken(r, main_tokens[node], .none); + try renderToken(r, main_tokens[node] + 1, .none); + return renderIdentifier(r, main_tokens[node] + 2, space, .eagerly_unquote); }, .block_two, @@ -256,18 +323,18 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, => { const statements = [2]Ast.Node.Index{ datas[node].lhs, datas[node].rhs }; if (datas[node].lhs == 0) { - return renderBlock(gpa, ais, tree, node, statements[0..0], space); + return renderBlock(r, node, statements[0..0], space); } else if (datas[node].rhs == 0) { - return renderBlock(gpa, ais, tree, node, statements[0..1], space); + return renderBlock(r, node, statements[0..1], space); } else { - return renderBlock(gpa, ais, tree, node, statements[0..2], space); + return renderBlock(r, node, statements[0..2], space); } }, .block, .block_semicolon, => { const statements = tree.extra_data[datas[node].lhs..datas[node].rhs]; - return renderBlock(gpa, ais, tree, node, statements, space); + return renderBlock(r, node, statements, space); }, .@"errdefer" => { @@ -275,33 +342,33 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, const payload_token = datas[node].lhs; const expr = datas[node].rhs; - try renderToken(ais, tree, defer_token, .space); + try renderToken(r, defer_token, .space); if (payload_token != 0) { - try renderToken(ais, tree, payload_token - 1, .none); // | - try renderIdentifier(ais, tree, payload_token, .none, .preserve_when_shadowing); // identifier - try renderToken(ais, tree, payload_token + 1, .space); // | + try renderToken(r, payload_token - 1, .none); // | + try renderIdentifier(r, payload_token, .none, .preserve_when_shadowing); // identifier + try renderToken(r, payload_token + 1, .space); // | } - return renderExpression(gpa, ais, tree, expr, space); + return renderExpression(r, expr, space); }, .@"defer" => { const defer_token = main_tokens[node]; const expr = datas[node].rhs; - try renderToken(ais, tree, defer_token, .space); - return renderExpression(gpa, ais, tree, expr, space); + try renderToken(r, defer_token, .space); + return renderExpression(r, expr, space); }, .@"comptime", .@"nosuspend" => { const comptime_token = main_tokens[node]; const block = datas[node].lhs; - try renderToken(ais, tree, comptime_token, .space); - return renderExpression(gpa, ais, tree, block, space); + try renderToken(r, comptime_token, .space); + return renderExpression(r, block, space); }, .@"suspend" => { const suspend_token = main_tokens[node]; const body = datas[node].lhs; - try renderToken(ais, tree, suspend_token, .space); - return renderExpression(gpa, ais, tree, body, space); + try renderToken(r, suspend_token, .space); + return renderExpression(r, body, space); }, .@"catch" => { @@ -311,27 +378,27 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, const same_line = tree.tokensOnSameLine(main_token, fallback_first); const after_op_space = if (same_line) Space.space else Space.newline; - try renderExpression(gpa, ais, tree, datas[node].lhs, .space); // target + try renderExpression(r, datas[node].lhs, .space); // target if (token_tags[fallback_first - 1] == .pipe) { - try renderToken(ais, tree, main_token, .space); // catch keyword - try renderToken(ais, tree, main_token + 1, .none); // pipe - try renderIdentifier(ais, tree, main_token + 2, .none, .preserve_when_shadowing); // payload identifier - try renderToken(ais, tree, main_token + 3, after_op_space); // pipe + try renderToken(r, main_token, .space); // catch keyword + try renderToken(r, main_token + 1, .none); // pipe + try renderIdentifier(r, main_token + 2, .none, .preserve_when_shadowing); // payload identifier + try renderToken(r, main_token + 3, after_op_space); // pipe } else { assert(token_tags[fallback_first - 1] == .keyword_catch); - try renderToken(ais, tree, main_token, after_op_space); // catch keyword + try renderToken(r, main_token, after_op_space); // catch keyword } ais.pushIndentOneShot(); - try renderExpression(gpa, ais, tree, datas[node].rhs, space); // fallback + try renderExpression(r, datas[node].rhs, space); // fallback }, .field_access => { const main_token = main_tokens[node]; const field_access = datas[node]; - try renderExpression(gpa, ais, tree, field_access.lhs, .none); + try renderExpression(r, field_access.lhs, .none); // Allow a line break between the lhs and the dot if the lhs and rhs // are on different lines. @@ -342,7 +409,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, ais.pushIndentOneShot(); } - try renderToken(ais, tree, main_token, .none); // . + try renderToken(r, main_token, .none); // . // This check ensures that zag() is indented in the following example: // const x = foo @@ -353,25 +420,25 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, ais.pushIndentOneShot(); } - return renderIdentifier(ais, tree, field_access.rhs, space, .eagerly_unquote); // field + return renderIdentifier(r, field_access.rhs, space, .eagerly_unquote); // field }, .error_union, .switch_range, => { const infix = datas[node]; - try renderExpression(gpa, ais, tree, infix.lhs, .none); - try renderToken(ais, tree, main_tokens[node], .none); - return renderExpression(gpa, ais, tree, infix.rhs, space); + try renderExpression(r, infix.lhs, .none); + try renderToken(r, main_tokens[node], .none); + return renderExpression(r, infix.rhs, space); }, .for_range => { const infix = datas[node]; - try renderExpression(gpa, ais, tree, infix.lhs, .none); + try renderExpression(r, infix.lhs, .none); if (infix.rhs != 0) { - try renderToken(ais, tree, main_tokens[node], .none); - return renderExpression(gpa, ais, tree, infix.rhs, space); + try renderToken(r, main_tokens[node], .none); + return renderExpression(r, infix.rhs, space); } else { - return renderToken(ais, tree, main_tokens[node], space); + return renderToken(r, main_tokens[node], space); } }, @@ -424,17 +491,17 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .@"orelse", => { const infix = datas[node]; - try renderExpression(gpa, ais, tree, infix.lhs, .space); + try renderExpression(r, infix.lhs, .space); const op_token = main_tokens[node]; if (tree.tokensOnSameLine(op_token, op_token + 1)) { - try renderToken(ais, tree, op_token, .space); + try renderToken(r, op_token, .space); } else { ais.pushIndent(); - try renderToken(ais, tree, op_token, .newline); + try renderToken(r, op_token, .newline); ais.popIndent(); } ais.pushIndentOneShot(); - return renderExpression(gpa, ais, tree, infix.rhs, space); + return renderExpression(r, infix.rhs, space); }, .assign_destructure => { @@ -445,7 +512,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, const maybe_comptime_token = tree.firstToken(node) - 1; if (token_tags[maybe_comptime_token] == .keyword_comptime) { - try renderToken(ais, tree, maybe_comptime_token, .space); + try renderToken(r, maybe_comptime_token, .space); } for (lhs_exprs, 0..) |lhs_node, i| { @@ -456,21 +523,21 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .simple_var_decl, .aligned_var_decl, => { - try renderVarDecl(gpa, ais, tree, tree.fullVarDecl(lhs_node).?, true, lhs_space); + try renderVarDecl(r, tree.fullVarDecl(lhs_node).?, true, lhs_space); }, - else => try renderExpression(gpa, ais, tree, lhs_node, lhs_space), + else => try renderExpression(r, lhs_node, lhs_space), } } const equal_token = main_tokens[node]; if (tree.tokensOnSameLine(equal_token, equal_token + 1)) { - try renderToken(ais, tree, equal_token, .space); + try renderToken(r, equal_token, .space); } else { ais.pushIndent(); - try renderToken(ais, tree, equal_token, .newline); + try renderToken(r, equal_token, .newline); ais.popIndent(); } ais.pushIndentOneShot(); - return renderExpression(gpa, ais, tree, rhs, space); + return renderExpression(r, rhs, space); }, .bit_not, @@ -480,27 +547,27 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .optional_type, .address_of, => { - try renderToken(ais, tree, main_tokens[node], .none); - return renderExpression(gpa, ais, tree, datas[node].lhs, space); + try renderToken(r, main_tokens[node], .none); + return renderExpression(r, datas[node].lhs, space); }, .@"try", .@"resume", .@"await", => { - try renderToken(ais, tree, main_tokens[node], .space); - return renderExpression(gpa, ais, tree, datas[node].lhs, space); + try renderToken(r, main_tokens[node], .space); + return renderExpression(r, datas[node].lhs, space); }, .array_type, .array_type_sentinel, - => return renderArrayType(gpa, ais, tree, tree.fullArrayType(node).?, space), + => return renderArrayType(r, tree.fullArrayType(node).?, space), .ptr_type_aligned, .ptr_type_sentinel, .ptr_type, .ptr_type_bit_range, - => return renderPtrType(gpa, ais, tree, tree.fullPtrType(node).?, space), + => return renderPtrType(r, tree.fullPtrType(node).?, space), .array_init_one, .array_init_one_comma, @@ -512,7 +579,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .array_init_comma, => { var elements: [2]Ast.Node.Index = undefined; - return renderArrayInit(gpa, ais, tree, tree.fullArrayInit(&elements, node).?, space); + return renderArrayInit(r, tree.fullArrayInit(&elements, node).?, space); }, .struct_init_one, @@ -525,7 +592,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .struct_init_comma, => { var buf: [2]Ast.Node.Index = undefined; - return renderStructInit(gpa, ais, tree, node, tree.fullStructInit(&buf, node).?, space); + return renderStructInit(r, node, tree.fullStructInit(&buf, node).?, space); }, .call_one, @@ -538,7 +605,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .async_call_comma, => { var buf: [1]Ast.Node.Index = undefined; - return renderCall(gpa, ais, tree, tree.fullCall(&buf, node).?, space); + return renderCall(r, tree.fullCall(&buf, node).?, space); }, .array_access => { @@ -547,25 +614,25 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, const rbracket = tree.lastToken(suffix.rhs) + 1; const one_line = tree.tokensOnSameLine(lbracket, rbracket); const inner_space = if (one_line) Space.none else Space.newline; - try renderExpression(gpa, ais, tree, suffix.lhs, .none); + try renderExpression(r, suffix.lhs, .none); ais.pushIndentNextLine(); - try renderToken(ais, tree, lbracket, inner_space); // [ - try renderExpression(gpa, ais, tree, suffix.rhs, inner_space); + try renderToken(r, lbracket, inner_space); // [ + try renderExpression(r, suffix.rhs, inner_space); ais.popIndent(); - return renderToken(ais, tree, rbracket, space); // ] + return renderToken(r, rbracket, space); // ] }, - .slice_open, .slice, .slice_sentinel => return renderSlice(gpa, ais, tree, node, tree.fullSlice(node).?, space), + .slice_open, .slice, .slice_sentinel => return renderSlice(r, node, tree.fullSlice(node).?, space), .deref => { - try renderExpression(gpa, ais, tree, datas[node].lhs, .none); - return renderToken(ais, tree, main_tokens[node], space); + try renderExpression(r, datas[node].lhs, .none); + return renderToken(r, main_tokens[node], space); }, .unwrap_optional => { - try renderExpression(gpa, ais, tree, datas[node].lhs, .none); - try renderToken(ais, tree, main_tokens[node], .none); - return renderToken(ais, tree, datas[node].rhs, space); + try renderExpression(r, datas[node].lhs, .none); + try renderToken(r, main_tokens[node], .none); + return renderToken(r, datas[node].rhs, space); }, .@"break" => { @@ -573,19 +640,19 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, const label_token = datas[node].lhs; const target = datas[node].rhs; if (label_token == 0 and target == 0) { - try renderToken(ais, tree, main_token, space); // break keyword + try renderToken(r, main_token, space); // break keyword } else if (label_token == 0 and target != 0) { - try renderToken(ais, tree, main_token, .space); // break keyword - try renderExpression(gpa, ais, tree, target, space); + try renderToken(r, main_token, .space); // break keyword + try renderExpression(r, target, space); } else if (label_token != 0 and target == 0) { - try renderToken(ais, tree, main_token, .space); // break keyword - try renderToken(ais, tree, label_token - 1, .none); // colon - try renderIdentifier(ais, tree, label_token, space, .eagerly_unquote); // identifier + try renderToken(r, main_token, .space); // break keyword + try renderToken(r, label_token - 1, .none); // colon + try renderIdentifier(r, label_token, space, .eagerly_unquote); // identifier } else if (label_token != 0 and target != 0) { - try renderToken(ais, tree, main_token, .space); // break keyword - try renderToken(ais, tree, label_token - 1, .none); // colon - try renderIdentifier(ais, tree, label_token, .space, .eagerly_unquote); // identifier - try renderExpression(gpa, ais, tree, target, space); + try renderToken(r, main_token, .space); // break keyword + try renderToken(r, label_token - 1, .none); // colon + try renderIdentifier(r, label_token, .space, .eagerly_unquote); // identifier + try renderExpression(r, target, space); } }, @@ -593,28 +660,28 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, const main_token = main_tokens[node]; const label = datas[node].lhs; if (label != 0) { - try renderToken(ais, tree, main_token, .space); // continue - try renderToken(ais, tree, label - 1, .none); // : - return renderIdentifier(ais, tree, label, space, .eagerly_unquote); // label + try renderToken(r, main_token, .space); // continue + try renderToken(r, label - 1, .none); // : + return renderIdentifier(r, label, space, .eagerly_unquote); // label } else { - return renderToken(ais, tree, main_token, space); // continue + return renderToken(r, main_token, space); // continue } }, .@"return" => { if (datas[node].lhs != 0) { - try renderToken(ais, tree, main_tokens[node], .space); - try renderExpression(gpa, ais, tree, datas[node].lhs, space); + try renderToken(r, main_tokens[node], .space); + try renderExpression(r, datas[node].lhs, space); } else { - try renderToken(ais, tree, main_tokens[node], space); + try renderToken(r, main_tokens[node], space); } }, .grouped_expression => { - try renderToken(ais, tree, main_tokens[node], .none); // lparen + try renderToken(r, main_tokens[node], .none); // lparen ais.pushIndentOneShot(); - try renderExpression(gpa, ais, tree, datas[node].lhs, .none); - return renderToken(ais, tree, datas[node].rhs, space); // rparen + try renderExpression(r, datas[node].lhs, .none); + return renderToken(r, datas[node].rhs, space); // rparen }, .container_decl, @@ -631,7 +698,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .tagged_union_two_trailing, => { var buf: [2]Ast.Node.Index = undefined; - return renderContainerDecl(gpa, ais, tree, node, tree.fullContainerDecl(&buf, node).?, space); + return renderContainerDecl(r, node, tree.fullContainerDecl(&buf, node).?, space); }, .error_set_decl => { @@ -639,62 +706,62 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, const lbrace = error_token + 1; const rbrace = datas[node].rhs; - try renderToken(ais, tree, error_token, .none); + try renderToken(r, error_token, .none); if (lbrace + 1 == rbrace) { // There is nothing between the braces so render condensed: `error{}` - try renderToken(ais, tree, lbrace, .none); - return renderToken(ais, tree, rbrace, space); + try renderToken(r, lbrace, .none); + return renderToken(r, rbrace, space); } else if (lbrace + 2 == rbrace and token_tags[lbrace + 1] == .identifier) { // There is exactly one member and no trailing comma or // comments, so render without surrounding spaces: `error{Foo}` - try renderToken(ais, tree, lbrace, .none); - try renderIdentifier(ais, tree, lbrace + 1, .none, .eagerly_unquote); // identifier - return renderToken(ais, tree, rbrace, space); + try renderToken(r, lbrace, .none); + try renderIdentifier(r, lbrace + 1, .none, .eagerly_unquote); // identifier + return renderToken(r, rbrace, space); } else if (token_tags[rbrace - 1] == .comma) { // There is a trailing comma so render each member on a new line. ais.pushIndentNextLine(); - try renderToken(ais, tree, lbrace, .newline); + try renderToken(r, lbrace, .newline); var i = lbrace + 1; while (i < rbrace) : (i += 1) { - if (i > lbrace + 1) try renderExtraNewlineToken(ais, tree, i); + if (i > lbrace + 1) try renderExtraNewlineToken(r, i); switch (token_tags[i]) { - .doc_comment => try renderToken(ais, tree, i, .newline), - .identifier => try renderIdentifier(ais, tree, i, .comma, .eagerly_unquote), + .doc_comment => try renderToken(r, i, .newline), + .identifier => try renderIdentifier(r, i, .comma, .eagerly_unquote), .comma => {}, else => unreachable, } } ais.popIndent(); - return renderToken(ais, tree, rbrace, space); + return renderToken(r, rbrace, space); } else { // There is no trailing comma so render everything on one line. - try renderToken(ais, tree, lbrace, .space); + try renderToken(r, lbrace, .space); var i = lbrace + 1; while (i < rbrace) : (i += 1) { switch (token_tags[i]) { .doc_comment => unreachable, // TODO - .identifier => try renderIdentifier(ais, tree, i, .comma_space, .eagerly_unquote), + .identifier => try renderIdentifier(r, i, .comma_space, .eagerly_unquote), .comma => {}, else => unreachable, } } - return renderToken(ais, tree, rbrace, space); + return renderToken(r, rbrace, space); } }, .builtin_call_two, .builtin_call_two_comma => { if (datas[node].lhs == 0) { - return renderBuiltinCall(gpa, ais, tree, main_tokens[node], &.{}, space); + return renderBuiltinCall(r, main_tokens[node], &.{}, space); } else if (datas[node].rhs == 0) { - return renderBuiltinCall(gpa, ais, tree, main_tokens[node], &.{datas[node].lhs}, space); + return renderBuiltinCall(r, main_tokens[node], &.{datas[node].lhs}, space); } else { - return renderBuiltinCall(gpa, ais, tree, main_tokens[node], &.{ datas[node].lhs, datas[node].rhs }, space); + return renderBuiltinCall(r, main_tokens[node], &.{ datas[node].lhs, datas[node].rhs }, space); } }, .builtin_call, .builtin_call_comma => { const params = tree.extra_data[datas[node].lhs..datas[node].rhs]; - return renderBuiltinCall(gpa, ais, tree, main_tokens[node], params, space); + return renderBuiltinCall(r, main_tokens[node], params, space); }, .fn_proto_simple, @@ -703,17 +770,17 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, .fn_proto, => { var buf: [1]Ast.Node.Index = undefined; - return renderFnProto(gpa, ais, tree, tree.fullFnProto(&buf, node).?, space); + return renderFnProto(r, tree.fullFnProto(&buf, node).?, space); }, .anyframe_type => { const main_token = main_tokens[node]; if (datas[node].rhs != 0) { - try renderToken(ais, tree, main_token, .none); // anyframe - try renderToken(ais, tree, main_token + 1, .none); // -> - return renderExpression(gpa, ais, tree, datas[node].rhs, space); + try renderToken(r, main_token, .none); // anyframe + try renderToken(r, main_token + 1, .none); // -> + return renderExpression(r, datas[node].rhs, space); } else { - return renderToken(ais, tree, main_token, space); // anyframe + return renderToken(r, main_token, space); // anyframe } }, @@ -726,48 +793,48 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, const cases = tree.extra_data[extra.start..extra.end]; const rparen = tree.lastToken(condition) + 1; - try renderToken(ais, tree, switch_token, .space); // switch keyword - try renderToken(ais, tree, switch_token + 1, .none); // lparen - try renderExpression(gpa, ais, tree, condition, .none); // condition expression - try renderToken(ais, tree, rparen, .space); // rparen + try renderToken(r, switch_token, .space); // switch keyword + try renderToken(r, switch_token + 1, .none); // lparen + try renderExpression(r, condition, .none); // condition expression + try renderToken(r, rparen, .space); // rparen ais.pushIndentNextLine(); if (cases.len == 0) { - try renderToken(ais, tree, rparen + 1, .none); // lbrace + try renderToken(r, rparen + 1, .none); // lbrace } else { - try renderToken(ais, tree, rparen + 1, .newline); // lbrace - try renderExpressions(gpa, ais, tree, cases, .comma); + try renderToken(r, rparen + 1, .newline); // lbrace + try renderExpressions(r, cases, .comma); } ais.popIndent(); - return renderToken(ais, tree, tree.lastToken(node), space); // rbrace + return renderToken(r, tree.lastToken(node), space); // rbrace }, .switch_case_one, .switch_case_inline_one, .switch_case, .switch_case_inline, - => return renderSwitchCase(gpa, ais, tree, tree.fullSwitchCase(node).?, space), + => return renderSwitchCase(r, tree.fullSwitchCase(node).?, space), .while_simple, .while_cont, .@"while", - => return renderWhile(gpa, ais, tree, tree.fullWhile(node).?, space), + => return renderWhile(r, tree.fullWhile(node).?, space), .for_simple, .@"for", - => return renderFor(gpa, ais, tree, tree.fullFor(node).?, space), + => return renderFor(r, tree.fullFor(node).?, space), .if_simple, .@"if", - => return renderIf(gpa, ais, tree, tree.fullIf(node).?, space), + => return renderIf(r, tree.fullIf(node).?, space), .asm_simple, .@"asm", - => return renderAsm(gpa, ais, tree, tree.fullAsm(node).?, space), + => return renderAsm(r, tree.fullAsm(node).?, space), .enum_literal => { - try renderToken(ais, tree, main_tokens[node] - 1, .none); // . - return renderIdentifier(ais, tree, main_tokens[node], space, .eagerly_unquote); // name + try renderToken(r, main_tokens[node] - 1, .none); // . + return renderIdentifier(r, main_tokens[node], space, .eagerly_unquote); // name }, .fn_decl => unreachable, @@ -787,34 +854,29 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, } fn renderArrayType( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, array_type: Ast.full.ArrayType, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const rbracket = tree.firstToken(array_type.ast.elem_type) - 1; const one_line = tree.tokensOnSameLine(array_type.ast.lbracket, rbracket); const inner_space = if (one_line) Space.none else Space.newline; ais.pushIndentNextLine(); - try renderToken(ais, tree, array_type.ast.lbracket, inner_space); // lbracket - try renderExpression(gpa, ais, tree, array_type.ast.elem_count, inner_space); + try renderToken(r, array_type.ast.lbracket, inner_space); // lbracket + try renderExpression(r, array_type.ast.elem_count, inner_space); if (array_type.ast.sentinel != 0) { - try renderToken(ais, tree, tree.firstToken(array_type.ast.sentinel) - 1, inner_space); // colon - try renderExpression(gpa, ais, tree, array_type.ast.sentinel, inner_space); + try renderToken(r, tree.firstToken(array_type.ast.sentinel) - 1, inner_space); // colon + try renderExpression(r, array_type.ast.sentinel, inner_space); } ais.popIndent(); - try renderToken(ais, tree, rbracket, .none); // rbracket - return renderExpression(gpa, ais, tree, array_type.ast.elem_type, space); + try renderToken(r, rbracket, .none); // rbracket + return renderExpression(r, array_type.ast.elem_type, space); } -fn renderPtrType( - gpa: Allocator, - ais: *Ais, - tree: Ast, - ptr_type: Ast.full.PtrType, - space: Space, -) Error!void { +fn renderPtrType(r: *Render, ptr_type: Ast.full.PtrType, space: Space) Error!void { + const tree = r.tree; switch (ptr_type.size) { .One => { // Since ** tokens exist and the same token is shared by two @@ -825,90 +887,89 @@ fn renderPtrType( if (tree.tokens.items(.tag)[ptr_type.ast.main_token] == .asterisk_asterisk and ptr_type.ast.main_token == tree.nodes.items(.main_token)[ptr_type.ast.child_type]) { - return renderExpression(gpa, ais, tree, ptr_type.ast.child_type, space); + return renderExpression(r, ptr_type.ast.child_type, space); } - try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk + try renderToken(r, ptr_type.ast.main_token, .none); // asterisk }, .Many => { if (ptr_type.ast.sentinel == 0) { - try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket - try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk - try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket + try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket + try renderToken(r, ptr_type.ast.main_token, .none); // asterisk + try renderToken(r, ptr_type.ast.main_token + 1, .none); // rbracket } else { - try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket - try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk - try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon - try renderExpression(gpa, ais, tree, ptr_type.ast.sentinel, .none); - try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket + try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket + try renderToken(r, ptr_type.ast.main_token, .none); // asterisk + try renderToken(r, ptr_type.ast.main_token + 1, .none); // colon + try renderExpression(r, ptr_type.ast.sentinel, .none); + try renderToken(r, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket } }, .C => { - try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket - try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk - try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // c - try renderToken(ais, tree, ptr_type.ast.main_token + 2, .none); // rbracket + try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket + try renderToken(r, ptr_type.ast.main_token, .none); // asterisk + try renderToken(r, ptr_type.ast.main_token + 1, .none); // c + try renderToken(r, ptr_type.ast.main_token + 2, .none); // rbracket }, .Slice => { if (ptr_type.ast.sentinel == 0) { - try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket - try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket + try renderToken(r, ptr_type.ast.main_token, .none); // lbracket + try renderToken(r, ptr_type.ast.main_token + 1, .none); // rbracket } else { - try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket - try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon - try renderExpression(gpa, ais, tree, ptr_type.ast.sentinel, .none); - try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket + try renderToken(r, ptr_type.ast.main_token, .none); // lbracket + try renderToken(r, ptr_type.ast.main_token + 1, .none); // colon + try renderExpression(r, ptr_type.ast.sentinel, .none); + try renderToken(r, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket } }, } if (ptr_type.allowzero_token) |allowzero_token| { - try renderToken(ais, tree, allowzero_token, .space); + try renderToken(r, allowzero_token, .space); } if (ptr_type.ast.align_node != 0) { const align_first = tree.firstToken(ptr_type.ast.align_node); - try renderToken(ais, tree, align_first - 2, .none); // align - try renderToken(ais, tree, align_first - 1, .none); // lparen - try renderExpression(gpa, ais, tree, ptr_type.ast.align_node, .none); + try renderToken(r, align_first - 2, .none); // align + try renderToken(r, align_first - 1, .none); // lparen + try renderExpression(r, ptr_type.ast.align_node, .none); if (ptr_type.ast.bit_range_start != 0) { assert(ptr_type.ast.bit_range_end != 0); - try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_start) - 1, .none); // colon - try renderExpression(gpa, ais, tree, ptr_type.ast.bit_range_start, .none); - try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_end) - 1, .none); // colon - try renderExpression(gpa, ais, tree, ptr_type.ast.bit_range_end, .none); - try renderToken(ais, tree, tree.lastToken(ptr_type.ast.bit_range_end) + 1, .space); // rparen + try renderToken(r, tree.firstToken(ptr_type.ast.bit_range_start) - 1, .none); // colon + try renderExpression(r, ptr_type.ast.bit_range_start, .none); + try renderToken(r, tree.firstToken(ptr_type.ast.bit_range_end) - 1, .none); // colon + try renderExpression(r, ptr_type.ast.bit_range_end, .none); + try renderToken(r, tree.lastToken(ptr_type.ast.bit_range_end) + 1, .space); // rparen } else { - try renderToken(ais, tree, tree.lastToken(ptr_type.ast.align_node) + 1, .space); // rparen + try renderToken(r, tree.lastToken(ptr_type.ast.align_node) + 1, .space); // rparen } } if (ptr_type.ast.addrspace_node != 0) { const addrspace_first = tree.firstToken(ptr_type.ast.addrspace_node); - try renderToken(ais, tree, addrspace_first - 2, .none); // addrspace - try renderToken(ais, tree, addrspace_first - 1, .none); // lparen - try renderExpression(gpa, ais, tree, ptr_type.ast.addrspace_node, .none); - try renderToken(ais, tree, tree.lastToken(ptr_type.ast.addrspace_node) + 1, .space); // rparen + try renderToken(r, addrspace_first - 2, .none); // addrspace + try renderToken(r, addrspace_first - 1, .none); // lparen + try renderExpression(r, ptr_type.ast.addrspace_node, .none); + try renderToken(r, tree.lastToken(ptr_type.ast.addrspace_node) + 1, .space); // rparen } if (ptr_type.const_token) |const_token| { - try renderToken(ais, tree, const_token, .space); + try renderToken(r, const_token, .space); } if (ptr_type.volatile_token) |volatile_token| { - try renderToken(ais, tree, volatile_token, .space); + try renderToken(r, volatile_token, .space); } - try renderExpression(gpa, ais, tree, ptr_type.ast.child_type, space); + try renderExpression(r, ptr_type.ast.child_type, space); } fn renderSlice( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, slice_node: Ast.Node.Index, slice: Ast.full.Slice, space: Space, ) Error!void { + const tree = r.tree; const node_tags = tree.nodes.items(.tag); const after_start_space_bool = nodeCausesSliceOpSpace(node_tags[slice.ast.start]) or if (slice.ast.end != 0) nodeCausesSliceOpSpace(node_tags[slice.ast.end]) else false; @@ -917,33 +978,32 @@ fn renderSlice( after_start_space else if (slice.ast.sentinel != 0) Space.space else Space.none; - try renderExpression(gpa, ais, tree, slice.ast.sliced, .none); - try renderToken(ais, tree, slice.ast.lbracket, .none); // lbracket + try renderExpression(r, slice.ast.sliced, .none); + try renderToken(r, slice.ast.lbracket, .none); // lbracket const start_last = tree.lastToken(slice.ast.start); - try renderExpression(gpa, ais, tree, slice.ast.start, after_start_space); - try renderToken(ais, tree, start_last + 1, after_dots_space); // ellipsis2 ("..") + try renderExpression(r, slice.ast.start, after_start_space); + try renderToken(r, start_last + 1, after_dots_space); // ellipsis2 ("..") if (slice.ast.end != 0) { const after_end_space = if (slice.ast.sentinel != 0) Space.space else Space.none; - try renderExpression(gpa, ais, tree, slice.ast.end, after_end_space); + try renderExpression(r, slice.ast.end, after_end_space); } if (slice.ast.sentinel != 0) { - try renderToken(ais, tree, tree.firstToken(slice.ast.sentinel) - 1, .none); // colon - try renderExpression(gpa, ais, tree, slice.ast.sentinel, .none); + try renderToken(r, tree.firstToken(slice.ast.sentinel) - 1, .none); // colon + try renderExpression(r, slice.ast.sentinel, .none); } - try renderToken(ais, tree, tree.lastToken(slice_node), space); // rbracket + try renderToken(r, tree.lastToken(slice_node), space); // rbracket } fn renderAsmOutput( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, asm_output: Ast.Node.Index, space: Space, ) Error!void { + const tree = r.tree; const token_tags = tree.tokens.items(.tag); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -951,77 +1011,95 @@ fn renderAsmOutput( assert(node_tags[asm_output] == .asm_output); const symbolic_name = main_tokens[asm_output]; - try renderToken(ais, tree, symbolic_name - 1, .none); // lbracket - try renderIdentifier(ais, tree, symbolic_name, .none, .eagerly_unquote); // ident - try renderToken(ais, tree, symbolic_name + 1, .space); // rbracket - try renderToken(ais, tree, symbolic_name + 2, .space); // "constraint" - try renderToken(ais, tree, symbolic_name + 3, .none); // lparen + try renderToken(r, symbolic_name - 1, .none); // lbracket + try renderIdentifier(r, symbolic_name, .none, .eagerly_unquote); // ident + try renderToken(r, symbolic_name + 1, .space); // rbracket + try renderToken(r, symbolic_name + 2, .space); // "constraint" + try renderToken(r, symbolic_name + 3, .none); // lparen if (token_tags[symbolic_name + 4] == .arrow) { - try renderToken(ais, tree, symbolic_name + 4, .space); // -> - try renderExpression(gpa, ais, tree, datas[asm_output].lhs, Space.none); - return renderToken(ais, tree, datas[asm_output].rhs, space); // rparen + try renderToken(r, symbolic_name + 4, .space); // -> + try renderExpression(r, datas[asm_output].lhs, Space.none); + return renderToken(r, datas[asm_output].rhs, space); // rparen } else { - try renderIdentifier(ais, tree, symbolic_name + 4, .none, .eagerly_unquote); // ident - return renderToken(ais, tree, symbolic_name + 5, space); // rparen + try renderIdentifier(r, symbolic_name + 4, .none, .eagerly_unquote); // ident + return renderToken(r, symbolic_name + 5, space); // rparen } } fn renderAsmInput( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, asm_input: Ast.Node.Index, space: Space, ) Error!void { + const tree = r.tree; const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); const datas = tree.nodes.items(.data); assert(node_tags[asm_input] == .asm_input); const symbolic_name = main_tokens[asm_input]; - try renderToken(ais, tree, symbolic_name - 1, .none); // lbracket - try renderIdentifier(ais, tree, symbolic_name, .none, .eagerly_unquote); // ident - try renderToken(ais, tree, symbolic_name + 1, .space); // rbracket - try renderToken(ais, tree, symbolic_name + 2, .space); // "constraint" - try renderToken(ais, tree, symbolic_name + 3, .none); // lparen - try renderExpression(gpa, ais, tree, datas[asm_input].lhs, Space.none); - return renderToken(ais, tree, datas[asm_input].rhs, space); // rparen + try renderToken(r, symbolic_name - 1, .none); // lbracket + try renderIdentifier(r, symbolic_name, .none, .eagerly_unquote); // ident + try renderToken(r, symbolic_name + 1, .space); // rbracket + try renderToken(r, symbolic_name + 2, .space); // "constraint" + try renderToken(r, symbolic_name + 3, .none); // lparen + try renderExpression(r, datas[asm_input].lhs, Space.none); + return renderToken(r, datas[asm_input].rhs, space); // rparen } fn renderVarDecl( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, + var_decl: Ast.full.VarDecl, + /// Destructures intentionally ignore leading `comptime` tokens. + ignore_comptime_token: bool, + /// `comma_space` and `space` are used for destructure LHS decls. + space: Space, +) Error!void { + try renderVarDeclWithoutFixups(r, var_decl, ignore_comptime_token, space); + if (r.fixups.unused_var_decls.contains(var_decl.ast.mut_token)) { + // Discard the variable like this: `_ = foo;` + const w = r.ais.writer(); + try w.writeAll("_ = "); + try w.writeAll(tokenSliceForRender(r.tree, var_decl.ast.mut_token + 1)); + try w.writeAll(";\n"); + } +} + +fn renderVarDeclWithoutFixups( + r: *Render, var_decl: Ast.full.VarDecl, /// Destructures intentionally ignore leading `comptime` tokens. ignore_comptime_token: bool, /// `comma_space` and `space` are used for destructure LHS decls. space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; + if (var_decl.visib_token) |visib_token| { - try renderToken(ais, tree, visib_token, Space.space); // pub + try renderToken(r, visib_token, Space.space); // pub } if (var_decl.extern_export_token) |extern_export_token| { - try renderToken(ais, tree, extern_export_token, Space.space); // extern + try renderToken(r, extern_export_token, Space.space); // extern if (var_decl.lib_name) |lib_name| { - try renderToken(ais, tree, lib_name, Space.space); // "lib" + try renderToken(r, lib_name, Space.space); // "lib" } } if (var_decl.threadlocal_token) |thread_local_token| { - try renderToken(ais, tree, thread_local_token, Space.space); // threadlocal + try renderToken(r, thread_local_token, Space.space); // threadlocal } if (!ignore_comptime_token) { if (var_decl.comptime_token) |comptime_token| { - try renderToken(ais, tree, comptime_token, Space.space); // comptime + try renderToken(r, comptime_token, Space.space); // comptime } } - try renderToken(ais, tree, var_decl.ast.mut_token, .space); // var + try renderToken(r, var_decl.ast.mut_token, .space); // var if (var_decl.ast.type_node != 0 or var_decl.ast.align_node != 0 or var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or @@ -1036,19 +1114,19 @@ fn renderVarDecl( else Space.none; - try renderIdentifier(ais, tree, var_decl.ast.mut_token + 1, name_space, .preserve_when_shadowing); // name + try renderIdentifier(r, var_decl.ast.mut_token + 1, name_space, .preserve_when_shadowing); // name } else { - return renderIdentifier(ais, tree, var_decl.ast.mut_token + 1, space, .preserve_when_shadowing); // name + return renderIdentifier(r, var_decl.ast.mut_token + 1, space, .preserve_when_shadowing); // name } if (var_decl.ast.type_node != 0) { - try renderToken(ais, tree, var_decl.ast.mut_token + 2, Space.space); // : + try renderToken(r, var_decl.ast.mut_token + 2, Space.space); // : if (var_decl.ast.align_node != 0 or var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0) { - try renderExpression(gpa, ais, tree, var_decl.ast.type_node, .space); + try renderExpression(r, var_decl.ast.type_node, .space); } else { - return renderExpression(gpa, ais, tree, var_decl.ast.type_node, space); + return renderExpression(r, var_decl.ast.type_node, space); } } @@ -1056,15 +1134,15 @@ fn renderVarDecl( const lparen = tree.firstToken(var_decl.ast.align_node) - 1; const align_kw = lparen - 1; const rparen = tree.lastToken(var_decl.ast.align_node) + 1; - try renderToken(ais, tree, align_kw, Space.none); // align - try renderToken(ais, tree, lparen, Space.none); // ( - try renderExpression(gpa, ais, tree, var_decl.ast.align_node, Space.none); + try renderToken(r, align_kw, Space.none); // align + try renderToken(r, lparen, Space.none); // ( + try renderExpression(r, var_decl.ast.align_node, Space.none); if (var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0) { - try renderToken(ais, tree, rparen, .space); // ) + try renderToken(r, rparen, .space); // ) } else { - return renderToken(ais, tree, rparen, space); // ) + return renderToken(r, rparen, space); // ) } } @@ -1072,14 +1150,14 @@ fn renderVarDecl( const lparen = tree.firstToken(var_decl.ast.addrspace_node) - 1; const addrspace_kw = lparen - 1; const rparen = tree.lastToken(var_decl.ast.addrspace_node) + 1; - try renderToken(ais, tree, addrspace_kw, Space.none); // addrspace - try renderToken(ais, tree, lparen, Space.none); // ( - try renderExpression(gpa, ais, tree, var_decl.ast.addrspace_node, Space.none); + try renderToken(r, addrspace_kw, Space.none); // addrspace + try renderToken(r, lparen, Space.none); // ( + try renderExpression(r, var_decl.ast.addrspace_node, Space.none); if (var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0) { - try renderToken(ais, tree, rparen, .space); // ) + try renderToken(r, rparen, .space); // ) } else { - try renderToken(ais, tree, rparen, .none); // ) - return renderToken(ais, tree, rparen + 1, Space.newline); // ; + try renderToken(r, rparen, .none); // ) + return renderToken(r, rparen + 1, Space.newline); // ; } } @@ -1087,13 +1165,13 @@ fn renderVarDecl( const lparen = tree.firstToken(var_decl.ast.section_node) - 1; const section_kw = lparen - 1; const rparen = tree.lastToken(var_decl.ast.section_node) + 1; - try renderToken(ais, tree, section_kw, Space.none); // linksection - try renderToken(ais, tree, lparen, Space.none); // ( - try renderExpression(gpa, ais, tree, var_decl.ast.section_node, Space.none); + try renderToken(r, section_kw, Space.none); // linksection + try renderToken(r, lparen, Space.none); // ( + try renderExpression(r, var_decl.ast.section_node, Space.none); if (var_decl.ast.init_node != 0) { - try renderToken(ais, tree, rparen, .space); // ) + try renderToken(r, rparen, .space); // ) } else { - return renderToken(ais, tree, rparen, space); // ) + return renderToken(r, rparen, space); // ) } } @@ -1103,15 +1181,15 @@ fn renderVarDecl( const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline; { ais.pushIndent(); - try renderToken(ais, tree, eq_token, eq_space); // = + try renderToken(r, eq_token, eq_space); // = ais.popIndent(); } ais.pushIndentOneShot(); - return renderExpression(gpa, ais, tree, var_decl.ast.init_node, space); // ; + return renderExpression(r, var_decl.ast.init_node, space); // ; } -fn renderIf(gpa: Allocator, ais: *Ais, tree: Ast, if_node: Ast.full.If, space: Space) Error!void { - return renderWhile(gpa, ais, tree, .{ +fn renderIf(r: *Render, if_node: Ast.full.If, space: Space) Error!void { + return renderWhile(r, .{ .ast = .{ .while_token = if_node.ast.if_token, .cond_expr = if_node.ast.cond_expr, @@ -1129,40 +1207,41 @@ fn renderIf(gpa: Allocator, ais: *Ais, tree: Ast, if_node: Ast.full.If, space: S /// Note that this function is additionally used to render if expressions, with /// respective values set to null. -fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While, space: Space) Error!void { +fn renderWhile(r: *Render, while_node: Ast.full.While, space: Space) Error!void { + const tree = r.tree; const token_tags = tree.tokens.items(.tag); if (while_node.label_token) |label| { - try renderIdentifier(ais, tree, label, .none, .eagerly_unquote); // label - try renderToken(ais, tree, label + 1, .space); // : + try renderIdentifier(r, label, .none, .eagerly_unquote); // label + try renderToken(r, label + 1, .space); // : } if (while_node.inline_token) |inline_token| { - try renderToken(ais, tree, inline_token, .space); // inline + try renderToken(r, inline_token, .space); // inline } - try renderToken(ais, tree, while_node.ast.while_token, .space); // if/for/while - try renderToken(ais, tree, while_node.ast.while_token + 1, .none); // lparen - try renderExpression(gpa, ais, tree, while_node.ast.cond_expr, .none); // condition + try renderToken(r, while_node.ast.while_token, .space); // if/for/while + try renderToken(r, while_node.ast.while_token + 1, .none); // lparen + try renderExpression(r, while_node.ast.cond_expr, .none); // condition var last_prefix_token = tree.lastToken(while_node.ast.cond_expr) + 1; // rparen if (while_node.payload_token) |payload_token| { - try renderToken(ais, tree, last_prefix_token, .space); - try renderToken(ais, tree, payload_token - 1, .none); // | + try renderToken(r, last_prefix_token, .space); + try renderToken(r, payload_token - 1, .none); // | const ident = blk: { if (token_tags[payload_token] == .asterisk) { - try renderToken(ais, tree, payload_token, .none); // * + try renderToken(r, payload_token, .none); // * break :blk payload_token + 1; } else { break :blk payload_token; } }; - try renderIdentifier(ais, tree, ident, .none, .preserve_when_shadowing); // identifier + try renderIdentifier(r, ident, .none, .preserve_when_shadowing); // identifier const pipe = blk: { if (token_tags[ident + 1] == .comma) { - try renderToken(ais, tree, ident + 1, .space); // , - try renderIdentifier(ais, tree, ident + 2, .none, .preserve_when_shadowing); // index + try renderToken(r, ident + 1, .space); // , + try renderIdentifier(r, ident + 2, .none, .preserve_when_shadowing); // index break :blk ident + 3; } else { break :blk ident + 1; @@ -1172,18 +1251,16 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While, } if (while_node.ast.cont_expr != 0) { - try renderToken(ais, tree, last_prefix_token, .space); + try renderToken(r, last_prefix_token, .space); const lparen = tree.firstToken(while_node.ast.cont_expr) - 1; - try renderToken(ais, tree, lparen - 1, .space); // : - try renderToken(ais, tree, lparen, .none); // lparen - try renderExpression(gpa, ais, tree, while_node.ast.cont_expr, .none); + try renderToken(r, lparen - 1, .space); // : + try renderToken(r, lparen, .none); // lparen + try renderExpression(r, while_node.ast.cont_expr, .none); last_prefix_token = tree.lastToken(while_node.ast.cont_expr) + 1; // rparen } try renderThenElse( - gpa, - ais, - tree, + r, last_prefix_token, while_node.ast.then_expr, while_node.else_token, @@ -1194,9 +1271,7 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While, } fn renderThenElse( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, last_prefix_token: Ast.TokenIndex, then_expr: Ast.Node.Index, else_token: Ast.TokenIndex, @@ -1204,33 +1279,35 @@ fn renderThenElse( else_expr: Ast.Node.Index, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const node_tags = tree.nodes.items(.tag); const then_expr_is_block = nodeIsBlock(node_tags[then_expr]); const indent_then_expr = !then_expr_is_block and !tree.tokensOnSameLine(last_prefix_token, tree.firstToken(then_expr)); if (indent_then_expr or (then_expr_is_block and ais.isLineOverIndented())) { ais.pushIndentNextLine(); - try renderToken(ais, tree, last_prefix_token, .newline); + try renderToken(r, last_prefix_token, .newline); ais.popIndent(); } else { - try renderToken(ais, tree, last_prefix_token, .space); + try renderToken(r, last_prefix_token, .space); } if (else_expr != 0) { if (indent_then_expr) { ais.pushIndent(); - try renderExpression(gpa, ais, tree, then_expr, .newline); + try renderExpression(r, then_expr, .newline); ais.popIndent(); } else { - try renderExpression(gpa, ais, tree, then_expr, .space); + try renderExpression(r, then_expr, .space); } var last_else_token = else_token; if (maybe_error_token) |error_token| { - try renderToken(ais, tree, else_token, .space); // else - try renderToken(ais, tree, error_token - 1, .none); // | - try renderIdentifier(ais, tree, error_token, .none, .preserve_when_shadowing); // identifier + try renderToken(r, else_token, .space); // else + try renderToken(r, error_token - 1, .none); // | + try renderIdentifier(r, error_token, .none, .preserve_when_shadowing); // identifier last_else_token = error_token + 1; // | } @@ -1239,53 +1316,55 @@ fn renderThenElse( !nodeIsIfForWhileSwitch(node_tags[else_expr]); if (indent_else_expr) { ais.pushIndentNextLine(); - try renderToken(ais, tree, last_else_token, .newline); + try renderToken(r, last_else_token, .newline); ais.popIndent(); - try renderExpressionIndented(gpa, ais, tree, else_expr, space); + try renderExpressionIndented(r, else_expr, space); } else { - try renderToken(ais, tree, last_else_token, .space); - try renderExpression(gpa, ais, tree, else_expr, space); + try renderToken(r, last_else_token, .space); + try renderExpression(r, else_expr, space); } } else { if (indent_then_expr) { - try renderExpressionIndented(gpa, ais, tree, then_expr, space); + try renderExpressionIndented(r, then_expr, space); } else { - try renderExpression(gpa, ais, tree, then_expr, space); + try renderExpression(r, then_expr, space); } } } -fn renderFor(gpa: Allocator, ais: *Ais, tree: Ast, for_node: Ast.full.For, space: Space) Error!void { +fn renderFor(r: *Render, for_node: Ast.full.For, space: Space) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); if (for_node.label_token) |label| { - try renderIdentifier(ais, tree, label, .none, .eagerly_unquote); // label - try renderToken(ais, tree, label + 1, .space); // : + try renderIdentifier(r, label, .none, .eagerly_unquote); // label + try renderToken(r, label + 1, .space); // : } if (for_node.inline_token) |inline_token| { - try renderToken(ais, tree, inline_token, .space); // inline + try renderToken(r, inline_token, .space); // inline } - try renderToken(ais, tree, for_node.ast.for_token, .space); // if/for/while + try renderToken(r, for_node.ast.for_token, .space); // if/for/while const lparen = for_node.ast.for_token + 1; - try renderParamList(gpa, ais, tree, lparen, for_node.ast.inputs, .space); + try renderParamList(r, lparen, for_node.ast.inputs, .space); var cur = for_node.payload_token; const pipe = std.mem.indexOfScalarPos(std.zig.Token.Tag, token_tags, cur, .pipe).?; if (token_tags[pipe - 1] == .comma) { ais.pushIndentNextLine(); - try renderToken(ais, tree, cur - 1, .newline); // | + try renderToken(r, cur - 1, .newline); // | while (true) { if (token_tags[cur] == .asterisk) { - try renderToken(ais, tree, cur, .none); // * + try renderToken(r, cur, .none); // * cur += 1; } - try renderIdentifier(ais, tree, cur, .none, .preserve_when_shadowing); // identifier + try renderIdentifier(r, cur, .none, .preserve_when_shadowing); // identifier cur += 1; if (token_tags[cur] == .comma) { - try renderToken(ais, tree, cur, .newline); // , + try renderToken(r, cur, .newline); // , cur += 1; } if (token_tags[cur] == .pipe) { @@ -1294,16 +1373,16 @@ fn renderFor(gpa: Allocator, ais: *Ais, tree: Ast, for_node: Ast.full.For, space } ais.popIndent(); } else { - try renderToken(ais, tree, cur - 1, .none); // | + try renderToken(r, cur - 1, .none); // | while (true) { if (token_tags[cur] == .asterisk) { - try renderToken(ais, tree, cur, .none); // * + try renderToken(r, cur, .none); // * cur += 1; } - try renderIdentifier(ais, tree, cur, .none, .preserve_when_shadowing); // identifier + try renderIdentifier(r, cur, .none, .preserve_when_shadowing); // identifier cur += 1; if (token_tags[cur] == .comma) { - try renderToken(ais, tree, cur, .space); // , + try renderToken(r, cur, .space); // , cur += 1; } if (token_tags[cur] == .pipe) { @@ -1313,9 +1392,7 @@ fn renderFor(gpa: Allocator, ais: *Ais, tree: Ast, for_node: Ast.full.For, space } try renderThenElse( - gpa, - ais, - tree, + r, cur, for_node.ast.then_expr, for_node.else_token, @@ -1326,13 +1403,13 @@ fn renderFor(gpa: Allocator, ais: *Ais, tree: Ast, for_node: Ast.full.For, space } fn renderContainerField( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, container: Container, field_param: Ast.full.ContainerField, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; var field = field_param; if (container != .tuple) field.convertToNonTupleLike(tree.nodes); const quote: QuoteBehavior = switch (container) { @@ -1341,102 +1418,102 @@ fn renderContainerField( }; if (field.comptime_token) |t| { - try renderToken(ais, tree, t, .space); // comptime + try renderToken(r, t, .space); // comptime } if (field.ast.type_expr == 0 and field.ast.value_expr == 0) { if (field.ast.align_expr != 0) { - try renderIdentifier(ais, tree, field.ast.main_token, .space, quote); // name + try renderIdentifier(r, field.ast.main_token, .space, quote); // name const lparen_token = tree.firstToken(field.ast.align_expr) - 1; const align_kw = lparen_token - 1; const rparen_token = tree.lastToken(field.ast.align_expr) + 1; - try renderToken(ais, tree, align_kw, .none); // align - try renderToken(ais, tree, lparen_token, .none); // ( - try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment - return renderToken(ais, tree, rparen_token, .space); // ) + try renderToken(r, align_kw, .none); // align + try renderToken(r, lparen_token, .none); // ( + try renderExpression(r, field.ast.align_expr, .none); // alignment + return renderToken(r, rparen_token, .space); // ) } - return renderIdentifierComma(ais, tree, field.ast.main_token, space, quote); // name + return renderIdentifierComma(r, field.ast.main_token, space, quote); // name } if (field.ast.type_expr != 0 and field.ast.value_expr == 0) { if (!field.ast.tuple_like) { - try renderIdentifier(ais, tree, field.ast.main_token, .none, quote); // name - try renderToken(ais, tree, field.ast.main_token + 1, .space); // : + try renderIdentifier(r, field.ast.main_token, .none, quote); // name + try renderToken(r, field.ast.main_token + 1, .space); // : } if (field.ast.align_expr != 0) { - try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type + try renderExpression(r, field.ast.type_expr, .space); // type const align_token = tree.firstToken(field.ast.align_expr) - 2; - try renderToken(ais, tree, align_token, .none); // align - try renderToken(ais, tree, align_token + 1, .none); // ( - try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment + try renderToken(r, align_token, .none); // align + try renderToken(r, align_token + 1, .none); // ( + try renderExpression(r, field.ast.align_expr, .none); // alignment const rparen = tree.lastToken(field.ast.align_expr) + 1; - return renderTokenComma(ais, tree, rparen, space); // ) + return renderTokenComma(r, rparen, space); // ) } else { - return renderExpressionComma(gpa, ais, tree, field.ast.type_expr, space); // type + return renderExpressionComma(r, field.ast.type_expr, space); // type } } if (field.ast.type_expr == 0 and field.ast.value_expr != 0) { - try renderIdentifier(ais, tree, field.ast.main_token, .space, quote); // name + try renderIdentifier(r, field.ast.main_token, .space, quote); // name if (field.ast.align_expr != 0) { const lparen_token = tree.firstToken(field.ast.align_expr) - 1; const align_kw = lparen_token - 1; const rparen_token = tree.lastToken(field.ast.align_expr) + 1; - try renderToken(ais, tree, align_kw, .none); // align - try renderToken(ais, tree, lparen_token, .none); // ( - try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment - try renderToken(ais, tree, rparen_token, .space); // ) + try renderToken(r, align_kw, .none); // align + try renderToken(r, lparen_token, .none); // ( + try renderExpression(r, field.ast.align_expr, .none); // alignment + try renderToken(r, rparen_token, .space); // ) } - try renderToken(ais, tree, field.ast.main_token + 1, .space); // = - return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value + try renderToken(r, field.ast.main_token + 1, .space); // = + return renderExpressionComma(r, field.ast.value_expr, space); // value } if (!field.ast.tuple_like) { - try renderIdentifier(ais, tree, field.ast.main_token, .none, quote); // name - try renderToken(ais, tree, field.ast.main_token + 1, .space); // : + try renderIdentifier(r, field.ast.main_token, .none, quote); // name + try renderToken(r, field.ast.main_token + 1, .space); // : } - try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type + try renderExpression(r, field.ast.type_expr, .space); // type if (field.ast.align_expr != 0) { const lparen_token = tree.firstToken(field.ast.align_expr) - 1; const align_kw = lparen_token - 1; const rparen_token = tree.lastToken(field.ast.align_expr) + 1; - try renderToken(ais, tree, align_kw, .none); // align - try renderToken(ais, tree, lparen_token, .none); // ( - try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment - try renderToken(ais, tree, rparen_token, .space); // ) + try renderToken(r, align_kw, .none); // align + try renderToken(r, lparen_token, .none); // ( + try renderExpression(r, field.ast.align_expr, .none); // alignment + try renderToken(r, rparen_token, .space); // ) } const eq_token = tree.firstToken(field.ast.value_expr) - 1; const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline; { ais.pushIndent(); - try renderToken(ais, tree, eq_token, eq_space); // = + try renderToken(r, eq_token, eq_space); // = ais.popIndent(); } if (eq_space == .space) - return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value + return renderExpressionComma(r, field.ast.value_expr, space); // value const token_tags = tree.tokens.items(.tag); const maybe_comma = tree.lastToken(field.ast.value_expr) + 1; if (token_tags[maybe_comma] == .comma) { ais.pushIndent(); - try renderExpression(gpa, ais, tree, field.ast.value_expr, .none); // value + try renderExpression(r, field.ast.value_expr, .none); // value ais.popIndent(); - try renderToken(ais, tree, maybe_comma, .newline); + try renderToken(r, maybe_comma, .newline); } else { ais.pushIndent(); - try renderExpression(gpa, ais, tree, field.ast.value_expr, space); // value + try renderExpression(r, field.ast.value_expr, space); // value ais.popIndent(); } } fn renderBuiltinCall( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, builtin_token: Ast.TokenIndex, params: []const Ast.Node.Index, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); // TODO remove before release of 0.12.0 @@ -1465,14 +1542,14 @@ fn renderBuiltinCall( if (token_tags[after_last_param_token] != .comma) { // Render all on one line, no trailing comma. try ais.writer().writeAll("@as"); - try renderToken(ais, tree, builtin_token + 1, .none); // ( - try renderExpression(gpa, ais, tree, params[0], .comma_space); + try renderToken(r, builtin_token + 1, .none); // ( + try renderExpression(r, params[0], .comma_space); } else { // Render one param per line. try ais.writer().writeAll("@as"); ais.pushIndent(); - try renderToken(ais, tree, builtin_token + 1, .newline); // ( - try renderExpression(gpa, ais, tree, params[0], .comma); + try renderToken(r, builtin_token + 1, .newline); // ( + try renderExpression(r, params[0], .comma); } } // Corresponding logic below builtin name rewrite below @@ -1507,29 +1584,29 @@ fn renderBuiltinCall( } else if (mem.eql(u8, slice, "@errSetCast")) { try ais.writer().writeAll("@errorCast"); } else { - try renderToken(ais, tree, builtin_token, .none); // @name + try renderToken(r, builtin_token, .none); // @name } if (rewrite_two_param_cast) { // Matches with corresponding logic above builtin name rewrite const after_last_param_token = tree.lastToken(params[1]) + 1; try ais.writer().writeAll("("); - try renderExpression(gpa, ais, tree, params[1], .none); + try renderExpression(r, params[1], .none); try ais.writer().writeAll(")"); if (token_tags[after_last_param_token] != .comma) { // Render all on one line, no trailing comma. - return renderToken(ais, tree, after_last_param_token, space); // ) + return renderToken(r, after_last_param_token, space); // ) } else { // Render one param per line. ais.popIndent(); - try renderToken(ais, tree, after_last_param_token, .newline); // , - return renderToken(ais, tree, after_last_param_token + 1, space); // ) + try renderToken(r, after_last_param_token, .newline); // , + return renderToken(r, after_last_param_token + 1, space); // ) } } if (params.len == 0) { - try renderToken(ais, tree, builtin_token + 1, .none); // ( - return renderToken(ais, tree, builtin_token + 2, space); // ) + try renderToken(r, builtin_token + 1, .none); // ( + return renderToken(r, builtin_token + 2, space); // ) } const last_param = params[params.len - 1]; @@ -1537,7 +1614,7 @@ fn renderBuiltinCall( if (token_tags[after_last_param_token] != .comma) { // Render all on one line, no trailing comma. - try renderToken(ais, tree, builtin_token + 1, .none); // ( + try renderToken(r, builtin_token + 1, .none); // ( for (params, 0..) |param_node, i| { const first_param_token = tree.firstToken(param_node); @@ -1546,39 +1623,41 @@ fn renderBuiltinCall( { ais.pushIndentOneShot(); } - try renderExpression(gpa, ais, tree, param_node, .none); + try renderExpression(r, param_node, .none); if (i + 1 < params.len) { const comma_token = tree.lastToken(param_node) + 1; - try renderToken(ais, tree, comma_token, .space); // , + try renderToken(r, comma_token, .space); // , } } - return renderToken(ais, tree, after_last_param_token, space); // ) + return renderToken(r, after_last_param_token, space); // ) } else { // Render one param per line. ais.pushIndent(); - try renderToken(ais, tree, builtin_token + 1, Space.newline); // ( + try renderToken(r, builtin_token + 1, Space.newline); // ( for (params) |param_node| { - try renderExpression(gpa, ais, tree, param_node, .comma); + try renderExpression(r, param_node, .comma); } ais.popIndent(); - return renderToken(ais, tree, after_last_param_token + 1, space); // ) + return renderToken(r, after_last_param_token + 1, space); // ) } } -fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProto, space: Space) Error!void { +fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); const token_starts = tree.tokens.items(.start); const after_fn_token = fn_proto.ast.fn_token + 1; const lparen = if (token_tags[after_fn_token] == .identifier) blk: { - try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn - try renderIdentifier(ais, tree, after_fn_token, .none, .preserve_when_shadowing); // name + try renderToken(r, fn_proto.ast.fn_token, .space); // fn + try renderIdentifier(r, after_fn_token, .none, .preserve_when_shadowing); // name break :blk after_fn_token + 1; } else blk: { - try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn + try renderToken(r, fn_proto.ast.fn_token, .space); // fn break :blk fn_proto.ast.fn_token + 1; }; assert(token_tags[lparen] == .l_paren); @@ -1630,7 +1709,7 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt const trailing_comma = token_tags[rparen - 1] == .comma; if (!trailing_comma and !hasComment(tree, lparen, rparen)) { // Render all on one line, no trailing comma. - try renderToken(ais, tree, lparen, .none); // ( + try renderToken(r, lparen, .none); // ( var param_i: usize = 0; var last_param_token = lparen; @@ -1638,25 +1717,25 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt last_param_token += 1; switch (token_tags[last_param_token]) { .doc_comment => { - try renderToken(ais, tree, last_param_token, .newline); + try renderToken(r, last_param_token, .newline); continue; }, .ellipsis3 => { - try renderToken(ais, tree, last_param_token, .none); // ... + try renderToken(r, last_param_token, .none); // ... break; }, .keyword_noalias, .keyword_comptime => { - try renderToken(ais, tree, last_param_token, .space); + try renderToken(r, last_param_token, .space); last_param_token += 1; }, .identifier => {}, .keyword_anytype => { - try renderToken(ais, tree, last_param_token, .none); // anytype + try renderToken(r, last_param_token, .none); // anytype continue; }, .r_paren => break, .comma => { - try renderToken(ais, tree, last_param_token, .space); // , + try renderToken(r, last_param_token, .space); // , continue; }, else => {}, // Parameter type without a name. @@ -1664,24 +1743,24 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt if (token_tags[last_param_token] == .identifier and token_tags[last_param_token + 1] == .colon) { - try renderIdentifier(ais, tree, last_param_token, .none, .preserve_when_shadowing); // name + try renderIdentifier(r, last_param_token, .none, .preserve_when_shadowing); // name last_param_token += 1; - try renderToken(ais, tree, last_param_token, .space); // : + try renderToken(r, last_param_token, .space); // : last_param_token += 1; } if (token_tags[last_param_token] == .keyword_anytype) { - try renderToken(ais, tree, last_param_token, .none); // anytype + try renderToken(r, last_param_token, .none); // anytype continue; } const param = fn_proto.ast.params[param_i]; param_i += 1; - try renderExpression(gpa, ais, tree, param, .none); + try renderExpression(r, param, .none); last_param_token = tree.lastToken(param); } } else { // One param per line. ais.pushIndent(); - try renderToken(ais, tree, lparen, .newline); // ( + try renderToken(r, lparen, .newline); // ( var param_i: usize = 0; var last_param_token = lparen; @@ -1689,20 +1768,20 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt last_param_token += 1; switch (token_tags[last_param_token]) { .doc_comment => { - try renderToken(ais, tree, last_param_token, .newline); + try renderToken(r, last_param_token, .newline); continue; }, .ellipsis3 => { - try renderToken(ais, tree, last_param_token, .comma); // ... + try renderToken(r, last_param_token, .comma); // ... break; }, .keyword_noalias, .keyword_comptime => { - try renderToken(ais, tree, last_param_token, .space); + try renderToken(r, last_param_token, .space); last_param_token += 1; }, .identifier => {}, .keyword_anytype => { - try renderToken(ais, tree, last_param_token, .comma); // anytype + try renderToken(r, last_param_token, .comma); // anytype if (token_tags[last_param_token + 1] == .comma) last_param_token += 1; continue; @@ -1713,56 +1792,56 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt if (token_tags[last_param_token] == .identifier and token_tags[last_param_token + 1] == .colon) { - try renderIdentifier(ais, tree, last_param_token, .none, .preserve_when_shadowing); // name + try renderIdentifier(r, last_param_token, .none, .preserve_when_shadowing); // name last_param_token += 1; - try renderToken(ais, tree, last_param_token, .space); // : + try renderToken(r, last_param_token, .space); // : last_param_token += 1; } if (token_tags[last_param_token] == .keyword_anytype) { - try renderToken(ais, tree, last_param_token, .comma); // anytype + try renderToken(r, last_param_token, .comma); // anytype if (token_tags[last_param_token + 1] == .comma) last_param_token += 1; continue; } const param = fn_proto.ast.params[param_i]; param_i += 1; - try renderExpression(gpa, ais, tree, param, .comma); + try renderExpression(r, param, .comma); last_param_token = tree.lastToken(param); if (token_tags[last_param_token + 1] == .comma) last_param_token += 1; } ais.popIndent(); } - try renderToken(ais, tree, rparen, .space); // ) + try renderToken(r, rparen, .space); // ) if (fn_proto.ast.align_expr != 0) { const align_lparen = tree.firstToken(fn_proto.ast.align_expr) - 1; const align_rparen = tree.lastToken(fn_proto.ast.align_expr) + 1; - try renderToken(ais, tree, align_lparen - 1, .none); // align - try renderToken(ais, tree, align_lparen, .none); // ( - try renderExpression(gpa, ais, tree, fn_proto.ast.align_expr, .none); - try renderToken(ais, tree, align_rparen, .space); // ) + try renderToken(r, align_lparen - 1, .none); // align + try renderToken(r, align_lparen, .none); // ( + try renderExpression(r, fn_proto.ast.align_expr, .none); + try renderToken(r, align_rparen, .space); // ) } if (fn_proto.ast.addrspace_expr != 0) { const align_lparen = tree.firstToken(fn_proto.ast.addrspace_expr) - 1; const align_rparen = tree.lastToken(fn_proto.ast.addrspace_expr) + 1; - try renderToken(ais, tree, align_lparen - 1, .none); // addrspace - try renderToken(ais, tree, align_lparen, .none); // ( - try renderExpression(gpa, ais, tree, fn_proto.ast.addrspace_expr, .none); - try renderToken(ais, tree, align_rparen, .space); // ) + try renderToken(r, align_lparen - 1, .none); // addrspace + try renderToken(r, align_lparen, .none); // ( + try renderExpression(r, fn_proto.ast.addrspace_expr, .none); + try renderToken(r, align_rparen, .space); // ) } if (fn_proto.ast.section_expr != 0) { const section_lparen = tree.firstToken(fn_proto.ast.section_expr) - 1; const section_rparen = tree.lastToken(fn_proto.ast.section_expr) + 1; - try renderToken(ais, tree, section_lparen - 1, .none); // section - try renderToken(ais, tree, section_lparen, .none); // ( - try renderExpression(gpa, ais, tree, fn_proto.ast.section_expr, .none); - try renderToken(ais, tree, section_rparen, .space); // ) + try renderToken(r, section_lparen - 1, .none); // section + try renderToken(r, section_lparen, .none); // ( + try renderExpression(r, fn_proto.ast.section_expr, .none); + try renderToken(r, section_rparen, .space); // ) } const is_callconv_inline = mem.eql(u8, "Inline", tree.tokenSlice(tree.nodes.items(.main_token)[fn_proto.ast.callconv_expr])); @@ -1771,25 +1850,24 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt const callconv_lparen = tree.firstToken(fn_proto.ast.callconv_expr) - 1; const callconv_rparen = tree.lastToken(fn_proto.ast.callconv_expr) + 1; - try renderToken(ais, tree, callconv_lparen - 1, .none); // callconv - try renderToken(ais, tree, callconv_lparen, .none); // ( - try renderExpression(gpa, ais, tree, fn_proto.ast.callconv_expr, .none); - try renderToken(ais, tree, callconv_rparen, .space); // ) + try renderToken(r, callconv_lparen - 1, .none); // callconv + try renderToken(r, callconv_lparen, .none); // ( + try renderExpression(r, fn_proto.ast.callconv_expr, .none); + try renderToken(r, callconv_rparen, .space); // ) } if (token_tags[maybe_bang] == .bang) { - try renderToken(ais, tree, maybe_bang, .none); // ! + try renderToken(r, maybe_bang, .none); // ! } - return renderExpression(gpa, ais, tree, fn_proto.ast.return_type, space); + return renderExpression(r, fn_proto.ast.return_type, space); } fn renderSwitchCase( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, switch_case: Ast.full.SwitchCase, space: Space, ) Error!void { + const tree = r.tree; const node_tags = tree.nodes.items(.tag); const token_tags = tree.tokens.items(.tag); const trailing_comma = token_tags[switch_case.ast.arrow_token - 1] == .comma; @@ -1800,22 +1878,22 @@ fn renderSwitchCase( // render inline keyword if (switch_case.inline_token) |some| { - try renderToken(ais, tree, some, .space); + try renderToken(r, some, .space); } // Render everything before the arrow if (switch_case.ast.values.len == 0) { - try renderToken(ais, tree, switch_case.ast.arrow_token - 1, .space); // else keyword + try renderToken(r, switch_case.ast.arrow_token - 1, .space); // else keyword } else if (switch_case.ast.values.len == 1 and !has_comment_before_arrow) { // render on one line and drop the trailing comma if any - try renderExpression(gpa, ais, tree, switch_case.ast.values[0], .space); + try renderExpression(r, switch_case.ast.values[0], .space); } else if (trailing_comma or has_comment_before_arrow) { // Render each value on a new line - try renderExpressions(gpa, ais, tree, switch_case.ast.values, .comma); + try renderExpressions(r, switch_case.ast.values, .comma); } else { // Render on one line for (switch_case.ast.values) |value_expr| { - try renderExpression(gpa, ais, tree, value_expr, .comma_space); + try renderExpression(r, value_expr, .comma_space); } } @@ -1826,35 +1904,35 @@ fn renderSwitchCase( else Space.space; const after_arrow_space: Space = if (switch_case.payload_token == null) pre_target_space else .space; - try renderToken(ais, tree, switch_case.ast.arrow_token, after_arrow_space); // => + try renderToken(r, switch_case.ast.arrow_token, after_arrow_space); // => if (switch_case.payload_token) |payload_token| { - try renderToken(ais, tree, payload_token - 1, .none); // pipe + try renderToken(r, payload_token - 1, .none); // pipe const ident = payload_token + @intFromBool(token_tags[payload_token] == .asterisk); if (token_tags[payload_token] == .asterisk) { - try renderToken(ais, tree, payload_token, .none); // asterisk + try renderToken(r, payload_token, .none); // asterisk } - try renderIdentifier(ais, tree, ident, .none, .preserve_when_shadowing); // identifier + try renderIdentifier(r, ident, .none, .preserve_when_shadowing); // identifier if (token_tags[ident + 1] == .comma) { - try renderToken(ais, tree, ident + 1, .space); // , - try renderIdentifier(ais, tree, ident + 2, .none, .preserve_when_shadowing); // identifier - try renderToken(ais, tree, ident + 3, pre_target_space); // pipe + try renderToken(r, ident + 1, .space); // , + try renderIdentifier(r, ident + 2, .none, .preserve_when_shadowing); // identifier + try renderToken(r, ident + 3, pre_target_space); // pipe } else { - try renderToken(ais, tree, ident + 1, pre_target_space); // pipe + try renderToken(r, ident + 1, pre_target_space); // pipe } } - try renderExpression(gpa, ais, tree, switch_case.ast.target_expr, space); + try renderExpression(r, switch_case.ast.target_expr, space); } fn renderBlock( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, block_node: Ast.Node.Index, statements: []const Ast.Node.Index, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); const node_tags = tree.nodes.items(.tag); const lbrace = tree.nodes.items(.main_token)[block_node]; @@ -1862,51 +1940,51 @@ fn renderBlock( if (token_tags[lbrace - 1] == .colon and token_tags[lbrace - 2] == .identifier) { - try renderIdentifier(ais, tree, lbrace - 2, .none, .eagerly_unquote); // identifier - try renderToken(ais, tree, lbrace - 1, .space); // : + try renderIdentifier(r, lbrace - 2, .none, .eagerly_unquote); // identifier + try renderToken(r, lbrace - 1, .space); // : } ais.pushIndentNextLine(); if (statements.len == 0) { - try renderToken(ais, tree, lbrace, .none); + try renderToken(r, lbrace, .none); } else { - try renderToken(ais, tree, lbrace, .newline); + try renderToken(r, lbrace, .newline); for (statements, 0..) |stmt, i| { - if (i != 0) try renderExtraNewline(ais, tree, stmt); + if (i != 0) try renderExtraNewline(r, stmt); switch (node_tags[stmt]) { .global_var_decl, .local_var_decl, .simple_var_decl, .aligned_var_decl, - => try renderVarDecl(gpa, ais, tree, tree.fullVarDecl(stmt).?, false, .semicolon), - else => try renderExpression(gpa, ais, tree, stmt, .semicolon), + => try renderVarDecl(r, tree.fullVarDecl(stmt).?, false, .semicolon), + else => try renderExpression(r, stmt, .semicolon), } } } ais.popIndent(); - try renderToken(ais, tree, tree.lastToken(block_node), space); // rbrace + try renderToken(r, tree.lastToken(block_node), space); // rbrace } fn renderStructInit( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, struct_node: Ast.Node.Index, struct_init: Ast.full.StructInit, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); if (struct_init.ast.type_expr == 0) { - try renderToken(ais, tree, struct_init.ast.lbrace - 1, .none); // . + try renderToken(r, struct_init.ast.lbrace - 1, .none); // . } else { - try renderExpression(gpa, ais, tree, struct_init.ast.type_expr, .none); // T + try renderExpression(r, struct_init.ast.type_expr, .none); // T } if (struct_init.ast.fields.len == 0) { ais.pushIndentNextLine(); - try renderToken(ais, tree, struct_init.ast.lbrace, .none); // lbrace + try renderToken(r, struct_init.ast.lbrace, .none); // lbrace ais.popIndent(); - return renderToken(ais, tree, struct_init.ast.lbrace + 1, space); // rbrace + return renderToken(r, struct_init.ast.lbrace + 1, space); // rbrace } const rbrace = tree.lastToken(struct_node); @@ -1914,65 +1992,66 @@ fn renderStructInit( if (trailing_comma or hasComment(tree, struct_init.ast.lbrace, rbrace)) { // Render one field init per line. ais.pushIndentNextLine(); - try renderToken(ais, tree, struct_init.ast.lbrace, .newline); + try renderToken(r, struct_init.ast.lbrace, .newline); - try renderToken(ais, tree, struct_init.ast.lbrace + 1, .none); // . - try renderIdentifier(ais, tree, struct_init.ast.lbrace + 2, .space, .eagerly_unquote); // name + try renderToken(r, struct_init.ast.lbrace + 1, .none); // . + try renderIdentifier(r, struct_init.ast.lbrace + 2, .space, .eagerly_unquote); // name // Don't output a space after the = if expression is a multiline string, // since then it will start on the next line. const nodes = tree.nodes.items(.tag); const expr = nodes[struct_init.ast.fields[0]]; var space_after_equal: Space = if (expr == .multiline_string_literal) .none else .space; - try renderToken(ais, tree, struct_init.ast.lbrace + 3, space_after_equal); // = - try renderExpression(gpa, ais, tree, struct_init.ast.fields[0], .comma); + try renderToken(r, struct_init.ast.lbrace + 3, space_after_equal); // = + try renderExpression(r, struct_init.ast.fields[0], .comma); for (struct_init.ast.fields[1..]) |field_init| { const init_token = tree.firstToken(field_init); - try renderExtraNewlineToken(ais, tree, init_token - 3); - try renderToken(ais, tree, init_token - 3, .none); // . - try renderIdentifier(ais, tree, init_token - 2, .space, .eagerly_unquote); // name + try renderExtraNewlineToken(r, init_token - 3); + try renderToken(r, init_token - 3, .none); // . + try renderIdentifier(r, init_token - 2, .space, .eagerly_unquote); // name space_after_equal = if (nodes[field_init] == .multiline_string_literal) .none else .space; - try renderToken(ais, tree, init_token - 1, space_after_equal); // = - try renderExpression(gpa, ais, tree, field_init, .comma); + try renderToken(r, init_token - 1, space_after_equal); // = + try renderExpression(r, field_init, .comma); } ais.popIndent(); } else { // Render all on one line, no trailing comma. - try renderToken(ais, tree, struct_init.ast.lbrace, .space); + try renderToken(r, struct_init.ast.lbrace, .space); for (struct_init.ast.fields) |field_init| { const init_token = tree.firstToken(field_init); - try renderToken(ais, tree, init_token - 3, .none); // . - try renderIdentifier(ais, tree, init_token - 2, .space, .eagerly_unquote); // name - try renderToken(ais, tree, init_token - 1, .space); // = - try renderExpression(gpa, ais, tree, field_init, .comma_space); + try renderToken(r, init_token - 3, .none); // . + try renderIdentifier(r, init_token - 2, .space, .eagerly_unquote); // name + try renderToken(r, init_token - 1, .space); // = + try renderExpression(r, field_init, .comma_space); } } - return renderToken(ais, tree, rbrace, space); + return renderToken(r, rbrace, space); } fn renderArrayInit( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, array_init: Ast.full.ArrayInit, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; + const gpa = r.gpa; const token_tags = tree.tokens.items(.tag); if (array_init.ast.type_expr == 0) { - try renderToken(ais, tree, array_init.ast.lbrace - 1, .none); // . + try renderToken(r, array_init.ast.lbrace - 1, .none); // . } else { - try renderExpression(gpa, ais, tree, array_init.ast.type_expr, .none); // T + try renderExpression(r, array_init.ast.type_expr, .none); // T } if (array_init.ast.elements.len == 0) { ais.pushIndentNextLine(); - try renderToken(ais, tree, array_init.ast.lbrace, .none); // lbrace + try renderToken(r, array_init.ast.lbrace, .none); // lbrace ais.popIndent(); - return renderToken(ais, tree, array_init.ast.lbrace + 1, space); // rbrace + return renderToken(r, array_init.ast.lbrace + 1, space); // rbrace } const last_elem = array_init.ast.elements[array_init.ast.elements.len - 1]; @@ -1987,9 +2066,9 @@ fn renderArrayInit( if (token_tags[first_token] != .multiline_string_literal_line and !anythingBetween(tree, last_elem_token, rbrace)) { - try renderToken(ais, tree, array_init.ast.lbrace, .none); - try renderExpression(gpa, ais, tree, only_elem, .none); - return renderToken(ais, tree, rbrace, space); + try renderToken(r, array_init.ast.lbrace, .none); + try renderExpression(r, only_elem, .none); + return renderToken(r, rbrace, space); } } @@ -2000,19 +2079,19 @@ fn renderArrayInit( // Render all on one line, no trailing comma. if (array_init.ast.elements.len == 1) { // If there is only one element, we don't use spaces - try renderToken(ais, tree, array_init.ast.lbrace, .none); - try renderExpression(gpa, ais, tree, array_init.ast.elements[0], .none); + try renderToken(r, array_init.ast.lbrace, .none); + try renderExpression(r, array_init.ast.elements[0], .none); } else { - try renderToken(ais, tree, array_init.ast.lbrace, .space); + try renderToken(r, array_init.ast.lbrace, .space); for (array_init.ast.elements) |elem| { - try renderExpression(gpa, ais, tree, elem, .comma_space); + try renderExpression(r, elem, .comma_space); } } - return renderToken(ais, tree, last_elem_token + 1, space); // rbrace + return renderToken(r, last_elem_token + 1, space); // rbrace } ais.pushIndentNextLine(); - try renderToken(ais, tree, array_init.ast.lbrace, .newline); + try renderToken(r, array_init.ast.lbrace, .newline); var expr_index: usize = 0; while (true) { @@ -2068,6 +2147,12 @@ fn renderArrayInit( .indent_delta = indent_delta, .underlying_writer = sub_expr_buffer.writer(), }; + var sub_render: Render = .{ + .gpa = r.gpa, + .ais = &auto_indenting_stream, + .tree = r.tree, + .fixups = r.fixups, + }; // Calculate size of columns in current section var column_counter: usize = 0; @@ -2078,7 +2163,7 @@ fn renderArrayInit( sub_expr_buffer_starts[i] = start; if (i + 1 < section_exprs.len) { - try renderExpression(gpa, &auto_indenting_stream, tree, expr, .none); + try renderExpression(&sub_render, expr, .none); const width = sub_expr_buffer.items.len - start; const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start..], '\n') != null; contains_newline = contains_newline or this_contains_newline; @@ -2098,7 +2183,7 @@ fn renderArrayInit( column_counter = 0; } } else { - try renderExpression(gpa, &auto_indenting_stream, tree, expr, .comma); + try renderExpression(&sub_render, expr, .comma); const width = sub_expr_buffer.items.len - start - 2; const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start .. sub_expr_buffer.items.len - 1], '\n') != null; contains_newline = contains_newline or this_contains_newline; @@ -2143,7 +2228,7 @@ fn renderArrayInit( if (column_counter != row_size - 1) { if (!expr_newlines[i] and !expr_newlines[i + 1]) { // Neither the current or next expression is multiline - try renderToken(ais, tree, comma, .space); // , + try renderToken(r, comma, .space); // , assert(column_widths[column_counter % row_size] >= expr_widths[i]); const padding = column_widths[column_counter % row_size] - expr_widths[i]; try ais.writer().writeByteNTimes(' ', padding); @@ -2154,13 +2239,13 @@ fn renderArrayInit( } if (single_line and row_size != 1) { - try renderToken(ais, tree, comma, .space); // , + try renderToken(r, comma, .space); // , continue; } column_counter = 0; - try renderToken(ais, tree, comma, .newline); // , - try renderExtraNewline(ais, tree, next_expr); + try renderToken(r, comma, .newline); // , + try renderExtraNewline(r, next_expr); } } @@ -2169,21 +2254,21 @@ fn renderArrayInit( } ais.popIndent(); - return renderToken(ais, tree, rbrace, space); // rbrace + return renderToken(r, rbrace, space); // rbrace } fn renderContainerDecl( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, container_decl_node: Ast.Node.Index, container_decl: Ast.full.ContainerDecl, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); if (container_decl.layout_token) |layout_token| { - try renderToken(ais, tree, layout_token, .space); + try renderToken(r, layout_token, .space); } const container: Container = switch (token_tags[container_decl.ast.main_token]) { @@ -2196,29 +2281,29 @@ fn renderContainerDecl( var lbrace: Ast.TokenIndex = undefined; if (container_decl.ast.enum_token) |enum_token| { - try renderToken(ais, tree, container_decl.ast.main_token, .none); // union - try renderToken(ais, tree, enum_token - 1, .none); // lparen - try renderToken(ais, tree, enum_token, .none); // enum + try renderToken(r, container_decl.ast.main_token, .none); // union + try renderToken(r, enum_token - 1, .none); // lparen + try renderToken(r, enum_token, .none); // enum if (container_decl.ast.arg != 0) { - try renderToken(ais, tree, enum_token + 1, .none); // lparen - try renderExpression(gpa, ais, tree, container_decl.ast.arg, .none); + try renderToken(r, enum_token + 1, .none); // lparen + try renderExpression(r, container_decl.ast.arg, .none); const rparen = tree.lastToken(container_decl.ast.arg) + 1; - try renderToken(ais, tree, rparen, .none); // rparen - try renderToken(ais, tree, rparen + 1, .space); // rparen + try renderToken(r, rparen, .none); // rparen + try renderToken(r, rparen + 1, .space); // rparen lbrace = rparen + 2; } else { - try renderToken(ais, tree, enum_token + 1, .space); // rparen + try renderToken(r, enum_token + 1, .space); // rparen lbrace = enum_token + 2; } } else if (container_decl.ast.arg != 0) { - try renderToken(ais, tree, container_decl.ast.main_token, .none); // union - try renderToken(ais, tree, container_decl.ast.main_token + 1, .none); // lparen - try renderExpression(gpa, ais, tree, container_decl.ast.arg, .none); + try renderToken(r, container_decl.ast.main_token, .none); // union + try renderToken(r, container_decl.ast.main_token + 1, .none); // lparen + try renderExpression(r, container_decl.ast.arg, .none); const rparen = tree.lastToken(container_decl.ast.arg) + 1; - try renderToken(ais, tree, rparen, .space); // rparen + try renderToken(r, rparen, .space); // rparen lbrace = rparen + 1; } else { - try renderToken(ais, tree, container_decl.ast.main_token, .space); // union + try renderToken(r, container_decl.ast.main_token, .space); // union lbrace = container_decl.ast.main_token + 1; } @@ -2226,13 +2311,13 @@ fn renderContainerDecl( if (container_decl.ast.members.len == 0) { ais.pushIndentNextLine(); if (token_tags[lbrace + 1] == .container_doc_comment) { - try renderToken(ais, tree, lbrace, .newline); // lbrace - try renderContainerDocComments(ais, tree, lbrace + 1); + try renderToken(r, lbrace, .newline); // lbrace + try renderContainerDocComments(r, lbrace + 1); } else { - try renderToken(ais, tree, lbrace, .none); // lbrace + try renderToken(r, lbrace, .none); // lbrace } ais.popIndent(); - return renderToken(ais, tree, rbrace, space); // rbrace + return renderToken(r, rbrace, space); // rbrace } const src_has_trailing_comma = token_tags[rbrace - 1] == .comma; @@ -2258,52 +2343,52 @@ fn renderContainerDecl( } // Print all the declarations on the same line. - try renderToken(ais, tree, lbrace, .space); // lbrace + try renderToken(r, lbrace, .space); // lbrace for (container_decl.ast.members) |member| { - try renderMember(gpa, ais, tree, container, member, .space); + try renderMember(r, container, member, .space); } - return renderToken(ais, tree, rbrace, space); // rbrace + return renderToken(r, rbrace, space); // rbrace } // One member per line. ais.pushIndentNextLine(); - try renderToken(ais, tree, lbrace, .newline); // lbrace + try renderToken(r, lbrace, .newline); // lbrace if (token_tags[lbrace + 1] == .container_doc_comment) { - try renderContainerDocComments(ais, tree, lbrace + 1); + try renderContainerDocComments(r, lbrace + 1); } for (container_decl.ast.members, 0..) |member, i| { - if (i != 0) try renderExtraNewline(ais, tree, member); + if (i != 0) try renderExtraNewline(r, member); switch (tree.nodes.items(.tag)[member]) { // For container fields, ensure a trailing comma is added if necessary. .container_field_init, .container_field_align, .container_field, - => try renderMember(gpa, ais, tree, container, member, .comma), + => try renderMember(r, container, member, .comma), - else => try renderMember(gpa, ais, tree, container, member, .newline), + else => try renderMember(r, container, member, .newline), } } ais.popIndent(); - return renderToken(ais, tree, rbrace, space); // rbrace + return renderToken(r, rbrace, space); // rbrace } fn renderAsm( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, asm_node: Ast.full.Asm, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); - try renderToken(ais, tree, asm_node.ast.asm_token, .space); // asm + try renderToken(r, asm_node.ast.asm_token, .space); // asm if (asm_node.volatile_token) |volatile_token| { - try renderToken(ais, tree, volatile_token, .space); // volatile - try renderToken(ais, tree, volatile_token + 1, .none); // lparen + try renderToken(r, volatile_token, .space); // volatile + try renderToken(r, volatile_token + 1, .none); // lparen } else { - try renderToken(ais, tree, asm_node.ast.asm_token + 1, .none); // lparen + try renderToken(r, asm_node.ast.asm_token + 1, .none); // lparen } if (asm_node.ast.items.len == 0) { @@ -2311,27 +2396,27 @@ fn renderAsm( if (asm_node.first_clobber) |first_clobber| { // asm ("foo" ::: "a", "b") // asm ("foo" ::: "a", "b",) - try renderExpression(gpa, ais, tree, asm_node.ast.template, .space); + try renderExpression(r, asm_node.ast.template, .space); // Render the three colons. - try renderToken(ais, tree, first_clobber - 3, .none); - try renderToken(ais, tree, first_clobber - 2, .none); - try renderToken(ais, tree, first_clobber - 1, .space); + try renderToken(r, first_clobber - 3, .none); + try renderToken(r, first_clobber - 2, .none); + try renderToken(r, first_clobber - 1, .space); var tok_i = first_clobber; while (true) : (tok_i += 1) { - try renderToken(ais, tree, tok_i, .none); + try renderToken(r, tok_i, .none); tok_i += 1; switch (token_tags[tok_i]) { .r_paren => { ais.popIndent(); - return renderToken(ais, tree, tok_i, space); + return renderToken(r, tok_i, space); }, .comma => { if (token_tags[tok_i + 1] == .r_paren) { ais.popIndent(); - return renderToken(ais, tree, tok_i + 1, space); + return renderToken(r, tok_i + 1, space); } else { - try renderToken(ais, tree, tok_i, .space); + try renderToken(r, tok_i, .space); } }, else => unreachable, @@ -2339,40 +2424,40 @@ fn renderAsm( } } else { // asm ("foo") - try renderExpression(gpa, ais, tree, asm_node.ast.template, .none); + try renderExpression(r, asm_node.ast.template, .none); ais.popIndent(); - return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen + return renderToken(r, asm_node.ast.rparen, space); // rparen } } ais.pushIndent(); - try renderExpression(gpa, ais, tree, asm_node.ast.template, .newline); + try renderExpression(r, asm_node.ast.template, .newline); ais.setIndentDelta(asm_indent_delta); const colon1 = tree.lastToken(asm_node.ast.template) + 1; const colon2 = if (asm_node.outputs.len == 0) colon2: { - try renderToken(ais, tree, colon1, .newline); // : + try renderToken(r, colon1, .newline); // : break :colon2 colon1 + 1; } else colon2: { - try renderToken(ais, tree, colon1, .space); // : + try renderToken(r, colon1, .space); // : ais.pushIndent(); for (asm_node.outputs, 0..) |asm_output, i| { if (i + 1 < asm_node.outputs.len) { const next_asm_output = asm_node.outputs[i + 1]; - try renderAsmOutput(gpa, ais, tree, asm_output, .none); + try renderAsmOutput(r, asm_output, .none); const comma = tree.firstToken(next_asm_output) - 1; - try renderToken(ais, tree, comma, .newline); // , - try renderExtraNewlineToken(ais, tree, tree.firstToken(next_asm_output)); + try renderToken(r, comma, .newline); // , + try renderExtraNewlineToken(r, tree.firstToken(next_asm_output)); } else if (asm_node.inputs.len == 0 and asm_node.first_clobber == null) { - try renderAsmOutput(gpa, ais, tree, asm_output, .comma); + try renderAsmOutput(r, asm_output, .comma); ais.popIndent(); ais.setIndentDelta(indent_delta); ais.popIndent(); - return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen + return renderToken(r, asm_node.ast.rparen, space); // rparen } else { - try renderAsmOutput(gpa, ais, tree, asm_output, .comma); + try renderAsmOutput(r, asm_output, .comma); const comma_or_colon = tree.lastToken(asm_output) + 1; ais.popIndent(); break :colon2 switch (token_tags[comma_or_colon]) { @@ -2384,27 +2469,27 @@ fn renderAsm( }; const colon3 = if (asm_node.inputs.len == 0) colon3: { - try renderToken(ais, tree, colon2, .newline); // : + try renderToken(r, colon2, .newline); // : break :colon3 colon2 + 1; } else colon3: { - try renderToken(ais, tree, colon2, .space); // : + try renderToken(r, colon2, .space); // : ais.pushIndent(); for (asm_node.inputs, 0..) |asm_input, i| { if (i + 1 < asm_node.inputs.len) { const next_asm_input = asm_node.inputs[i + 1]; - try renderAsmInput(gpa, ais, tree, asm_input, .none); + try renderAsmInput(r, asm_input, .none); const first_token = tree.firstToken(next_asm_input); - try renderToken(ais, tree, first_token - 1, .newline); // , - try renderExtraNewlineToken(ais, tree, first_token); + try renderToken(r, first_token - 1, .newline); // , + try renderExtraNewlineToken(r, first_token); } else if (asm_node.first_clobber == null) { - try renderAsmInput(gpa, ais, tree, asm_input, .comma); + try renderAsmInput(r, asm_input, .comma); ais.popIndent(); ais.setIndentDelta(indent_delta); ais.popIndent(); - return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen + return renderToken(r, asm_node.ast.rparen, space); // rparen } else { - try renderAsmInput(gpa, ais, tree, asm_input, .comma); + try renderAsmInput(r, asm_input, .comma); const comma_or_colon = tree.lastToken(asm_input) + 1; ais.popIndent(); break :colon3 switch (token_tags[comma_or_colon]) { @@ -2416,7 +2501,7 @@ fn renderAsm( unreachable; }; - try renderToken(ais, tree, colon3, .space); // : + try renderToken(r, colon3, .space); // : const first_clobber = asm_node.first_clobber.?; var tok_i = first_clobber; while (true) { @@ -2424,20 +2509,20 @@ fn renderAsm( .r_paren => { ais.setIndentDelta(indent_delta); ais.popIndent(); - try renderToken(ais, tree, tok_i, .newline); - return renderToken(ais, tree, tok_i + 1, space); + try renderToken(r, tok_i, .newline); + return renderToken(r, tok_i + 1, space); }, .comma => { switch (token_tags[tok_i + 2]) { .r_paren => { ais.setIndentDelta(indent_delta); ais.popIndent(); - try renderToken(ais, tree, tok_i, .newline); - return renderToken(ais, tree, tok_i + 2, space); + try renderToken(r, tok_i, .newline); + return renderToken(r, tok_i + 2, space); }, else => { - try renderToken(ais, tree, tok_i, .none); - try renderToken(ais, tree, tok_i + 1, .space); + try renderToken(r, tok_i, .none); + try renderToken(r, tok_i + 1, .space); tok_i += 2; }, } @@ -2448,44 +2533,42 @@ fn renderAsm( } fn renderCall( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, call: Ast.full.Call, space: Space, ) Error!void { if (call.async_token) |async_token| { - try renderToken(ais, tree, async_token, .space); + try renderToken(r, async_token, .space); } - try renderExpression(gpa, ais, tree, call.ast.fn_expr, .none); - try renderParamList(gpa, ais, tree, call.ast.lparen, call.ast.params, space); + try renderExpression(r, call.ast.fn_expr, .none); + try renderParamList(r, call.ast.lparen, call.ast.params, space); } fn renderParamList( - gpa: Allocator, - ais: *Ais, - tree: Ast, + r: *Render, lparen: Ast.TokenIndex, params: []const Ast.Node.Index, space: Space, ) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); if (params.len == 0) { ais.pushIndentNextLine(); - try renderToken(ais, tree, lparen, .none); + try renderToken(r, lparen, .none); ais.popIndent(); - return renderToken(ais, tree, lparen + 1, space); // ) + return renderToken(r, lparen + 1, space); // ) } const last_param = params[params.len - 1]; const after_last_param_tok = tree.lastToken(last_param) + 1; if (token_tags[after_last_param_tok] == .comma) { ais.pushIndentNextLine(); - try renderToken(ais, tree, lparen, .newline); // ( + try renderToken(r, lparen, .newline); // ( for (params, 0..) |param_node, i| { if (i + 1 < params.len) { - try renderExpression(gpa, ais, tree, param_node, .none); + try renderExpression(r, param_node, .none); // Unindent the comma for multiline string literals. const is_multiline_string = @@ -2493,20 +2576,20 @@ fn renderParamList( if (is_multiline_string) ais.popIndent(); const comma = tree.lastToken(param_node) + 1; - try renderToken(ais, tree, comma, .newline); // , + try renderToken(r, comma, .newline); // , if (is_multiline_string) ais.pushIndent(); - try renderExtraNewline(ais, tree, params[i + 1]); + try renderExtraNewline(r, params[i + 1]); } else { - try renderExpression(gpa, ais, tree, param_node, .comma); + try renderExpression(r, param_node, .comma); } } ais.popIndent(); - return renderToken(ais, tree, after_last_param_tok + 1, space); // ) + return renderToken(r, after_last_param_tok + 1, space); // ) } - try renderToken(ais, tree, lparen, .none); // ( + try renderToken(r, lparen, .none); // ( for (params, 0..) |param_node, i| { const first_param_token = tree.firstToken(param_node); @@ -2515,23 +2598,25 @@ fn renderParamList( { ais.pushIndentOneShot(); } - try renderExpression(gpa, ais, tree, param_node, .none); + try renderExpression(r, param_node, .none); if (i + 1 < params.len) { const comma = tree.lastToken(param_node) + 1; const next_multiline_string = token_tags[tree.firstToken(params[i + 1])] == .multiline_string_literal_line; const comma_space: Space = if (next_multiline_string) .none else .space; - try renderToken(ais, tree, comma, comma_space); + try renderToken(r, comma, comma_space); } } - return renderToken(ais, tree, after_last_param_tok, space); // ) + return renderToken(r, after_last_param_tok, space); // ) } /// Renders the given expression indented, popping the indent before rendering /// any following line comments -fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void { +fn renderExpressionIndented(r: *Render, node: Ast.Node.Index, space: Space) Error!void { + const tree = r.tree; + const ais = r.ais; const token_starts = tree.tokens.items(.start); const token_tags = tree.tokens.items(.tag); @@ -2545,24 +2630,24 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node .semicolon => token_tags[last_token + 1] == .semicolon, }; - try renderExpression(gpa, ais, tree, node, if (punctuation) .none else .skip); + try renderExpression(r, node, if (punctuation) .none else .skip); switch (space) { .none, .space, .newline, .skip => {}, .comma => { if (token_tags[last_token + 1] == .comma) { - try renderToken(ais, tree, last_token + 1, .skip); + try renderToken(r, last_token + 1, .skip); last_token += 1; } else { try ais.writer().writeByte(','); } }, .comma_space => if (token_tags[last_token + 1] == .comma) { - try renderToken(ais, tree, last_token + 1, .skip); + try renderToken(r, last_token + 1, .skip); last_token += 1; }, .semicolon => if (token_tags[last_token + 1] == .semicolon) { - try renderToken(ais, tree, last_token + 1, .skip); + try renderToken(r, last_token + 1, .skip); last_token += 1; }, } @@ -2572,7 +2657,7 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node if (space == .skip) return; const comment_start = token_starts[last_token] + tokenSliceForRender(tree, last_token).len; - const comment = try renderComments(ais, tree, comment_start, token_starts[last_token + 1]); + const comment = try renderComments(r, comment_start, token_starts[last_token + 1]); if (!comment) switch (space) { .none => {}, @@ -2589,40 +2674,43 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node /// Render an expression, and the comma that follows it, if it is present in the source. /// If a comma is present, and `space` is `Space.comma`, render only a single comma. -fn renderExpressionComma(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void { +fn renderExpressionComma(r: *Render, node: Ast.Node.Index, space: Space) Error!void { + const tree = r.tree; const token_tags = tree.tokens.items(.tag); const maybe_comma = tree.lastToken(node) + 1; if (token_tags[maybe_comma] == .comma and space != .comma) { - try renderExpression(gpa, ais, tree, node, .none); - return renderToken(ais, tree, maybe_comma, space); + try renderExpression(r, node, .none); + return renderToken(r, maybe_comma, space); } else { - return renderExpression(gpa, ais, tree, node, space); + return renderExpression(r, node, space); } } /// Render a token, and the comma that follows it, if it is present in the source. /// If a comma is present, and `space` is `Space.comma`, render only a single comma. -fn renderTokenComma(ais: *Ais, tree: Ast, token: Ast.TokenIndex, space: Space) Error!void { +fn renderTokenComma(r: *Render, token: Ast.TokenIndex, space: Space) Error!void { + const tree = r.tree; const token_tags = tree.tokens.items(.tag); const maybe_comma = token + 1; if (token_tags[maybe_comma] == .comma and space != .comma) { - try renderToken(ais, tree, token, .none); - return renderToken(ais, tree, maybe_comma, space); + try renderToken(r, token, .none); + return renderToken(r, maybe_comma, space); } else { - return renderToken(ais, tree, token, space); + return renderToken(r, token, space); } } /// Render an identifier, and the comma that follows it, if it is present in the source. /// If a comma is present, and `space` is `Space.comma`, render only a single comma. -fn renderIdentifierComma(ais: *Ais, tree: Ast, token: Ast.TokenIndex, space: Space, quote: QuoteBehavior) Error!void { +fn renderIdentifierComma(r: *Render, token: Ast.TokenIndex, space: Space, quote: QuoteBehavior) Error!void { + const tree = r.tree; const token_tags = tree.tokens.items(.tag); const maybe_comma = token + 1; if (token_tags[maybe_comma] == .comma and space != .comma) { - try renderIdentifier(ais, tree, token, .none, quote); - return renderToken(ais, tree, maybe_comma, space); + try renderIdentifier(r, token, .none, quote); + return renderToken(r, maybe_comma, space); } else { - return renderIdentifier(ais, tree, token, space, quote); + return renderIdentifier(r, token, space, quote); } } @@ -2647,13 +2735,17 @@ const Space = enum { skip, }; -fn renderToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Space) Error!void { +fn renderToken(r: *Render, token_index: Ast.TokenIndex, space: Space) Error!void { + const tree = r.tree; + const ais = r.ais; const lexeme = tokenSliceForRender(tree, token_index); try ais.writer().writeAll(lexeme); - try renderSpace(ais, tree, token_index, lexeme.len, space); + try renderSpace(r, token_index, lexeme.len, space); } -fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: usize, space: Space) Error!void { +fn renderSpace(r: *Render, token_index: Ast.TokenIndex, lexeme_len: usize, space: Space) Error!void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); const token_starts = tree.tokens.items(.start); @@ -2665,26 +2757,26 @@ fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: us try ais.writer().writeByte(','); } - const comment = try renderComments(ais, tree, token_start + lexeme_len, token_starts[token_index + 1]); + const comment = try renderComments(r, token_start + lexeme_len, token_starts[token_index + 1]); switch (space) { .none => {}, .space => if (!comment) try ais.writer().writeByte(' '), .newline => if (!comment) try ais.insertNewline(), .comma => if (token_tags[token_index + 1] == .comma) { - try renderToken(ais, tree, token_index + 1, .newline); + try renderToken(r, token_index + 1, .newline); } else if (!comment) { try ais.insertNewline(); }, .comma_space => if (token_tags[token_index + 1] == .comma) { - try renderToken(ais, tree, token_index + 1, .space); + try renderToken(r, token_index + 1, .space); } else if (!comment) { try ais.writer().writeByte(' '); }, .semicolon => if (token_tags[token_index + 1] == .semicolon) { - try renderToken(ais, tree, token_index + 1, .newline); + try renderToken(r, token_index + 1, .newline); } else if (!comment) { try ais.insertNewline(); }, @@ -2693,18 +2785,32 @@ fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: us } } +fn renderOnlySpace(r: *Render, space: Space) Error!void { + const ais = r.ais; + switch (space) { + .none => {}, + .space => try ais.writer().writeByte(' '), + .newline => try ais.insertNewline(), + .comma => try ais.writer().writeAll(",\n"), + .comma_space => try ais.writer().writeAll(", "), + .semicolon => try ais.writer().writeAll(";\n"), + .skip => unreachable, + } +} + const QuoteBehavior = enum { preserve_when_shadowing, eagerly_unquote, eagerly_unquote_except_underscore, }; -fn renderIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Space, quote: QuoteBehavior) Error!void { +fn renderIdentifier(r: *Render, token_index: Ast.TokenIndex, space: Space, quote: QuoteBehavior) Error!void { + const tree = r.tree; const token_tags = tree.tokens.items(.tag); assert(token_tags[token_index] == .identifier); const lexeme = tokenSliceForRender(tree, token_index); if (lexeme[0] != '@') { - return renderToken(ais, tree, token_index, space); + return renderToken(r, token_index, space); } assert(lexeme.len >= 3); @@ -2715,15 +2821,15 @@ fn renderIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Sp // Empty name can't be unquoted. if (contents.len == 0) { - return renderQuotedIdentifier(ais, tree, token_index, space, false); + return renderQuotedIdentifier(r, token_index, space, false); } // Special case for _ which would incorrectly be rejected by isValidId below. if (contents.len == 1 and contents[0] == '_') switch (quote) { - .eagerly_unquote => return renderQuotedIdentifier(ais, tree, token_index, space, true), + .eagerly_unquote => return renderQuotedIdentifier(r, token_index, space, true), .eagerly_unquote_except_underscore, .preserve_when_shadowing, - => return renderQuotedIdentifier(ais, tree, token_index, space, false), + => return renderQuotedIdentifier(r, token_index, space, false), }; // Scan the entire name for characters that would (after un-escaping) be illegal in a symbol, @@ -2731,23 +2837,23 @@ fn renderIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Sp var contents_i: usize = 0; while (contents_i < contents.len) { switch (contents[contents_i]) { - '0'...'9' => if (contents_i == 0) return renderQuotedIdentifier(ais, tree, token_index, space, false), + '0'...'9' => if (contents_i == 0) return renderQuotedIdentifier(r, token_index, space, false), 'A'...'Z', 'a'...'z', '_' => {}, '\\' => { var esc_offset = contents_i; const res = std.zig.string_literal.parseEscapeSequence(contents, &esc_offset); switch (res) { .success => |char| switch (char) { - '0'...'9' => if (contents_i == 0) return renderQuotedIdentifier(ais, tree, token_index, space, false), + '0'...'9' => if (contents_i == 0) return renderQuotedIdentifier(r, token_index, space, false), 'A'...'Z', 'a'...'z', '_' => {}, - else => return renderQuotedIdentifier(ais, tree, token_index, space, false), + else => return renderQuotedIdentifier(r, token_index, space, false), }, - .failure => return renderQuotedIdentifier(ais, tree, token_index, space, false), + .failure => return renderQuotedIdentifier(r, token_index, space, false), } contents_i += esc_offset; continue; }, - else => return renderQuotedIdentifier(ais, tree, token_index, space, false), + else => return renderQuotedIdentifier(r, token_index, space, false), } contents_i += 1; } @@ -2784,23 +2890,25 @@ fn renderIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Sp // We read the whole thing, so it could be a keyword or primitive. if (contents_i == contents.len) { if (!std.zig.isValidId(buf[0..buf_i])) { - return renderQuotedIdentifier(ais, tree, token_index, space, false); + return renderQuotedIdentifier(r, token_index, space, false); } if (primitives.isPrimitive(buf[0..buf_i])) switch (quote) { .eagerly_unquote, .eagerly_unquote_except_underscore, - => return renderQuotedIdentifier(ais, tree, token_index, space, true), - .preserve_when_shadowing => return renderQuotedIdentifier(ais, tree, token_index, space, false), + => return renderQuotedIdentifier(r, token_index, space, true), + .preserve_when_shadowing => return renderQuotedIdentifier(r, token_index, space, false), }; } - try renderQuotedIdentifier(ais, tree, token_index, space, true); + try renderQuotedIdentifier(r, token_index, space, true); } // Renders a @"" quoted identifier, normalizing escapes. // Unnecessary escapes are un-escaped, and \u escapes are normalized to \x when they fit. // If unquote is true, the @"" is removed and the result is a bare symbol whose validity is asserted. -fn renderQuotedIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Space, comptime unquote: bool) !void { +fn renderQuotedIdentifier(r: *Render, token_index: Ast.TokenIndex, space: Space, comptime unquote: bool) !void { + const tree = r.tree; + const ais = r.ais; const token_tags = tree.tokens.items(.tag); assert(token_tags[token_index] == .identifier); const lexeme = tokenSliceForRender(tree, token_index); @@ -2811,7 +2919,7 @@ fn renderQuotedIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, spa try renderIdentifierContents(ais.writer(), contents); if (!unquote) try ais.writer().writeByte('\"'); - try renderSpace(ais, tree, token_index, lexeme.len, space); + try renderSpace(r, token_index, lexeme.len, space); } fn renderIdentifierContents(writer: anytype, bytes: []const u8) !void { @@ -2884,7 +2992,10 @@ fn hasMultilineString(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.Tok /// Assumes that start is the first byte past the previous token and /// that end is the last byte before the next token. -fn renderComments(ais: *Ais, tree: Ast, start: usize, end: usize) Error!bool { +fn renderComments(r: *Render, start: usize, end: usize) Error!bool { + const tree = r.tree; + const ais = r.ais; + var index: usize = start; while (mem.indexOf(u8, tree.source[index..end], "//")) |offset| { const comment_start = index + offset; @@ -2944,12 +3055,14 @@ fn renderComments(ais: *Ais, tree: Ast, start: usize, end: usize) Error!bool { return index != start; } -fn renderExtraNewline(ais: *Ais, tree: Ast, node: Ast.Node.Index) Error!void { - return renderExtraNewlineToken(ais, tree, tree.firstToken(node)); +fn renderExtraNewline(r: *Render, node: Ast.Node.Index) Error!void { + return renderExtraNewlineToken(r, r.tree.firstToken(node)); } /// Check if there is an empty line immediately before the given token. If so, render it. -fn renderExtraNewlineToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex) Error!void { +fn renderExtraNewlineToken(r: *Render, token_index: Ast.TokenIndex) Error!void { + const tree = r.tree; + const ais = r.ais; const token_starts = tree.tokens.items(.start); const token_start = token_starts[token_index]; if (token_start == 0) return; @@ -2974,7 +3087,8 @@ fn renderExtraNewlineToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex) Er /// end_token is the token one past the last doc comment token. This function /// searches backwards from there. -fn renderDocComments(ais: *Ais, tree: Ast, end_token: Ast.TokenIndex) Error!void { +fn renderDocComments(r: *Render, end_token: Ast.TokenIndex) Error!void { + const tree = r.tree; // Search backwards for the first doc comment. const token_tags = tree.tokens.items(.tag); if (end_token == 0) return; @@ -2995,27 +3109,45 @@ fn renderDocComments(ais: *Ais, tree: Ast, end_token: Ast.TokenIndex) Error!void assert(prev_token_tag != .l_paren); if (prev_token_tag != .l_brace) { - try renderExtraNewlineToken(ais, tree, first_tok); + try renderExtraNewlineToken(r, first_tok); } } while (token_tags[tok] == .doc_comment) : (tok += 1) { - try renderToken(ais, tree, tok, .newline); + try renderToken(r, tok, .newline); } } /// start_token is first container doc comment token. -fn renderContainerDocComments(ais: *Ais, tree: Ast, start_token: Ast.TokenIndex) Error!void { +fn renderContainerDocComments(r: *Render, start_token: Ast.TokenIndex) Error!void { + const tree = r.tree; const token_tags = tree.tokens.items(.tag); var tok = start_token; while (token_tags[tok] == .container_doc_comment) : (tok += 1) { - try renderToken(ais, tree, tok, .newline); + try renderToken(r, tok, .newline); } // Render extra newline if there is one between final container doc comment and // the next token. If the next token is a doc comment, that code path // will have its own logic to insert a newline. if (token_tags[tok] != .doc_comment) { - try renderExtraNewlineToken(ais, tree, tok); + try renderExtraNewlineToken(r, tok); + } +} + +fn discardAllParams(r: *Render, fn_proto_node: Ast.Node.Index) Error!void { + const tree = &r.tree; + const ais = r.ais; + var buf: [1]Ast.Node.Index = undefined; + const fn_proto = tree.fullFnProto(&buf, fn_proto_node).?; + const token_tags = tree.tokens.items(.tag); + var it = fn_proto.iterate(tree); + while (it.next()) |param| { + const name_ident = param.name_token.?; + assert(token_tags[name_ident] == .identifier); + const w = ais.writer(); + try w.writeAll("_ = "); + try w.writeAll(tokenSliceForRender(r.tree, name_ident)); + try w.writeAll(";\n"); } } diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 59dcf29e16..72f65afb3a 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -1,5 +1,4 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); pub const Token = struct { tag: Tag, @@ -1450,8 +1449,6 @@ test "chars" { } test "invalid token characters" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testTokenize("#", &.{.invalid}); try testTokenize("`", &.{.invalid}); try testTokenize("'c", &.{.invalid}); @@ -1571,8 +1568,6 @@ test "pipe and then invalid" { } test "line comment and doc comment" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testTokenize("//", &.{}); try testTokenize("// a / b", &.{}); try testTokenize("// /", &.{}); @@ -1647,8 +1642,6 @@ test "range literals" { } test "number literals decimal" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testTokenize("0", &.{.number_literal}); try testTokenize("1", &.{.number_literal}); try testTokenize("2", &.{.number_literal}); @@ -1897,8 +1890,6 @@ test "invalid token with unfinished escape right before eof" { } test "saturating operators" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try testTokenize("<<", &.{.angle_bracket_angle_bracket_left}); try testTokenize("<<|", &.{.angle_bracket_angle_bracket_left_pipe}); try testTokenize("<<|=", &.{.angle_bracket_angle_bracket_left_pipe_equal}); |
