authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-01 17:23:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-01 17:23:49-07:00
log20554d32c0a9e8adeb311645797e0d6873f4bbc0
tree1080a2c4700156e8b1283ddbadad64e1f4520063
parentbf8fafc37d4182196d108c773ae36c33a109d703

zig fmt: start reworking with new memory layout

* start implementation of ast.Tree.firstToken and lastToken * clarify some ast.Node doc comments * reimplement renderToken

5 files changed, 6134 insertions(+), 6093 deletions(-)

lib/std/zig/ast.zig+285-15
......@@ -185,24 +185,293 @@ pub const Tree = struct {
185185 }
186186 }
187187
188 /// Skips over comments.
189 pub fn prevToken(self: *const Tree, token_index: TokenIndex) TokenIndex {
190 const token_tags = self.tokens.items(.tag);
191 var index = token_index - 1;
192 while (token_tags[index] == .LineComment) {
193 index -= 1;
188 pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {
189 const tags = tree.nodes.items(.tag);
190 const datas = tree.nodes.items(.data);
191 const main_tokens = tree.nodes.items(.main_token);
192 switch (tags[node]) {
193 .Root => return 0,
194
195 .UsingNamespace,
196 .TestDecl,
197 .ErrDefer,
198 .Defer,
199 .BoolNot,
200 .Negation,
201 .BitNot,
202 .NegationWrap,
203 .AddressOf,
204 .Try,
205 .Await,
206 .OptionalType,
207 .ArrayInitDotTwo,
208 .ArrayInitDot,
209 .StructInitDotTwo,
210 .StructInitDot,
211 .Switch,
212 .IfSimple,
213 .IfSimpleOptional,
214 .If,
215 .IfOptional,
216 .IfError,
217 .Suspend,
218 .Resume,
219 .Continue,
220 .Break,
221 .Return,
222 .AnyFrameType,
223 .OneToken,
224 .Identifier,
225 .EnumLiteral,
226 .MultilineStringLiteral,
227 .GroupedExpression,
228 .BuiltinCallTwo,
229 .BuiltinCall,
230 .ErrorSetDecl,
231 .AnyType,
232 .Comptime,
233 .Nosuspend,
234 .Block,
235 .AsmSimple,
236 .Asm,
237 => return main_tokens[node],
238
239 .Catch,
240 .FieldAccess,
241 .UnwrapOptional,
242 .EqualEqual,
243 .BangEqual,
244 .LessThan,
245 .GreaterThan,
246 .LessOrEqual,
247 .GreaterOrEqual,
248 .AssignMul,
249 .AssignDiv,
250 .AssignMod,
251 .AssignAdd,
252 .AssignSub,
253 .AssignBitShiftLeft,
254 .AssignBitShiftRight,
255 .AssignBitAnd,
256 .AssignBitXor,
257 .AssignBitOr,
258 .AssignMulWrap,
259 .AssignAddWrap,
260 .AssignSubWrap,
261 .Assign,
262 .MergeErrorSets,
263 .Mul,
264 .Div,
265 .Mod,
266 .ArrayMult,
267 .MulWrap,
268 .Add,
269 .Sub,
270 .ArrayCat,
271 .AddWrap,
272 .SubWrap,
273 .BitShiftLeft,
274 .BitShiftRight,
275 .BitAnd,
276 .BitXor,
277 .BitOr,
278 .OrElse,
279 .BoolAnd,
280 .BoolOr,
281 .SliceOpen,
282 .Slice,
283 .Deref,
284 .ArrayAccess,
285 .ArrayInitOne,
286 .ArrayInit,
287 .StructInitOne,
288 .CallOne,
289 .Call,
290 .SwitchCaseOne,
291 .SwitchRange,
292 .FnDecl,
293 => return tree.firstToken(datas[node].lhs),
294
295 .GlobalVarDecl,
296 .LocalVarDecl,
297 .SimpleVarDecl,
298 .AlignedVarDecl,
299 .ArrayType,
300 .ArrayTypeSentinel,
301 .PtrTypeAligned,
302 .PtrTypeSentinel,
303 .PtrType,
304 .SliceType,
305 .StructInit,
306 .SwitchCaseMulti,
307 .WhileSimple,
308 .WhileSimpleOptional,
309 .WhileCont,
310 .WhileContOptional,
311 .While,
312 .WhileOptional,
313 .WhileError,
314 .ForSimple,
315 .For,
316 .FnProtoSimple,
317 .FnProtoSimpleMulti,
318 .FnProtoOne,
319 .FnProto,
320 .ContainerDecl,
321 .ContainerDeclArg,
322 .TaggedUnion,
323 .TaggedUnionEnumTag,
324 .ContainerFieldInit,
325 .ContainerFieldAlign,
326 .ContainerField,
327 .AsmOutput,
328 .AsmInput,
329 .ErrorValue,
330 .ErrorUnion,
331 => @panic("TODO finish implementing firstToken"),
194332 }
195 return index;
196333 }
197334
198 /// Skips over comments.
199 pub fn nextToken(self: *const Tree, token_index: TokenIndex) TokenIndex {
200 const token_tags = self.tokens.items(.tag);
201 var index = token_index + 1;
202 while (token_tags[index] == .LineComment) {
203 index += 1;
335 pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
336 const tags = tree.nodes.items(.tag);
337 const datas = tree.nodes.items(.data);
338 const main_tokens = tree.nodes.items(.main_token);
339 switch (tags[node]) {
340 .Root,
341 .UsingNamespace,
342 .TestDecl,
343 .ErrDefer,
344 .Defer,
345 .BoolNot,
346 .Negation,
347 .BitNot,
348 .NegationWrap,
349 .AddressOf,
350 .Try,
351 .Await,
352 .OptionalType,
353 .ArrayInitDotTwo,
354 .ArrayInitDot,
355 .StructInitDotTwo,
356 .StructInitDot,
357 .Switch,
358 .IfSimple,
359 .IfSimpleOptional,
360 .If,
361 .IfOptional,
362 .IfError,
363 .Suspend,
364 .Resume,
365 .Continue,
366 .Break,
367 .Return,
368 .AnyFrameType,
369 .OneToken,
370 .Identifier,
371 .EnumLiteral,
372 .MultilineStringLiteral,
373 .GroupedExpression,
374 .BuiltinCallTwo,
375 .BuiltinCall,
376 .ErrorSetDecl,
377 .AnyType,
378 .Comptime,
379 .Nosuspend,
380 .Block,
381 .AsmSimple,
382 .Asm,
383 .Catch,
384 .FieldAccess,
385 .UnwrapOptional,
386 .EqualEqual,
387 .BangEqual,
388 .LessThan,
389 .GreaterThan,
390 .LessOrEqual,
391 .GreaterOrEqual,
392 .AssignMul,
393 .AssignDiv,
394 .AssignMod,
395 .AssignAdd,
396 .AssignSub,
397 .AssignBitShiftLeft,
398 .AssignBitShiftRight,
399 .AssignBitAnd,
400 .AssignBitXor,
401 .AssignBitOr,
402 .AssignMulWrap,
403 .AssignAddWrap,
404 .AssignSubWrap,
405 .Assign,
406 .MergeErrorSets,
407 .Mul,
408 .Div,
409 .Mod,
410 .ArrayMult,
411 .MulWrap,
412 .Add,
413 .Sub,
414 .ArrayCat,
415 .AddWrap,
416 .SubWrap,
417 .BitShiftLeft,
418 .BitShiftRight,
419 .BitAnd,
420 .BitXor,
421 .BitOr,
422 .OrElse,
423 .BoolAnd,
424 .BoolOr,
425 .SliceOpen,
426 .Slice,
427 .Deref,
428 .ArrayAccess,
429 .ArrayInitOne,
430 .ArrayInit,
431 .StructInitOne,
432 .CallOne,
433 .Call,
434 .SwitchCaseOne,
435 .SwitchRange,
436 .FnDecl,
437 .GlobalVarDecl,
438 .LocalVarDecl,
439 .SimpleVarDecl,
440 .AlignedVarDecl,
441 .ArrayType,
442 .ArrayTypeSentinel,
443 .PtrTypeAligned,
444 .PtrTypeSentinel,
445 .PtrType,
446 .SliceType,
447 .StructInit,
448 .SwitchCaseMulti,
449 .WhileSimple,
450 .WhileSimpleOptional,
451 .WhileCont,
452 .WhileContOptional,
453 .While,
454 .WhileOptional,
455 .WhileError,
456 .ForSimple,
457 .For,
458 .FnProtoSimple,
459 .FnProtoSimpleMulti,
460 .FnProtoOne,
461 .FnProto,
462 .ContainerDecl,
463 .ContainerDeclArg,
464 .TaggedUnion,
465 .TaggedUnionEnumTag,
466 .ContainerFieldInit,
467 .ContainerFieldAlign,
468 .ContainerField,
469 .AsmOutput,
470 .AsmInput,
471 .ErrorValue,
472 .ErrorUnion,
473 => @panic("TODO finish implementing lastToken"),
204474 }
205 return index;
206475 }
207476};
208477
......@@ -454,7 +723,7 @@ pub const Node = struct {
454723 /// lhs is test name token (must be string literal), if any.
455724 /// rhs is the body node.
456725 TestDecl,
457 /// lhs is the index into global_var_decl_list.
726 /// lhs is the index into extra_data.
458727 /// rhs is the initialization expression, if any.
459728 GlobalVarDecl,
460729 /// `var a: x align(y) = rhs`
......@@ -732,6 +1001,7 @@ pub const Node = struct {
7321001 /// `nosuspend lhs`. rhs unused.
7331002 Nosuspend,
7341003 /// `{}`. `sub_list[lhs..rhs]`.
1004 /// main_token points at the `{`.
7351005 Block,
7361006 /// `asm(lhs)`. rhs unused.
7371007 AsmSimple,
lib/std/zig/parse.zig+1-1
......@@ -594,7 +594,7 @@ const Parser = struct {
594594 p.eatToken(.Keyword_var) orelse
595595 return null_node;
596596
597 const name_token = try p.expectToken(.Identifier);
597 _ = try p.expectToken(.Identifier);
598598 const type_node: Node.Index = if (p.eatToken(.Colon) == null) 0 else try p.expectTypeExpr();
599599 const align_node = try p.parseByteAlign();
600600 const section_node = try p.parseLinkSection();
lib/std/zig/parser_test.zig+3702-3723
......@@ -3,3727 +3,3704 @@
33// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
6test "zig fmt: convert var to anytype" {
7 // TODO remove in next release cycle
8 try testTransform(
9 \\pub fn main(
10 \\ a: var,
11 \\ bar: var,
12 \\) void {}
13 ,
14 \\pub fn main(
15 \\ a: anytype,
16 \\ bar: anytype,
17 \\) void {}
18 \\
19 );
20}
21
22test "zig fmt: noasync to nosuspend" {
23 // TODO: remove this
24 try testTransform(
25 \\pub fn main() void {
26 \\ noasync call();
27 \\}
28 ,
29 \\pub fn main() void {
30 \\ nosuspend call();
31 \\}
32 \\
33 );
34}
35
36test "recovery: top level" {
37 try testError(
38 \\test "" {inline}
39 \\test "" {inline}
40 , &[_]Error{
41 .ExpectedInlinable,
42 .ExpectedInlinable,
43 });
44}
45
46test "recovery: block statements" {
47 try testError(
48 \\test "" {
49 \\ foo + +;
50 \\ inline;
51 \\}
52 , &[_]Error{
53 .InvalidToken,
54 .ExpectedInlinable,
55 });
56}
57
58test "recovery: missing comma" {
59 try testError(
60 \\test "" {
61 \\ switch (foo) {
62 \\ 2 => {}
63 \\ 3 => {}
64 \\ else => {
65 \\ foo && bar +;
66 \\ }
67 \\ }
68 \\}
69 , &[_]Error{
70 .ExpectedToken,
71 .ExpectedToken,
72 .InvalidAnd,
73 .InvalidToken,
74 });
75}
76
77test "recovery: extra qualifier" {
78 try testError(
79 \\const a: *const const u8;
80 \\test ""
81 , &[_]Error{
82 .ExtraConstQualifier,
83 .ExpectedLBrace,
84 });
85}
86
87test "recovery: missing return type" {
88 try testError(
89 \\fn foo() {
90 \\ a && b;
91 \\}
92 \\test ""
93 , &[_]Error{
94 .ExpectedReturnType,
95 .InvalidAnd,
96 .ExpectedLBrace,
97 });
98}
99
100test "recovery: continue after invalid decl" {
101 try testError(
102 \\fn foo {
103 \\ inline;
104 \\}
105 \\pub test "" {
106 \\ async a && b;
107 \\}
108 , &[_]Error{
109 .ExpectedToken,
110 .ExpectedPubItem,
111 .ExpectedParamList,
112 .InvalidAnd,
113 });
114 try testError(
115 \\threadlocal test "" {
116 \\ @a && b;
117 \\}
118 , &[_]Error{
119 .ExpectedVarDecl,
120 .ExpectedParamList,
121 .InvalidAnd,
122 });
123}
124
125test "recovery: invalid extern/inline" {
126 try testError(
127 \\inline test "" { a && b; }
128 , &[_]Error{
129 .ExpectedFn,
130 .InvalidAnd,
131 });
132 try testError(
133 \\extern "" test "" { a && b; }
134 , &[_]Error{
135 .ExpectedVarDeclOrFn,
136 .InvalidAnd,
137 });
138}
139
140test "recovery: missing semicolon" {
141 try testError(
142 \\test "" {
143 \\ comptime a && b
144 \\ c && d
145 \\ @foo
146 \\}
147 , &[_]Error{
148 .InvalidAnd,
149 .ExpectedToken,
150 .InvalidAnd,
151 .ExpectedToken,
152 .ExpectedParamList,
153 .ExpectedToken,
154 });
155}
156
157test "recovery: invalid container members" {
158 try testError(
159 \\usingnamespace;
160 \\foo+
161 \\bar@,
162 \\while (a == 2) { test "" {}}
163 \\test "" {
164 \\ a && b
165 \\}
166 , &[_]Error{
167 .ExpectedExpr,
168 .ExpectedToken,
169 .ExpectedToken,
170 .ExpectedContainerMembers,
171 .InvalidAnd,
172 .ExpectedToken,
173 });
174}
175
176test "recovery: invalid parameter" {
177 try testError(
178 \\fn main() void {
179 \\ a(comptime T: type)
180 \\}
181 , &[_]Error{
182 .ExpectedToken,
183 });
184}
185
186test "recovery: extra '}' at top level" {
187 try testError(
188 \\}}}
189 \\test "" {
190 \\ a && b;
191 \\}
192 , &[_]Error{
193 .ExpectedContainerMembers,
194 .ExpectedContainerMembers,
195 .ExpectedContainerMembers,
196 .InvalidAnd,
197 });
198}
199
200test "recovery: mismatched bracket at top level" {
201 try testError(
202 \\const S = struct {
203 \\ arr: 128]?G
204 \\};
205 , &[_]Error{
206 .ExpectedToken,
207 });
208}
209
210test "recovery: invalid global error set access" {
211 try testError(
212 \\test "" {
213 \\ error && foo;
214 \\}
215 , &[_]Error{
216 .ExpectedToken,
217 .ExpectedIdentifier,
218 .InvalidAnd,
219 });
220}
221
222test "recovery: invalid asterisk after pointer dereference" {
223 try testError(
224 \\test "" {
225 \\ var sequence = "repeat".*** 10;
226 \\}
227 , &[_]Error{
228 .AsteriskAfterPointerDereference,
229 });
230 try testError(
231 \\test "" {
232 \\ var sequence = "repeat".** 10&&a;
233 \\}
234 , &[_]Error{
235 .AsteriskAfterPointerDereference,
236 .InvalidAnd,
237 });
238}
239
240test "recovery: missing semicolon after if, for, while stmt" {
241 try testError(
242 \\test "" {
243 \\ if (foo) bar
244 \\ for (foo) |a| bar
245 \\ while (foo) bar
246 \\ a && b;
247 \\}
248 , &[_]Error{
249 .ExpectedSemiOrElse,
250 .ExpectedSemiOrElse,
251 .ExpectedSemiOrElse,
252 .InvalidAnd,
253 });
254}
255
256test "recovery: invalid comptime" {
257 try testError(
258 \\comptime
259 , &[_]Error{
260 .ExpectedBlockOrField,
261 });
262}
263
264test "recovery: missing block after for/while loops" {
265 try testError(
266 \\test "" { while (foo) }
267 , &[_]Error{
268 .ExpectedBlockOrAssignment,
269 });
270 try testError(
271 \\test "" { for (foo) |bar| }
272 , &[_]Error{
273 .ExpectedBlockOrAssignment,
274 });
275}
276
277test "zig fmt: respect line breaks after var declarations" {
278 try testCanonical(
279 \\const crc =
280 \\ lookup_tables[0][p[7]] ^
281 \\ lookup_tables[1][p[6]] ^
282 \\ lookup_tables[2][p[5]] ^
283 \\ lookup_tables[3][p[4]] ^
284 \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
285 \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
286 \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
287 \\ lookup_tables[7][@truncate(u8, self.crc >> 0)];
288 \\
289 );
290}
291
292test "zig fmt: multiline string mixed with comments" {
293 try testCanonical(
294 \\const s1 =
295 \\ //\\one
296 \\ \\two)
297 \\ \\three
298 \\;
299 \\const s2 =
300 \\ \\one
301 \\ \\two)
302 \\ //\\three
303 \\;
304 \\const s3 =
305 \\ \\one
306 \\ //\\two)
307 \\ \\three
308 \\;
309 \\const s4 =
310 \\ \\one
311 \\ //\\two
312 \\ \\three
313 \\ //\\four
314 \\ \\five
315 \\;
316 \\const a =
317 \\ 1;
318 \\
319 );
320}
321
322test "zig fmt: empty file" {
323 try testCanonical(
324 \\
325 );
326}
327
328test "zig fmt: if statment" {
329 try testCanonical(
330 \\test "" {
331 \\ if (optional()) |some|
332 \\ bar = some.foo();
333 \\}
334 \\
335 );
336}
337
338test "zig fmt: top-level fields" {
339 try testCanonical(
340 \\a: did_you_know,
341 \\b: all_files_are,
342 \\structs: ?x,
343 \\
344 );
345}
346
347test "zig fmt: decl between fields" {
348 try testError(
349 \\const S = struct {
350 \\ const foo = 2;
351 \\ const bar = 2;
352 \\ const baz = 2;
353 \\ a: usize,
354 \\ const foo1 = 2;
355 \\ const bar1 = 2;
356 \\ const baz1 = 2;
357 \\ b: usize,
358 \\};
359 , &[_]Error{
360 .DeclBetweenFields,
361 });
362}
363
364test "zig fmt: eof after missing comma" {
365 try testError(
366 \\foo()
367 , &[_]Error{
368 .ExpectedToken,
369 });
370}
371
372test "zig fmt: errdefer with payload" {
373 try testCanonical(
374 \\pub fn main() anyerror!void {
375 \\ errdefer |a| x += 1;
376 \\ errdefer |a| {}
377 \\ errdefer |a| {
378 \\ x += 1;
379 \\ }
380 \\}
381 \\
382 );
383}
384
385test "zig fmt: nosuspend block" {
386 try testCanonical(
387 \\pub fn main() anyerror!void {
388 \\ nosuspend {
389 \\ var foo: Foo = .{ .bar = 42 };
390 \\ }
391 \\}
392 \\
393 );
394}
395
396test "zig fmt: nosuspend await" {
397 try testCanonical(
398 \\fn foo() void {
399 \\ x = nosuspend await y;
400 \\}
401 \\
402 );
403}
404
405test "zig fmt: trailing comma in container declaration" {
406 try testCanonical(
407 \\const X = struct { foo: i32 };
408 \\const X = struct { foo: i32, bar: i32 };
409 \\const X = struct { foo: i32 = 1, bar: i32 = 2 };
410 \\const X = struct { foo: i32 align(4), bar: i32 align(4) };
411 \\const X = struct { foo: i32 align(4) = 1, bar: i32 align(4) = 2 };
412 \\
413 );
414 try testCanonical(
415 \\test "" {
416 \\ comptime {
417 \\ const X = struct {
418 \\ x: i32
419 \\ };
420 \\ }
421 \\}
422 \\
423 );
424 try testTransform(
425 \\const X = struct {
426 \\ foo: i32, bar: i8 };
427 ,
428 \\const X = struct {
429 \\ foo: i32, bar: i8
430 \\};
431 \\
432 );
433}
434
435test "zig fmt: trailing comma in fn parameter list" {
436 try testCanonical(
437 \\pub fn f(
438 \\ a: i32,
439 \\ b: i32,
440 \\) i32 {}
441 \\pub fn f(
442 \\ a: i32,
443 \\ b: i32,
444 \\) align(8) i32 {}
445 \\pub fn f(
446 \\ a: i32,
447 \\ b: i32,
448 \\) linksection(".text") i32 {}
449 \\pub fn f(
450 \\ a: i32,
451 \\ b: i32,
452 \\) callconv(.C) i32 {}
453 \\pub fn f(
454 \\ a: i32,
455 \\ b: i32,
456 \\) align(8) linksection(".text") i32 {}
457 \\pub fn f(
458 \\ a: i32,
459 \\ b: i32,
460 \\) align(8) callconv(.C) i32 {}
461 \\pub fn f(
462 \\ a: i32,
463 \\ b: i32,
464 \\) align(8) linksection(".text") callconv(.C) i32 {}
465 \\pub fn f(
466 \\ a: i32,
467 \\ b: i32,
468 \\) linksection(".text") callconv(.C) i32 {}
469 \\
470 );
471}
472
473test "zig fmt: comptime struct field" {
474 try testCanonical(
475 \\const Foo = struct {
476 \\ a: i32,
477 \\ comptime b: i32 = 1234,
478 \\};
479 \\
480 );
481}
482
483test "zig fmt: c pointer type" {
484 try testCanonical(
485 \\pub extern fn repro() [*c]const u8;
486 \\
487 );
488}
489
490test "zig fmt: builtin call with trailing comma" {
491 try testCanonical(
492 \\pub fn main() void {
493 \\ @breakpoint();
494 \\ _ = @boolToInt(a);
495 \\ _ = @call(
496 \\ a,
497 \\ b,
498 \\ c,
499 \\ );
500 \\}
501 \\
502 );
503}
504
505test "zig fmt: asm expression with comptime content" {
506 try testCanonical(
507 \\comptime {
508 \\ asm ("foo" ++ "bar");
509 \\}
510 \\pub fn main() void {
511 \\ asm volatile ("foo" ++ "bar");
512 \\ asm volatile ("foo" ++ "bar"
513 \\ : [_] "" (x)
514 \\ );
515 \\ asm volatile ("foo" ++ "bar"
516 \\ : [_] "" (x)
517 \\ : [_] "" (y)
518 \\ );
519 \\ asm volatile ("foo" ++ "bar"
520 \\ : [_] "" (x)
521 \\ : [_] "" (y)
522 \\ : "h", "e", "l", "l", "o"
523 \\ );
524 \\}
525 \\
526 );
527}
528
529test "zig fmt: anytype struct field" {
530 try testCanonical(
531 \\pub const Pointer = struct {
532 \\ sentinel: anytype,
533 \\};
534 \\
535 );
536}
537
538test "zig fmt: sentinel-terminated array type" {
539 try testCanonical(
540 \\pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 {
541 \\ return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
542 \\}
543 \\
544 );
545}
546
547test "zig fmt: sentinel-terminated slice type" {
548 try testCanonical(
549 \\pub fn toSlice(self: Buffer) [:0]u8 {
550 \\ return self.list.toSlice()[0..self.len()];
551 \\}
552 \\
553 );
554}
555
556test "zig fmt: anon literal in array" {
557 try testCanonical(
558 \\var arr: [2]Foo = .{
559 \\ .{ .a = 2 },
560 \\ .{ .b = 3 },
561 \\};
562 \\
563 );
564}
565
566test "zig fmt: alignment in anonymous literal" {
567 try testTransform(
568 \\const a = .{
569 \\ "U", "L", "F",
570 \\ "U'",
571 \\ "L'",
572 \\ "F'",
573 \\};
574 \\
575 ,
576 \\const a = .{
577 \\ "U", "L", "F",
578 \\ "U'", "L'", "F'",
579 \\};
580 \\
581 );
582}
583
584test "zig fmt: anon struct literal syntax" {
585 try testCanonical(
586 \\const x = .{
587 \\ .a = b,
588 \\ .c = d,
589 \\};
590 \\
591 );
592}
593
594test "zig fmt: anon list literal syntax" {
595 try testCanonical(
596 \\const x = .{ a, b, c };
597 \\
598 );
599}
600
601test "zig fmt: async function" {
602 try testCanonical(
603 \\pub const Server = struct {
604 \\ handleRequestFn: fn (*Server, *const std.net.Address, File) callconv(.Async) void,
605 \\};
606 \\test "hi" {
607 \\ var ptr = @ptrCast(fn (i32) callconv(.Async) void, other);
608 \\}
609 \\
610 );
611}
612
613test "zig fmt: whitespace fixes" {
614 try testTransform("test \"\" {\r\n\tconst hi = x;\r\n}\n// zig fmt: off\ntest \"\"{\r\n\tconst a = b;}\r\n",
615 \\test "" {
616 \\ const hi = x;
617 \\}
618 \\// zig fmt: off
619 \\test ""{
620 \\ const a = b;}
621 \\
622 );
623}
624
625test "zig fmt: while else err prong with no block" {
626 try testCanonical(
627 \\test "" {
628 \\ const result = while (returnError()) |value| {
629 \\ break value;
630 \\ } else |err| @as(i32, 2);
631 \\ expect(result == 2);
632 \\}
633 \\
634 );
635}
636
637test "zig fmt: tagged union with enum values" {
638 try testCanonical(
639 \\const MultipleChoice2 = union(enum(u32)) {
640 \\ Unspecified1: i32,
641 \\ A: f32 = 20,
642 \\ Unspecified2: void,
643 \\ B: bool = 40,
644 \\ Unspecified3: i32,
645 \\ C: i8 = 60,
646 \\ Unspecified4: void,
647 \\ D: void = 1000,
648 \\ Unspecified5: i32,
649 \\};
650 \\
651 );
652}
653
654test "zig fmt: allowzero pointer" {
655 try testCanonical(
656 \\const T = [*]allowzero const u8;
657 \\
658 );
659}
660
661test "zig fmt: enum literal" {
662 try testCanonical(
663 \\const x = .hi;
664 \\
665 );
666}
667
668test "zig fmt: enum literal inside array literal" {
669 try testCanonical(
670 \\test "enums in arrays" {
671 \\ var colors = []Color{.Green};
672 \\ colors = []Colors{ .Green, .Cyan };
673 \\ colors = []Colors{
674 \\ .Grey,
675 \\ .Green,
676 \\ .Cyan,
677 \\ };
678 \\}
679 \\
680 );
681}
682
683test "zig fmt: character literal larger than u8" {
684 try testCanonical(
685 \\const x = '\u{01f4a9}';
686 \\
687 );
688}
689
690test "zig fmt: infix operator and then multiline string literal" {
691 try testCanonical(
692 \\const x = "" ++
693 \\ \\ hi
694 \\;
695 \\
696 );
697}
698
699test "zig fmt: infix operator and then multiline string literal" {
700 try testCanonical(
701 \\const x = "" ++
702 \\ \\ hi0
703 \\ \\ hi1
704 \\ \\ hi2
705 \\;
706 \\
707 );
708}
709
710test "zig fmt: C pointers" {
711 try testCanonical(
712 \\const Ptr = [*c]i32;
713 \\
714 );
715}
716
717test "zig fmt: threadlocal" {
718 try testCanonical(
719 \\threadlocal var x: i32 = 1234;
720 \\
721 );
722}
723
724test "zig fmt: linksection" {
725 try testCanonical(
726 \\export var aoeu: u64 linksection(".text.derp") = 1234;
727 \\export fn _start() linksection(".text.boot") callconv(.Naked) noreturn {}
728 \\
729 );
730}
731
732test "zig fmt: correctly move doc comments on struct fields" {
733 try testTransform(
734 \\pub const section_64 = extern struct {
735 \\ sectname: [16]u8, /// name of this section
736 \\ segname: [16]u8, /// segment this section goes in
737 \\};
738 ,
739 \\pub const section_64 = extern struct {
740 \\ /// name of this section
741 \\ sectname: [16]u8,
742 \\ /// segment this section goes in
743 \\ segname: [16]u8,
744 \\};
745 \\
746 );
747}
748
749test "zig fmt: correctly space struct fields with doc comments" {
750 try testTransform(
751 \\pub const S = struct {
752 \\ /// A
753 \\ a: u8,
754 \\ /// B
755 \\ /// B (cont)
756 \\ b: u8,
757 \\
758 \\
759 \\ /// C
760 \\ c: u8,
761 \\};
762 \\
763 ,
764 \\pub const S = struct {
765 \\ /// A
766 \\ a: u8,
767 \\ /// B
768 \\ /// B (cont)
769 \\ b: u8,
770 \\
771 \\ /// C
772 \\ c: u8,
773 \\};
774 \\
775 );
776}
777
778test "zig fmt: doc comments on param decl" {
779 try testCanonical(
780 \\pub const Allocator = struct {
781 \\ shrinkFn: fn (
782 \\ self: *Allocator,
783 \\ /// Guaranteed to be the same as what was returned from most recent call to
784 \\ /// `allocFn`, `reallocFn`, or `shrinkFn`.
785 \\ old_mem: []u8,
786 \\ /// Guaranteed to be the same as what was returned from most recent call to
787 \\ /// `allocFn`, `reallocFn`, or `shrinkFn`.
788 \\ old_alignment: u29,
789 \\ /// Guaranteed to be less than or equal to `old_mem.len`.
790 \\ new_byte_count: usize,
791 \\ /// Guaranteed to be less than or equal to `old_alignment`.
792 \\ new_alignment: u29,
793 \\ ) []u8,
794 \\};
795 \\
796 );
797}
798
799test "zig fmt: aligned struct field" {
800 try testCanonical(
801 \\pub const S = struct {
802 \\ f: i32 align(32),
803 \\};
804 \\
805 );
806 try testCanonical(
807 \\pub const S = struct {
808 \\ f: i32 align(32) = 1,
809 \\};
810 \\
811 );
812}
813
814test "zig fmt: comment to disable/enable zig fmt first" {
815 try testCanonical(
816 \\// Test trailing comma syntax
817 \\// zig fmt: off
818 \\
819 \\const struct_trailing_comma = struct { x: i32, y: i32, };
820 );
821}
822
823test "zig fmt: comment to disable/enable zig fmt" {
824 try testTransform(
825 \\const a = b;
826 \\// zig fmt: off
827 \\const c = d;
828 \\// zig fmt: on
829 \\const e = f;
830 ,
831 \\const a = b;
832 \\// zig fmt: off
833 \\const c = d;
834 \\// zig fmt: on
835 \\const e = f;
836 \\
837 );
838}
839
840test "zig fmt: line comment following 'zig fmt: off'" {
841 try testCanonical(
842 \\// zig fmt: off
843 \\// Test
844 \\const e = f;
845 );
846}
847
848test "zig fmt: doc comment following 'zig fmt: off'" {
849 try testCanonical(
850 \\// zig fmt: off
851 \\/// test
852 \\const e = f;
853 );
854}
855
856test "zig fmt: line and doc comment following 'zig fmt: off'" {
857 try testCanonical(
858 \\// zig fmt: off
859 \\// test 1
860 \\/// test 2
861 \\const e = f;
862 );
863}
864
865test "zig fmt: doc and line comment following 'zig fmt: off'" {
866 try testCanonical(
867 \\// zig fmt: off
868 \\/// test 1
869 \\// test 2
870 \\const e = f;
871 );
872}
873
874test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" {
875 try testCanonical(
876 \\// zig fmt: off
877 \\// zig fmt: on
878 \\// zig fmt: off
879 \\const e = f;
880 \\// zig fmt: off
881 \\// zig fmt: on
882 \\// zig fmt: off
883 \\const a = b;
884 \\// zig fmt: on
885 \\const c = d;
886 \\// zig fmt: on
887 \\
888 );
889}
890
891test "zig fmt: line comment following 'zig fmt: on'" {
892 try testCanonical(
893 \\// zig fmt: off
894 \\const e = f;
895 \\// zig fmt: on
896 \\// test
897 \\const e = f;
898 \\
899 );
900}
901
902test "zig fmt: doc comment following 'zig fmt: on'" {
903 try testCanonical(
904 \\// zig fmt: off
905 \\const e = f;
906 \\// zig fmt: on
907 \\/// test
908 \\const e = f;
909 \\
910 );
911}
912
913test "zig fmt: line and doc comment following 'zig fmt: on'" {
914 try testCanonical(
915 \\// zig fmt: off
916 \\const e = f;
917 \\// zig fmt: on
918 \\// test1
919 \\/// test2
920 \\const e = f;
921 \\
922 );
923}
924
925test "zig fmt: doc and line comment following 'zig fmt: on'" {
926 try testCanonical(
927 \\// zig fmt: off
928 \\const e = f;
929 \\// zig fmt: on
930 \\/// test1
931 \\// test2
932 \\const e = f;
933 \\
934 );
935}
936
937test "zig fmt: pointer of unknown length" {
938 try testCanonical(
939 \\fn foo(ptr: [*]u8) void {}
940 \\
941 );
942}
943
944test "zig fmt: spaces around slice operator" {
945 try testCanonical(
946 \\var a = b[c..d];
947 \\var a = b[c..d :0];
948 \\var a = b[c + 1 .. d];
949 \\var a = b[c + 1 ..];
950 \\var a = b[c .. d + 1];
951 \\var a = b[c .. d + 1 :0];
952 \\var a = b[c.a..d.e];
953 \\var a = b[c.a..d.e :0];
954 \\
955 );
956}
957
958test "zig fmt: async call in if condition" {
959 try testCanonical(
960 \\comptime {
961 \\ if (async b()) {
962 \\ a();
963 \\ }
964 \\}
965 \\
966 );
967}
968
969test "zig fmt: 2nd arg multiline string" {
970 try testCanonical(
971 \\comptime {
972 \\ cases.addAsm("hello world linux x86_64",
973 \\ \\.text
974 \\ , "Hello, world!\n");
975 \\}
976 \\
977 );
978}
979
980test "zig fmt: 2nd arg multiline string many args" {
981 try testCanonical(
982 \\comptime {
983 \\ cases.addAsm("hello world linux x86_64",
984 \\ \\.text
985 \\ , "Hello, world!\n", "Hello, world!\n");
986 \\}
987 \\
988 );
989}
990
991test "zig fmt: final arg multiline string" {
992 try testCanonical(
993 \\comptime {
994 \\ cases.addAsm("hello world linux x86_64", "Hello, world!\n",
995 \\ \\.text
996 \\ );
997 \\}
998 \\
999 );
1000}
1001
1002test "zig fmt: if condition wraps" {
1003 try testTransform(
1004 \\comptime {
1005 \\ if (cond and
1006 \\ cond) {
1007 \\ return x;
1008 \\ }
1009 \\ while (cond and
1010 \\ cond) {
1011 \\ return x;
1012 \\ }
1013 \\ if (a == b and
1014 \\ c) {
1015 \\ a = b;
1016 \\ }
1017 \\ while (a == b and
1018 \\ c) {
1019 \\ a = b;
1020 \\ }
1021 \\ if ((cond and
1022 \\ cond)) {
1023 \\ return x;
1024 \\ }
1025 \\ while ((cond and
1026 \\ cond)) {
1027 \\ return x;
1028 \\ }
1029 \\ var a = if (a) |*f| x: {
1030 \\ break :x &a.b;
1031 \\ } else |err| err;
1032 \\ var a = if (cond and
1033 \\ cond) |*f|
1034 \\ x: {
1035 \\ break :x &a.b;
1036 \\ } else |err| err;
1037 \\}
1038 ,
1039 \\comptime {
1040 \\ if (cond and
1041 \\ cond)
1042 \\ {
1043 \\ return x;
1044 \\ }
1045 \\ while (cond and
1046 \\ cond)
1047 \\ {
1048 \\ return x;
1049 \\ }
1050 \\ if (a == b and
1051 \\ c)
1052 \\ {
1053 \\ a = b;
1054 \\ }
1055 \\ while (a == b and
1056 \\ c)
1057 \\ {
1058 \\ a = b;
1059 \\ }
1060 \\ if ((cond and
1061 \\ cond))
1062 \\ {
1063 \\ return x;
1064 \\ }
1065 \\ while ((cond and
1066 \\ cond))
1067 \\ {
1068 \\ return x;
1069 \\ }
1070 \\ var a = if (a) |*f| x: {
1071 \\ break :x &a.b;
1072 \\ } else |err| err;
1073 \\ var a = if (cond and
1074 \\ cond) |*f|
1075 \\ x: {
1076 \\ break :x &a.b;
1077 \\ } else |err| err;
1078 \\}
1079 \\
1080 );
1081}
1082
1083test "zig fmt: if condition has line break but must not wrap" {
1084 try testCanonical(
1085 \\comptime {
1086 \\ if (self.user_input_options.put(
1087 \\ name,
1088 \\ UserInputOption{
1089 \\ .name = name,
1090 \\ .used = false,
1091 \\ },
1092 \\ ) catch unreachable) |*prev_value| {
1093 \\ foo();
1094 \\ bar();
1095 \\ }
1096 \\ if (put(
1097 \\ a,
1098 \\ b,
1099 \\ )) {
1100 \\ foo();
1101 \\ }
1102 \\}
1103 \\
1104 );
1105}
1106
1107test "zig fmt: if condition has line break but must not wrap" {
1108 try testCanonical(
1109 \\comptime {
1110 \\ if (self.user_input_options.put(name, UserInputOption{
1111 \\ .name = name,
1112 \\ .used = false,
1113 \\ }) catch unreachable) |*prev_value| {
1114 \\ foo();
1115 \\ bar();
1116 \\ }
1117 \\ if (put(
1118 \\ a,
1119 \\ b,
1120 \\ )) {
1121 \\ foo();
1122 \\ }
1123 \\}
1124 \\
1125 );
1126}
1127
1128test "zig fmt: function call with multiline argument" {
1129 try testCanonical(
1130 \\comptime {
1131 \\ self.user_input_options.put(name, UserInputOption{
1132 \\ .name = name,
1133 \\ .used = false,
1134 \\ });
1135 \\}
1136 \\
1137 );
1138}
1139
1140test "zig fmt: same-line doc comment on variable declaration" {
1141 try testTransform(
1142 \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
1143 \\pub const MAP_FILE = 0x0000; /// map from file (default)
1144 \\
1145 \\pub const EMEDIUMTYPE = 124; /// Wrong medium type
1146 \\
1147 \\// nameserver query return codes
1148 \\pub const ENSROK = 0; /// DNS server returned answer with no data
1149 ,
1150 \\/// allocated from memory, swap space
1151 \\pub const MAP_ANONYMOUS = 0x1000;
1152 \\/// map from file (default)
1153 \\pub const MAP_FILE = 0x0000;
1154 \\
1155 \\/// Wrong medium type
1156 \\pub const EMEDIUMTYPE = 124;
1157 \\
1158 \\// nameserver query return codes
1159 \\/// DNS server returned answer with no data
1160 \\pub const ENSROK = 0;
1161 \\
1162 );
1163}
1164
1165test "zig fmt: if-else with comment before else" {
1166 try testCanonical(
1167 \\comptime {
1168 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
1169 \\ if ((hx & 0x7fffffff) != 0x7f800000) {
1170 \\ return Complex(f32).new(y - y, y - y);
1171 \\ } // cexp(-inf +- i inf|nan) = 0 + i0
1172 \\ else if (hx & 0x80000000 != 0) {
1173 \\ return Complex(f32).new(0, 0);
1174 \\ } // cexp(+inf +- i inf|nan) = inf + i nan
1175 \\ else {
1176 \\ return Complex(f32).new(x, y - y);
1177 \\ }
1178 \\}
1179 \\
1180 );
1181}
1182
1183test "zig fmt: if nested" {
1184 try testCanonical(
1185 \\pub fn foo() void {
1186 \\ return if ((aInt & bInt) >= 0)
1187 \\ if (aInt < bInt)
1188 \\ GE_LESS
1189 \\ else if (aInt == bInt)
1190 \\ GE_EQUAL
1191 \\ else
1192 \\ GE_GREATER
1193 \\ else if (aInt > bInt)
1194 \\ GE_LESS
1195 \\ else if (aInt == bInt)
1196 \\ GE_EQUAL
1197 \\ else
1198 \\ GE_GREATER;
1199 \\}
1200 \\
1201 );
1202}
1203
1204test "zig fmt: respect line breaks in if-else" {
1205 try testCanonical(
1206 \\comptime {
1207 \\ return if (cond) a else b;
1208 \\ return if (cond)
1209 \\ a
1210 \\ else
1211 \\ b;
1212 \\ return if (cond)
1213 \\ a
1214 \\ else if (cond)
1215 \\ b
1216 \\ else
1217 \\ c;
1218 \\}
1219 \\
1220 );
1221}
1222
1223test "zig fmt: respect line breaks after infix operators" {
1224 try testCanonical(
1225 \\comptime {
1226 \\ self.crc =
1227 \\ lookup_tables[0][p[7]] ^
1228 \\ lookup_tables[1][p[6]] ^
1229 \\ lookup_tables[2][p[5]] ^
1230 \\ lookup_tables[3][p[4]] ^
1231 \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
1232 \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
1233 \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
1234 \\ lookup_tables[7][@truncate(u8, self.crc >> 0)];
1235 \\}
1236 \\
1237 );
1238}
1239
1240test "zig fmt: fn decl with trailing comma" {
1241 try testTransform(
1242 \\fn foo(a: i32, b: i32,) void {}
1243 ,
1244 \\fn foo(
1245 \\ a: i32,
1246 \\ b: i32,
1247 \\) void {}
1248 \\
1249 );
1250}
1251
1252test "zig fmt: enum decl with no trailing comma" {
1253 try testTransform(
1254 \\const StrLitKind = enum {Normal, C};
1255 ,
1256 \\const StrLitKind = enum { Normal, C };
1257 \\
1258 );
1259}
1260
1261test "zig fmt: switch comment before prong" {
1262 try testCanonical(
1263 \\comptime {
1264 \\ switch (a) {
1265 \\ // hi
1266 \\ 0 => {},
1267 \\ }
1268 \\}
1269 \\
1270 );
1271}
1272
1273test "zig fmt: struct literal no trailing comma" {
1274 try testTransform(
1275 \\const a = foo{ .x = 1, .y = 2 };
1276 \\const a = foo{ .x = 1,
1277 \\ .y = 2 };
1278 ,
1279 \\const a = foo{ .x = 1, .y = 2 };
1280 \\const a = foo{
1281 \\ .x = 1,
1282 \\ .y = 2,
1283 \\};
1284 \\
1285 );
1286}
1287
1288test "zig fmt: struct literal containing a multiline expression" {
1289 try testTransform(
1290 \\const a = A{ .x = if (f1()) 10 else 20 };
1291 \\const a = A{ .x = if (f1()) 10 else 20, };
1292 \\const a = A{ .x = if (f1())
1293 \\ 10 else 20 };
1294 \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 };
1295 \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100, };
1296 \\const a = A{ .x = if (f1())
1297 \\ 10 else 20};
1298 \\const a = A{ .x = switch(g) {0 => "ok", else => "no"} };
1299 \\
1300 ,
1301 \\const a = A{ .x = if (f1()) 10 else 20 };
1302 \\const a = A{
1303 \\ .x = if (f1()) 10 else 20,
1304 \\};
1305 \\const a = A{
1306 \\ .x = if (f1())
1307 \\ 10
1308 \\ else
1309 \\ 20,
1310 \\};
1311 \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 };
1312 \\const a = A{
1313 \\ .x = if (f1()) 10 else 20,
1314 \\ .y = f2() + 100,
1315 \\};
1316 \\const a = A{
1317 \\ .x = if (f1())
1318 \\ 10
1319 \\ else
1320 \\ 20,
1321 \\};
1322 \\const a = A{
1323 \\ .x = switch (g) {
1324 \\ 0 => "ok",
1325 \\ else => "no",
1326 \\ },
1327 \\};
1328 \\
1329 );
1330}
1331
1332test "zig fmt: array literal with hint" {
1333 try testTransform(
1334 \\const a = []u8{
1335 \\ 1, 2, //
1336 \\ 3,
1337 \\ 4,
1338 \\ 5,
1339 \\ 6,
1340 \\ 7 };
1341 \\const a = []u8{
1342 \\ 1, 2, //
1343 \\ 3,
1344 \\ 4,
1345 \\ 5,
1346 \\ 6,
1347 \\ 7, 8 };
1348 \\const a = []u8{
1349 \\ 1, 2, //
1350 \\ 3,
1351 \\ 4,
1352 \\ 5,
1353 \\ 6, // blah
1354 \\ 7, 8 };
1355 \\const a = []u8{
1356 \\ 1, 2, //
1357 \\ 3, //
1358 \\ 4,
1359 \\ 5,
1360 \\ 6,
1361 \\ 7 };
1362 \\const a = []u8{
1363 \\ 1,
1364 \\ 2,
1365 \\ 3, 4, //
1366 \\ 5, 6, //
1367 \\ 7, 8, //
1368 \\};
1369 ,
1370 \\const a = []u8{
1371 \\ 1, 2,
1372 \\ 3, 4,
1373 \\ 5, 6,
1374 \\ 7,
1375 \\};
1376 \\const a = []u8{
1377 \\ 1, 2,
1378 \\ 3, 4,
1379 \\ 5, 6,
1380 \\ 7, 8,
1381 \\};
1382 \\const a = []u8{
1383 \\ 1, 2,
1384 \\ 3, 4,
1385 \\ 5,
1386 \\ 6, // blah
1387 \\ 7,
1388 \\ 8,
1389 \\};
1390 \\const a = []u8{
1391 \\ 1, 2,
1392 \\ 3, //
1393 \\ 4,
1394 \\ 5, 6,
1395 \\ 7,
1396 \\};
1397 \\const a = []u8{
1398 \\ 1,
1399 \\ 2,
1400 \\ 3,
1401 \\ 4,
1402 \\ 5,
1403 \\ 6,
1404 \\ 7,
1405 \\ 8,
1406 \\};
1407 \\
1408 );
1409}
1410
1411test "zig fmt: array literal veritical column alignment" {
1412 try testTransform(
1413 \\const a = []u8{
1414 \\ 1000, 200,
1415 \\ 30, 4,
1416 \\ 50000, 60
1417 \\};
1418 \\const a = []u8{0, 1, 2, 3, 40,
1419 \\ 4,5,600,7,
1420 \\ 80,
1421 \\ 9, 10, 11, 0, 13, 14, 15};
1422 \\
1423 ,
1424 \\const a = []u8{
1425 \\ 1000, 200,
1426 \\ 30, 4,
1427 \\ 50000, 60,
1428 \\};
1429 \\const a = []u8{
1430 \\ 0, 1, 2, 3, 40,
1431 \\ 4, 5, 600, 7, 80,
1432 \\ 9, 10, 11, 0, 13,
1433 \\ 14, 15,
1434 \\};
1435 \\
1436 );
1437}
1438
1439test "zig fmt: multiline string with backslash at end of line" {
1440 try testCanonical(
1441 \\comptime {
1442 \\ err(
1443 \\ \\\
1444 \\ );
1445 \\}
1446 \\
1447 );
1448}
1449
1450test "zig fmt: multiline string parameter in fn call with trailing comma" {
1451 try testCanonical(
1452 \\fn foo() void {
1453 \\ try stdout.print(
1454 \\ \\ZIG_CMAKE_BINARY_DIR {}
1455 \\ \\ZIG_C_HEADER_FILES {}
1456 \\ \\ZIG_DIA_GUIDS_LIB {}
1457 \\ \\
1458 \\ ,
1459 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
1460 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
1461 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
1462 \\ );
1463 \\}
1464 \\
1465 );
1466}
1467
1468test "zig fmt: trailing comma on fn call" {
1469 try testCanonical(
1470 \\comptime {
1471 \\ var module = try Module.create(
1472 \\ allocator,
1473 \\ zig_lib_dir,
1474 \\ full_cache_dir,
1475 \\ );
1476 \\}
1477 \\
1478 );
1479}
1480
1481test "zig fmt: multi line arguments without last comma" {
1482 try testTransform(
1483 \\pub fn foo(
1484 \\ a: usize,
1485 \\ b: usize,
1486 \\ c: usize,
1487 \\ d: usize
1488 \\) usize {
1489 \\ return a + b + c + d;
1490 \\}
1491 \\
1492 ,
1493 \\pub fn foo(a: usize, b: usize, c: usize, d: usize) usize {
1494 \\ return a + b + c + d;
1495 \\}
1496 \\
1497 );
1498}
1499
1500test "zig fmt: empty block with only comment" {
1501 try testCanonical(
1502 \\comptime {
1503 \\ {
1504 \\ // comment
1505 \\ }
1506 \\}
1507 \\
1508 );
1509}
1510
1511test "zig fmt: no trailing comma on struct decl" {
1512 try testCanonical(
1513 \\const RoundParam = struct {
1514 \\ k: usize, s: u32, t: u32
1515 \\};
1516 \\
1517 );
1518}
1519
1520test "zig fmt: extra newlines at the end" {
1521 try testTransform(
1522 \\const a = b;
1523 \\
1524 \\
1525 \\
1526 ,
1527 \\const a = b;
1528 \\
1529 );
1530}
1531
1532test "zig fmt: simple asm" {
1533 try testTransform(
1534 \\comptime {
1535 \\ asm volatile (
1536 \\ \\.globl aoeu;
1537 \\ \\.type aoeu, @function;
1538 \\ \\.set aoeu, derp;
1539 \\ );
1540 \\
1541 \\ asm ("not real assembly"
1542 \\ :[a] "x" (x),);
1543 \\ asm ("not real assembly"
1544 \\ :[a] "x" (->i32),:[a] "x" (1),);
1545 \\ asm ("still not real assembly"
1546 \\ :::"a","b",);
1547 \\}
1548 ,
1549 \\comptime {
1550 \\ asm volatile (
1551 \\ \\.globl aoeu;
1552 \\ \\.type aoeu, @function;
1553 \\ \\.set aoeu, derp;
1554 \\ );
1555 \\
1556 \\ asm ("not real assembly"
1557 \\ : [a] "x" (x)
1558 \\ );
1559 \\ asm ("not real assembly"
1560 \\ : [a] "x" (-> i32)
1561 \\ : [a] "x" (1)
1562 \\ );
1563 \\ asm ("still not real assembly"
1564 \\ :
1565 \\ :
1566 \\ : "a", "b"
1567 \\ );
1568 \\}
1569 \\
1570 );
1571}
1572
1573test "zig fmt: nested struct literal with one item" {
1574 try testCanonical(
1575 \\const a = foo{
1576 \\ .item = bar{ .a = b },
1577 \\};
1578 \\
1579 );
1580}
1581
1582test "zig fmt: switch cases trailing comma" {
1583 try testTransform(
1584 \\fn switch_cases(x: i32) void {
1585 \\ switch (x) {
1586 \\ 1,2,3 => {},
1587 \\ 4,5, => {},
1588 \\ 6... 8, => {},
1589 \\ else => {},
1590 \\ }
1591 \\}
1592 ,
1593 \\fn switch_cases(x: i32) void {
1594 \\ switch (x) {
1595 \\ 1, 2, 3 => {},
1596 \\ 4,
1597 \\ 5,
1598 \\ => {},
1599 \\ 6...8 => {},
1600 \\ else => {},
1601 \\ }
1602 \\}
1603 \\
1604 );
1605}
1606
1607test "zig fmt: slice align" {
1608 try testCanonical(
1609 \\const A = struct {
1610 \\ items: []align(A) T,
1611 \\};
1612 \\
1613 );
1614}
1615
1616test "zig fmt: add trailing comma to array literal" {
1617 try testTransform(
1618 \\comptime {
1619 \\ return []u16{'m', 's', 'y', 's', '-' // hi
1620 \\ };
1621 \\ return []u16{'m', 's', 'y', 's',
1622 \\ '-'};
1623 \\ return []u16{'m', 's', 'y', 's', '-'};
1624 \\}
1625 ,
1626 \\comptime {
1627 \\ return []u16{
1628 \\ 'm', 's', 'y', 's', '-', // hi
1629 \\ };
1630 \\ return []u16{
1631 \\ 'm', 's', 'y', 's',
1632 \\ '-',
1633 \\ };
1634 \\ return []u16{ 'm', 's', 'y', 's', '-' };
1635 \\}
1636 \\
1637 );
1638}
1639
1640test "zig fmt: first thing in file is line comment" {
1641 try testCanonical(
1642 \\// Introspection and determination of system libraries needed by zig.
1643 \\
1644 \\// Introspection and determination of system libraries needed by zig.
1645 \\
1646 \\const std = @import("std");
1647 \\
1648 );
1649}
1650
1651test "zig fmt: line comment after doc comment" {
1652 try testCanonical(
1653 \\/// doc comment
1654 \\// line comment
1655 \\fn foo() void {}
1656 \\
1657 );
1658}
1659
1660test "zig fmt: float literal with exponent" {
1661 try testCanonical(
1662 \\test "bit field alignment" {
1663 \\ assert(@TypeOf(&blah.b) == *align(1:3:6) const u3);
1664 \\}
1665 \\
1666 );
1667}
1668
1669test "zig fmt: float literal with exponent" {
1670 try testCanonical(
1671 \\test "aoeu" {
1672 \\ switch (state) {
1673 \\ TermState.Start => switch (c) {
1674 \\ '\x1b' => state = TermState.Escape,
1675 \\ else => try out.writeByte(c),
1676 \\ },
1677 \\ }
1678 \\}
1679 \\
1680 );
1681}
1682test "zig fmt: float literal with exponent" {
1683 try testCanonical(
1684 \\pub const f64_true_min = 4.94065645841246544177e-324;
1685 \\const threshold = 0x1.a827999fcef32p+1022;
1686 \\
1687 );
1688}
1689
1690test "zig fmt: if-else end of comptime" {
1691 try testCanonical(
1692 \\comptime {
1693 \\ if (a) {
1694 \\ b();
1695 \\ } else {
1696 \\ b();
1697 \\ }
1698 \\}
1699 \\
1700 );
1701}
1702
1703test "zig fmt: nested blocks" {
1704 try testCanonical(
1705 \\comptime {
1706 \\ {
1707 \\ {
1708 \\ {
1709 \\ a();
1710 \\ }
1711 \\ }
1712 \\ }
1713 \\}
1714 \\
1715 );
1716}
1717
1718test "zig fmt: block with same line comment after end brace" {
1719 try testCanonical(
1720 \\comptime {
1721 \\ {
1722 \\ b();
1723 \\ } // comment
1724 \\}
1725 \\
1726 );
1727}
1728
1729test "zig fmt: statements with comment between" {
1730 try testCanonical(
1731 \\comptime {
1732 \\ a = b;
1733 \\ // comment
1734 \\ a = b;
1735 \\}
1736 \\
1737 );
1738}
1739
1740test "zig fmt: statements with empty line between" {
1741 try testCanonical(
1742 \\comptime {
1743 \\ a = b;
1744 \\
1745 \\ a = b;
1746 \\}
1747 \\
1748 );
1749}
1750
1751test "zig fmt: ptr deref operator and unwrap optional operator" {
1752 try testCanonical(
1753 \\const a = b.*;
1754 \\const a = b.?;
1755 \\
1756 );
1757}
1758
1759test "zig fmt: comment after if before another if" {
1760 try testCanonical(
1761 \\test "aoeu" {
1762 \\ // comment
1763 \\ if (x) {
1764 \\ bar();
1765 \\ }
1766 \\}
1767 \\
1768 \\test "aoeu" {
1769 \\ if (x) {
1770 \\ foo();
1771 \\ }
1772 \\ // comment
1773 \\ if (x) {
1774 \\ bar();
1775 \\ }
1776 \\}
1777 \\
1778 );
1779}
1780
1781test "zig fmt: line comment between if block and else keyword" {
1782 try testCanonical(
1783 \\test "aoeu" {
1784 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
1785 \\ if ((hx & 0x7fffffff) != 0x7f800000) {
1786 \\ return Complex(f32).new(y - y, y - y);
1787 \\ }
1788 \\ // cexp(-inf +- i inf|nan) = 0 + i0
1789 \\ else if (hx & 0x80000000 != 0) {
1790 \\ return Complex(f32).new(0, 0);
1791 \\ }
1792 \\ // cexp(+inf +- i inf|nan) = inf + i nan
1793 \\ // another comment
1794 \\ else {
1795 \\ return Complex(f32).new(x, y - y);
1796 \\ }
1797 \\}
1798 \\
1799 );
1800}
1801
1802test "zig fmt: same line comments in expression" {
1803 try testCanonical(
1804 \\test "aoeu" {
1805 \\ const x = ( // a
1806 \\ 0 // b
1807 \\ ); // c
1808 \\}
1809 \\
1810 );
1811}
1812
1813test "zig fmt: add comma on last switch prong" {
1814 try testTransform(
1815 \\test "aoeu" {
1816 \\switch (self.init_arg_expr) {
1817 \\ InitArg.Type => |t| { },
1818 \\ InitArg.None,
1819 \\ InitArg.Enum => { }
1820 \\}
1821 \\ switch (self.init_arg_expr) {
1822 \\ InitArg.Type => |t| { },
1823 \\ InitArg.None,
1824 \\ InitArg.Enum => { }//line comment
1825 \\ }
1826 \\}
1827 ,
1828 \\test "aoeu" {
1829 \\ switch (self.init_arg_expr) {
1830 \\ InitArg.Type => |t| {},
1831 \\ InitArg.None, InitArg.Enum => {},
1832 \\ }
1833 \\ switch (self.init_arg_expr) {
1834 \\ InitArg.Type => |t| {},
1835 \\ InitArg.None, InitArg.Enum => {}, //line comment
1836 \\ }
1837 \\}
1838 \\
1839 );
1840}
1841
1842test "zig fmt: same-line comment after a statement" {
1843 try testCanonical(
1844 \\test "" {
1845 \\ a = b;
1846 \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
1847 \\ a = b;
1848 \\}
1849 \\
1850 );
1851}
1852
1853test "zig fmt: same-line comment after var decl in struct" {
1854 try testCanonical(
1855 \\pub const vfs_cap_data = extern struct {
1856 \\ const Data = struct {}; // when on disk.
1857 \\};
1858 \\
1859 );
1860}
1861
1862test "zig fmt: same-line comment after field decl" {
1863 try testCanonical(
1864 \\pub const dirent = extern struct {
1865 \\ d_name: u8,
1866 \\ d_name: u8, // comment 1
1867 \\ d_name: u8,
1868 \\ d_name: u8, // comment 2
1869 \\ d_name: u8,
1870 \\};
1871 \\
1872 );
1873}
1874
1875test "zig fmt: same-line comment after switch prong" {
1876 try testCanonical(
1877 \\test "" {
1878 \\ switch (err) {
1879 \\ error.PathAlreadyExists => {}, // comment 2
1880 \\ else => return err, // comment 1
1881 \\ }
1882 \\}
1883 \\
1884 );
1885}
1886
1887test "zig fmt: same-line comment after non-block if expression" {
1888 try testCanonical(
1889 \\comptime {
1890 \\ if (sr > n_uword_bits - 1) // d > r
1891 \\ return 0;
1892 \\}
1893 \\
1894 );
1895}
1896
1897test "zig fmt: same-line comment on comptime expression" {
1898 try testCanonical(
1899 \\test "" {
1900 \\ comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt
1901 \\}
1902 \\
1903 );
1904}
1905
1906test "zig fmt: switch with empty body" {
1907 try testCanonical(
1908 \\test "" {
1909 \\ foo() catch |err| switch (err) {};
1910 \\}
1911 \\
1912 );
1913}
1914
1915test "zig fmt: line comments in struct initializer" {
1916 try testCanonical(
1917 \\fn foo() void {
1918 \\ return Self{
1919 \\ .a = b,
1920 \\
1921 \\ // Initialize these two fields to buffer_size so that
1922 \\ // in `readFn` we treat the state as being able to read
1923 \\ .start_index = buffer_size,
1924 \\ .end_index = buffer_size,
1925 \\
1926 \\ // middle
1927 \\
1928 \\ .a = b,
1929 \\
1930 \\ // end
1931 \\ };
1932 \\}
1933 \\
1934 );
1935}
1936
1937test "zig fmt: first line comment in struct initializer" {
1938 try testCanonical(
1939 \\pub fn acquire(self: *Self) HeldLock {
1940 \\ return HeldLock{
1941 \\ // guaranteed allocation elision
1942 \\ .held = self.lock.acquire(),
1943 \\ .value = &self.private_data,
1944 \\ };
1945 \\}
1946 \\
1947 );
1948}
1949
1950test "zig fmt: doc comments before struct field" {
1951 try testCanonical(
1952 \\pub const Allocator = struct {
1953 \\ /// Allocate byte_count bytes and return them in a slice, with the
1954 \\ /// slice's pointer aligned at least to alignment bytes.
1955 \\ allocFn: fn () void,
1956 \\};
1957 \\
1958 );
1959}
1960
1961test "zig fmt: error set declaration" {
1962 try testCanonical(
1963 \\const E = error{
1964 \\ A,
1965 \\ B,
1966 \\
1967 \\ C,
1968 \\};
1969 \\
1970 \\const Error = error{
1971 \\ /// no more memory
1972 \\ OutOfMemory,
1973 \\};
1974 \\
1975 \\const Error = error{
1976 \\ /// no more memory
1977 \\ OutOfMemory,
1978 \\
1979 \\ /// another
1980 \\ Another,
1981 \\
1982 \\ // end
1983 \\};
1984 \\
1985 \\const Error = error{OutOfMemory};
1986 \\const Error = error{};
1987 \\
1988 \\const Error = error{ OutOfMemory, OutOfTime };
1989 \\
1990 );
1991}
1992
1993test "zig fmt: union(enum(u32)) with assigned enum values" {
1994 try testCanonical(
1995 \\const MultipleChoice = union(enum(u32)) {
1996 \\ A = 20,
1997 \\ B = 40,
1998 \\ C = 60,
1999 \\ D = 1000,
2000 \\};
2001 \\
2002 );
2003}
2004
2005test "zig fmt: resume from suspend block" {
2006 try testCanonical(
2007 \\fn foo() void {
2008 \\ suspend {
2009 \\ resume @frame();
2010 \\ }
2011 \\}
2012 \\
2013 );
2014}
2015
2016test "zig fmt: comments before error set decl" {
2017 try testCanonical(
2018 \\const UnexpectedError = error{
2019 \\ /// The Operating System returned an undocumented error code.
2020 \\ Unexpected,
2021 \\ // another
2022 \\ Another,
2023 \\
2024 \\ // in between
2025 \\
2026 \\ // at end
2027 \\};
2028 \\
2029 );
2030}
2031
2032test "zig fmt: comments before switch prong" {
2033 try testCanonical(
2034 \\test "" {
2035 \\ switch (err) {
2036 \\ error.PathAlreadyExists => continue,
2037 \\
2038 \\ // comment 1
2039 \\
2040 \\ // comment 2
2041 \\ else => return err,
2042 \\ // at end
2043 \\ }
2044 \\}
2045 \\
2046 );
2047}
2048
2049test "zig fmt: comments before var decl in struct" {
2050 try testCanonical(
2051 \\pub const vfs_cap_data = extern struct {
2052 \\ // All of these are mandated as little endian
2053 \\ // when on disk.
2054 \\ const Data = struct {
2055 \\ permitted: u32,
2056 \\ inheritable: u32,
2057 \\ };
2058 \\
2059 \\ // in between
2060 \\
2061 \\ /// All of these are mandated as little endian
2062 \\ /// when on disk.
2063 \\ const Data = struct {
2064 \\ permitted: u32,
2065 \\ inheritable: u32,
2066 \\ };
2067 \\
2068 \\ // at end
2069 \\};
2070 \\
2071 );
2072}
2073
2074test "zig fmt: array literal with 1 item on 1 line" {
2075 try testCanonical(
2076 \\var s = []const u64{0} ** 25;
2077 \\
2078 );
2079}
2080
2081test "zig fmt: comments before global variables" {
2082 try testCanonical(
2083 \\/// Foo copies keys and values before they go into the map, and
2084 \\/// frees them when they get removed.
2085 \\pub const Foo = struct {};
2086 \\
2087 );
2088}
2089
2090test "zig fmt: comments in statements" {
2091 try testCanonical(
2092 \\test "std" {
2093 \\ // statement comment
2094 \\ _ = @import("foo/bar.zig");
2095 \\
2096 \\ // middle
2097 \\ // middle2
2098 \\
2099 \\ // end
2100 \\}
2101 \\
2102 );
2103}
2104
2105test "zig fmt: comments before test decl" {
2106 try testCanonical(
2107 \\/// top level doc comment
2108 \\test "hi" {}
2109 \\
2110 \\// top level normal comment
2111 \\test "hi" {}
2112 \\
2113 \\// middle
2114 \\
2115 \\// end
2116 \\
2117 );
2118}
2119
2120test "zig fmt: preserve spacing" {
2121 try testCanonical(
2122 \\const std = @import("std");
2123 \\
2124 \\pub fn main() !void {
2125 \\ var stdout_file = std.io.getStdOut;
2126 \\ var stdout_file = std.io.getStdOut;
2127 \\
2128 \\ var stdout_file = std.io.getStdOut;
2129 \\ var stdout_file = std.io.getStdOut;
2130 \\}
2131 \\
2132 );
2133}
2134
2135test "zig fmt: return types" {
2136 try testCanonical(
2137 \\pub fn main() !void {}
2138 \\pub fn main() anytype {}
2139 \\pub fn main() i32 {}
2140 \\
2141 );
2142}
2143
2144test "zig fmt: imports" {
2145 try testCanonical(
2146 \\const std = @import("std");
2147 \\const std = @import();
2148 \\
2149 );
2150}
2151
2152test "zig fmt: global declarations" {
2153 try testCanonical(
2154 \\const a = b;
2155 \\pub const a = b;
2156 \\var a = b;
2157 \\pub var a = b;
2158 \\const a: i32 = b;
2159 \\pub const a: i32 = b;
2160 \\var a: i32 = b;
2161 \\pub var a: i32 = b;
2162 \\extern const a: i32 = b;
2163 \\pub extern const a: i32 = b;
2164 \\extern var a: i32 = b;
2165 \\pub extern var a: i32 = b;
2166 \\extern "a" const a: i32 = b;
2167 \\pub extern "a" const a: i32 = b;
2168 \\extern "a" var a: i32 = b;
2169 \\pub extern "a" var a: i32 = b;
2170 \\
2171 );
2172}
2173
2174test "zig fmt: extern declaration" {
2175 try testCanonical(
2176 \\extern var foo: c_int;
2177 \\
2178 );
2179}
2180
2181test "zig fmt: alignment" {
2182 try testCanonical(
2183 \\var foo: c_int align(1);
2184 \\
2185 );
2186}
2187
2188test "zig fmt: C main" {
2189 try testCanonical(
2190 \\fn main(argc: c_int, argv: **u8) c_int {
2191 \\ const a = b;
2192 \\}
2193 \\
2194 );
2195}
2196
2197test "zig fmt: return" {
2198 try testCanonical(
2199 \\fn foo(argc: c_int, argv: **u8) c_int {
2200 \\ return 0;
2201 \\}
2202 \\
2203 \\fn bar() void {
2204 \\ return;
2205 \\}
2206 \\
2207 );
2208}
2209
2210test "zig fmt: pointer attributes" {
2211 try testCanonical(
2212 \\extern fn f1(s: *align(*u8) u8) c_int;
2213 \\extern fn f2(s: **align(1) *const *volatile u8) c_int;
2214 \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
2215 \\extern fn f4(s: *align(1) const volatile u8) c_int;
2216 \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int;
2217 \\
2218 );
2219}
2220
2221test "zig fmt: slice attributes" {
2222 try testCanonical(
2223 \\extern fn f1(s: *align(*u8) u8) c_int;
2224 \\extern fn f2(s: **align(1) *const *volatile u8) c_int;
2225 \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
2226 \\extern fn f4(s: *align(1) const volatile u8) c_int;
2227 \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int;
2228 \\
2229 );
2230}
2231
2232test "zig fmt: test declaration" {
2233 try testCanonical(
2234 \\test "test name" {
2235 \\ const a = 1;
2236 \\ var b = 1;
2237 \\}
2238 \\
2239 );
2240}
2241
2242test "zig fmt: infix operators" {
2243 try testCanonical(
2244 \\test "infix operators" {
2245 \\ var i = undefined;
2246 \\ i = 2;
2247 \\ i *= 2;
2248 \\ i |= 2;
2249 \\ i ^= 2;
2250 \\ i <<= 2;
2251 \\ i >>= 2;
2252 \\ i &= 2;
2253 \\ i *= 2;
2254 \\ i *%= 2;
2255 \\ i -= 2;
2256 \\ i -%= 2;
2257 \\ i += 2;
2258 \\ i +%= 2;
2259 \\ i /= 2;
2260 \\ i %= 2;
2261 \\ _ = i == i;
2262 \\ _ = i != i;
2263 \\ _ = i != i;
2264 \\ _ = i.i;
2265 \\ _ = i || i;
2266 \\ _ = i!i;
2267 \\ _ = i ** i;
2268 \\ _ = i ++ i;
2269 \\ _ = i orelse i;
2270 \\ _ = i % i;
2271 \\ _ = i / i;
2272 \\ _ = i *% i;
2273 \\ _ = i * i;
2274 \\ _ = i -% i;
2275 \\ _ = i - i;
2276 \\ _ = i +% i;
2277 \\ _ = i + i;
2278 \\ _ = i << i;
2279 \\ _ = i >> i;
2280 \\ _ = i & i;
2281 \\ _ = i ^ i;
2282 \\ _ = i | i;
2283 \\ _ = i >= i;
2284 \\ _ = i <= i;
2285 \\ _ = i > i;
2286 \\ _ = i < i;
2287 \\ _ = i and i;
2288 \\ _ = i or i;
2289 \\}
2290 \\
2291 );
2292}
2293
2294test "zig fmt: precedence" {
2295 try testCanonical(
2296 \\test "precedence" {
2297 \\ a!b();
2298 \\ (a!b)();
2299 \\ !a!b;
2300 \\ !(a!b);
2301 \\ !a{};
2302 \\ !(a{});
2303 \\ a + b{};
2304 \\ (a + b){};
2305 \\ a << b + c;
2306 \\ (a << b) + c;
2307 \\ a & b << c;
2308 \\ (a & b) << c;
2309 \\ a ^ b & c;
2310 \\ (a ^ b) & c;
2311 \\ a | b ^ c;
2312 \\ (a | b) ^ c;
2313 \\ a == b | c;
2314 \\ (a == b) | c;
2315 \\ a and b == c;
2316 \\ (a and b) == c;
2317 \\ a or b and c;
2318 \\ (a or b) and c;
2319 \\ (a or b) and c;
2320 \\}
2321 \\
2322 );
2323}
2324
2325test "zig fmt: prefix operators" {
2326 try testCanonical(
2327 \\test "prefix operators" {
2328 \\ try return --%~!&0;
2329 \\}
2330 \\
2331 );
2332}
2333
2334test "zig fmt: call expression" {
2335 try testCanonical(
2336 \\test "test calls" {
2337 \\ a();
2338 \\ a(1);
2339 \\ a(1, 2);
2340 \\ a(1, 2) + a(1, 2);
2341 \\}
2342 \\
2343 );
2344}
2345
2346test "zig fmt: anytype type" {
2347 try testCanonical(
2348 \\fn print(args: anytype) anytype {}
2349 \\
2350 );
2351}
2352
2353test "zig fmt: functions" {
2354 try testCanonical(
2355 \\extern fn puts(s: *const u8) c_int;
2356 \\extern "c" fn puts(s: *const u8) c_int;
2357 \\export fn puts(s: *const u8) c_int;
2358 \\inline fn puts(s: *const u8) c_int;
2359 \\noinline fn puts(s: *const u8) c_int;
2360 \\pub extern fn puts(s: *const u8) c_int;
2361 \\pub extern "c" fn puts(s: *const u8) c_int;
2362 \\pub export fn puts(s: *const u8) c_int;
2363 \\pub inline fn puts(s: *const u8) c_int;
2364 \\pub noinline fn puts(s: *const u8) c_int;
2365 \\pub extern fn puts(s: *const u8) align(2 + 2) c_int;
2366 \\pub extern "c" fn puts(s: *const u8) align(2 + 2) c_int;
2367 \\pub export fn puts(s: *const u8) align(2 + 2) c_int;
2368 \\pub inline fn puts(s: *const u8) align(2 + 2) c_int;
2369 \\pub noinline fn puts(s: *const u8) align(2 + 2) c_int;
2370 \\
2371 );
2372}
2373
2374test "zig fmt: multiline string" {
2375 try testCanonical(
2376 \\test "" {
2377 \\ const s1 =
2378 \\ \\one
2379 \\ \\two)
2380 \\ \\three
2381 \\ ;
2382 \\ const s3 = // hi
2383 \\ \\one
2384 \\ \\two)
2385 \\ \\three
2386 \\ ;
2387 \\}
2388 \\
2389 );
2390}
2391
2392test "zig fmt: values" {
2393 try testCanonical(
2394 \\test "values" {
2395 \\ 1;
2396 \\ 1.0;
2397 \\ "string";
2398 \\ 'c';
2399 \\ true;
2400 \\ false;
2401 \\ null;
2402 \\ undefined;
2403 \\ anyerror;
2404 \\ this;
2405 \\ unreachable;
2406 \\}
2407 \\
2408 );
2409}
2410
2411test "zig fmt: indexing" {
2412 try testCanonical(
2413 \\test "test index" {
2414 \\ a[0];
2415 \\ a[0 + 5];
2416 \\ a[0..];
2417 \\ a[0..5];
2418 \\ a[a[0]];
2419 \\ a[a[0..]];
2420 \\ a[a[0..5]];
2421 \\ a[a[0]..];
2422 \\ a[a[0..5]..];
2423 \\ a[a[0]..a[0]];
2424 \\ a[a[0..5]..a[0]];
2425 \\ a[a[0..5]..a[0..5]];
2426 \\}
2427 \\
2428 );
2429}
2430
2431test "zig fmt: struct declaration" {
2432 try testCanonical(
2433 \\const S = struct {
2434 \\ const Self = @This();
2435 \\ f1: u8,
2436 \\ f3: u8,
2437 \\
2438 \\ f2: u8,
2439 \\
2440 \\ fn method(self: *Self) Self {
2441 \\ return self.*;
2442 \\ }
2443 \\};
2444 \\
2445 \\const Ps = packed struct {
2446 \\ a: u8,
2447 \\ b: u8,
2448 \\
2449 \\ c: u8,
2450 \\};
2451 \\
2452 \\const Es = extern struct {
2453 \\ a: u8,
2454 \\ b: u8,
2455 \\
2456 \\ c: u8,
2457 \\};
2458 \\
2459 );
2460}
2461
2462test "zig fmt: enum declaration" {
2463 try testCanonical(
2464 \\const E = enum {
2465 \\ Ok,
2466 \\ SomethingElse = 0,
2467 \\};
2468 \\
2469 \\const E2 = enum(u8) {
2470 \\ Ok,
2471 \\ SomethingElse = 255,
2472 \\ SomethingThird,
2473 \\};
2474 \\
2475 \\const Ee = extern enum {
2476 \\ Ok,
2477 \\ SomethingElse,
2478 \\ SomethingThird,
2479 \\};
2480 \\
2481 \\const Ep = packed enum {
2482 \\ Ok,
2483 \\ SomethingElse,
2484 \\ SomethingThird,
2485 \\};
2486 \\
2487 );
2488}
2489
2490test "zig fmt: union declaration" {
2491 try testCanonical(
2492 \\const U = union {
2493 \\ Int: u8,
2494 \\ Float: f32,
2495 \\ None,
2496 \\ Bool: bool,
2497 \\};
2498 \\
2499 \\const Ue = union(enum) {
2500 \\ Int: u8,
2501 \\ Float: f32,
2502 \\ None,
2503 \\ Bool: bool,
2504 \\};
2505 \\
2506 \\const E = enum {
2507 \\ Int,
2508 \\ Float,
2509 \\ None,
2510 \\ Bool,
2511 \\};
2512 \\
2513 \\const Ue2 = union(E) {
2514 \\ Int: u8,
2515 \\ Float: f32,
2516 \\ None,
2517 \\ Bool: bool,
2518 \\};
2519 \\
2520 \\const Eu = extern union {
2521 \\ Int: u8,
2522 \\ Float: f32,
2523 \\ None,
2524 \\ Bool: bool,
2525 \\};
2526 \\
2527 );
2528}
2529
2530test "zig fmt: arrays" {
2531 try testCanonical(
2532 \\test "test array" {
2533 \\ const a: [2]u8 = [2]u8{
2534 \\ 1,
2535 \\ 2,
2536 \\ };
2537 \\ const a: [2]u8 = []u8{
2538 \\ 1,
2539 \\ 2,
2540 \\ };
2541 \\ const a: [0]u8 = []u8{};
2542 \\ const x: [4:0]u8 = undefined;
2543 \\}
2544 \\
2545 );
2546}
2547
2548test "zig fmt: container initializers" {
2549 try testCanonical(
2550 \\const a0 = []u8{};
2551 \\const a1 = []u8{1};
2552 \\const a2 = []u8{
2553 \\ 1,
2554 \\ 2,
2555 \\ 3,
2556 \\ 4,
2557 \\};
2558 \\const s0 = S{};
2559 \\const s1 = S{ .a = 1 };
2560 \\const s2 = S{
2561 \\ .a = 1,
2562 \\ .b = 2,
2563 \\};
2564 \\
2565 );
2566}
2567
2568test "zig fmt: catch" {
2569 try testCanonical(
2570 \\test "catch" {
2571 \\ const a: anyerror!u8 = 0;
2572 \\ _ = a catch return;
2573 \\ _ = a catch |err| return;
2574 \\}
2575 \\
2576 );
2577}
2578
2579test "zig fmt: blocks" {
2580 try testCanonical(
2581 \\test "blocks" {
2582 \\ {
2583 \\ const a = 0;
2584 \\ const b = 0;
2585 \\ }
2586 \\
2587 \\ blk: {
2588 \\ const a = 0;
2589 \\ const b = 0;
2590 \\ }
2591 \\
2592 \\ const r = blk: {
2593 \\ const a = 0;
2594 \\ const b = 0;
2595 \\ };
2596 \\}
2597 \\
2598 );
2599}
2600
2601test "zig fmt: switch" {
2602 try testCanonical(
2603 \\test "switch" {
2604 \\ switch (0) {
2605 \\ 0 => {},
2606 \\ 1 => unreachable,
2607 \\ 2, 3 => {},
2608 \\ 4...7 => {},
2609 \\ 1 + 4 * 3 + 22 => {},
2610 \\ else => {
2611 \\ const a = 1;
2612 \\ const b = a;
2613 \\ },
2614 \\ }
2615 \\
2616 \\ const res = switch (0) {
2617 \\ 0 => 0,
2618 \\ 1 => 2,
2619 \\ 1 => a = 4,
2620 \\ else => 4,
2621 \\ };
2622 \\
2623 \\ const Union = union(enum) {
2624 \\ Int: i64,
2625 \\ Float: f64,
2626 \\ };
2627 \\
2628 \\ switch (u) {
2629 \\ Union.Int => |int| {},
2630 \\ Union.Float => |*float| unreachable,
2631 \\ }
2632 \\}
2633 \\
2634 );
2635}
2636
2637test "zig fmt: while" {
2638 try testCanonical(
2639 \\test "while" {
2640 \\ while (10 < 1) unreachable;
2641 \\
2642 \\ while (10 < 1) unreachable else unreachable;
2643 \\
2644 \\ while (10 < 1) {
2645 \\ unreachable;
2646 \\ }
2647 \\
2648 \\ while (10 < 1)
2649 \\ unreachable;
2650 \\
2651 \\ var i: usize = 0;
2652 \\ while (i < 10) : (i += 1) {
2653 \\ continue;
2654 \\ }
2655 \\
2656 \\ i = 0;
2657 \\ while (i < 10) : (i += 1)
2658 \\ continue;
2659 \\
2660 \\ i = 0;
2661 \\ var j: usize = 0;
2662 \\ while (i < 10) : ({
2663 \\ i += 1;
2664 \\ j += 1;
2665 \\ }) {
2666 \\ continue;
2667 \\ }
2668 \\
2669 \\ var a: ?u8 = 2;
2670 \\ while (a) |v| : (a = null) {
2671 \\ continue;
2672 \\ }
2673 \\
2674 \\ while (a) |v| : (a = null)
2675 \\ unreachable;
2676 \\
2677 \\ label: while (10 < 0) {
2678 \\ unreachable;
2679 \\ }
2680 \\
2681 \\ const res = while (0 < 10) {
2682 \\ break 7;
2683 \\ } else {
2684 \\ unreachable;
2685 \\ };
2686 \\
2687 \\ const res = while (0 < 10)
2688 \\ break 7
2689 \\ else
2690 \\ unreachable;
2691 \\
2692 \\ var a: anyerror!u8 = 0;
2693 \\ while (a) |v| {
2694 \\ a = error.Err;
2695 \\ } else |err| {
2696 \\ i = 1;
2697 \\ }
2698 \\
2699 \\ comptime var k: usize = 0;
2700 \\ inline while (i < 10) : (i += 1)
2701 \\ j += 2;
2702 \\}
2703 \\
2704 );
2705}
2706
2707test "zig fmt: for" {
2708 try testCanonical(
2709 \\test "for" {
2710 \\ for (a) |v| {
2711 \\ continue;
2712 \\ }
2713 \\
2714 \\ for (a) |v| continue;
2715 \\
2716 \\ for (a) |v| continue else return;
2717 \\
2718 \\ for (a) |v| {
2719 \\ continue;
2720 \\ } else return;
2721 \\
2722 \\ for (a) |v| continue else {
2723 \\ return;
2724 \\ }
2725 \\
2726 \\ for (a) |v|
2727 \\ continue
2728 \\ else
2729 \\ return;
2730 \\
2731 \\ for (a) |v|
2732 \\ continue;
2733 \\
2734 \\ for (a) |*v|
2735 \\ continue;
2736 \\
2737 \\ for (a) |v, i| {
2738 \\ continue;
2739 \\ }
2740 \\
2741 \\ for (a) |v, i|
2742 \\ continue;
2743 \\
2744 \\ for (a) |b| switch (b) {
2745 \\ c => {},
2746 \\ d => {},
2747 \\ };
2748 \\
2749 \\ for (a) |b|
2750 \\ switch (b) {
2751 \\ c => {},
2752 \\ d => {},
2753 \\ };
2754 \\
2755 \\ const res = for (a) |v, i| {
2756 \\ break v;
2757 \\ } else {
2758 \\ unreachable;
2759 \\ };
2760 \\
2761 \\ var num: usize = 0;
2762 \\ inline for (a) |v, i| {
2763 \\ num += v;
2764 \\ num += i;
2765 \\ }
2766 \\}
2767 \\
2768 );
2769
2770 try testTransform(
2771 \\test "fix for" {
2772 \\ for (a) |x|
2773 \\ f(x) else continue;
2774 \\}
2775 \\
2776 ,
2777 \\test "fix for" {
2778 \\ for (a) |x|
2779 \\ f(x)
2780 \\ else continue;
2781 \\}
2782 \\
2783 );
2784}
2785
2786test "zig fmt: if" {
2787 try testCanonical(
2788 \\test "if" {
2789 \\ if (10 < 0) {
2790 \\ unreachable;
2791 \\ }
2792 \\
2793 \\ if (10 < 0) unreachable;
2794 \\
2795 \\ if (10 < 0) {
2796 \\ unreachable;
2797 \\ } else {
2798 \\ const a = 20;
2799 \\ }
2800 \\
2801 \\ if (10 < 0) {
2802 \\ unreachable;
2803 \\ } else if (5 < 0) {
2804 \\ unreachable;
2805 \\ } else {
2806 \\ const a = 20;
2807 \\ }
2808 \\
2809 \\ const is_world_broken = if (10 < 0) true else false;
2810 \\ const some_number = 1 + if (10 < 0) 2 else 3;
2811 \\
2812 \\ const a: ?u8 = 10;
2813 \\ const b: ?u8 = null;
2814 \\ if (a) |v| {
2815 \\ const some = v;
2816 \\ } else if (b) |*v| {
2817 \\ unreachable;
2818 \\ } else {
2819 \\ const some = 10;
2820 \\ }
2821 \\
2822 \\ const non_null_a = if (a) |v| v else 0;
2823 \\
2824 \\ const a_err: anyerror!u8 = 0;
2825 \\ if (a_err) |v| {
2826 \\ const p = v;
2827 \\ } else |err| {
2828 \\ unreachable;
2829 \\ }
2830 \\}
2831 \\
2832 );
2833}
2834
2835test "zig fmt: defer" {
2836 try testCanonical(
2837 \\test "defer" {
2838 \\ var i: usize = 0;
2839 \\ defer i = 1;
2840 \\ defer {
2841 \\ i += 2;
2842 \\ i *= i;
2843 \\ }
2844 \\
2845 \\ errdefer i += 3;
2846 \\ errdefer {
2847 \\ i += 2;
2848 \\ i /= i;
2849 \\ }
2850 \\}
2851 \\
2852 );
2853}
2854
2855test "zig fmt: comptime" {
2856 try testCanonical(
2857 \\fn a() u8 {
2858 \\ return 5;
2859 \\}
2860 \\
2861 \\fn b(comptime i: u8) u8 {
2862 \\ return i;
2863 \\}
2864 \\
2865 \\const av = comptime a();
2866 \\const av2 = comptime blk: {
2867 \\ var res = a();
2868 \\ res *= b(2);
2869 \\ break :blk res;
2870 \\};
2871 \\
2872 \\comptime {
2873 \\ _ = a();
2874 \\}
2875 \\
2876 \\test "comptime" {
2877 \\ const av3 = comptime a();
2878 \\ const av4 = comptime blk: {
2879 \\ var res = a();
2880 \\ res *= a();
2881 \\ break :blk res;
2882 \\ };
2883 \\
2884 \\ comptime var i = 0;
2885 \\ comptime {
2886 \\ i = a();
2887 \\ i += b(i);
2888 \\ }
2889 \\}
2890 \\
2891 );
2892}
2893
2894test "zig fmt: fn type" {
2895 try testCanonical(
2896 \\fn a(i: u8) u8 {
2897 \\ return i + 1;
2898 \\}
2899 \\
2900 \\const a: fn (u8) u8 = undefined;
2901 \\const b: fn (u8) callconv(.Naked) u8 = undefined;
2902 \\const ap: fn (u8) u8 = a;
2903 \\
2904 );
2905}
2906
2907test "zig fmt: inline asm" {
2908 try testCanonical(
2909 \\pub fn syscall1(number: usize, arg1: usize) usize {
2910 \\ return asm volatile ("syscall"
2911 \\ : [ret] "={rax}" (-> usize)
2912 \\ : [number] "{rax}" (number),
2913 \\ [arg1] "{rdi}" (arg1)
2914 \\ : "rcx", "r11"
2915 \\ );
2916 \\}
2917 \\
2918 );
2919}
2920
2921test "zig fmt: async functions" {
2922 try testCanonical(
2923 \\fn simpleAsyncFn() void {
2924 \\ const a = async a.b();
2925 \\ x += 1;
2926 \\ suspend;
2927 \\ x += 1;
2928 \\ suspend;
2929 \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable;
2930 \\ await p;
2931 \\}
2932 \\
2933 \\test "suspend, resume, await" {
2934 \\ const p: anyframe = async testAsyncSeq();
2935 \\ resume p;
2936 \\ await p;
2937 \\}
2938 \\
2939 );
2940}
2941
2942test "zig fmt: nosuspend" {
2943 try testCanonical(
2944 \\const a = nosuspend foo();
2945 \\
2946 );
2947}
2948
2949test "zig fmt: Block after if" {
2950 try testCanonical(
2951 \\test "Block after if" {
2952 \\ if (true) {
2953 \\ const a = 0;
2954 \\ }
2955 \\
2956 \\ {
2957 \\ const a = 0;
2958 \\ }
2959 \\}
2960 \\
2961 );
2962}
2963
2964test "zig fmt: use" {
2965 try testCanonical(
2966 \\usingnamespace @import("std");
2967 \\pub usingnamespace @import("std");
2968 \\
2969 );
2970}
2971
2972test "zig fmt: string identifier" {
2973 try testCanonical(
2974 \\const @"a b" = @"c d".@"e f";
2975 \\fn @"g h"() void {}
2976 \\
2977 );
2978}
2979
2980test "zig fmt: error return" {
2981 try testCanonical(
2982 \\fn err() anyerror {
2983 \\ call();
2984 \\ return error.InvalidArgs;
2985 \\}
2986 \\
2987 );
2988}
2989
2990test "zig fmt: comptime block in container" {
2991 try testCanonical(
2992 \\pub fn container() type {
2993 \\ return struct {
2994 \\ comptime {
2995 \\ if (false) {
2996 \\ unreachable;
2997 \\ }
2998 \\ }
2999 \\ };
3000 \\}
3001 \\
3002 );
3003}
3004
3005test "zig fmt: inline asm parameter alignment" {
3006 try testCanonical(
3007 \\pub fn main() void {
3008 \\ asm volatile (
3009 \\ \\ foo
3010 \\ \\ bar
3011 \\ );
3012 \\ asm volatile (
3013 \\ \\ foo
3014 \\ \\ bar
3015 \\ : [_] "" (-> usize),
3016 \\ [_] "" (-> usize)
3017 \\ );
3018 \\ asm volatile (
3019 \\ \\ foo
3020 \\ \\ bar
3021 \\ :
3022 \\ : [_] "" (0),
3023 \\ [_] "" (0)
3024 \\ );
3025 \\ asm volatile (
3026 \\ \\ foo
3027 \\ \\ bar
3028 \\ :
3029 \\ :
3030 \\ : "", ""
3031 \\ );
3032 \\ asm volatile (
3033 \\ \\ foo
3034 \\ \\ bar
3035 \\ : [_] "" (-> usize),
3036 \\ [_] "" (-> usize)
3037 \\ : [_] "" (0),
3038 \\ [_] "" (0)
3039 \\ : "", ""
3040 \\ );
3041 \\}
3042 \\
3043 );
3044}
3045
3046test "zig fmt: multiline string in array" {
3047 try testCanonical(
3048 \\const Foo = [][]const u8{
3049 \\ \\aaa
3050 \\ ,
3051 \\ \\bbb
3052 \\};
3053 \\
3054 \\fn bar() void {
3055 \\ const Foo = [][]const u8{
3056 \\ \\aaa
3057 \\ ,
3058 \\ \\bbb
3059 \\ };
3060 \\ const Bar = [][]const u8{ // comment here
3061 \\ \\aaa
3062 \\ \\
3063 \\ , // and another comment can go here
3064 \\ \\bbb
3065 \\ };
3066 \\}
3067 \\
3068 );
3069}
3070
3071test "zig fmt: if type expr" {
3072 try testCanonical(
3073 \\const mycond = true;
3074 \\pub fn foo() if (mycond) i32 else void {
3075 \\ if (mycond) {
3076 \\ return 42;
3077 \\ }
3078 \\}
3079 \\
3080 );
3081}
3082test "zig fmt: file ends with struct field" {
3083 try testCanonical(
3084 \\a: bool
3085 \\
3086 );
3087}
3088
3089test "zig fmt: comment after empty comment" {
3090 try testTransform(
3091 \\const x = true; //
3092 \\//
3093 \\//
3094 \\//a
3095 \\
3096 ,
3097 \\const x = true;
3098 \\//a
3099 \\
3100 );
3101}
3102
3103test "zig fmt: line comment in array" {
3104 try testTransform(
3105 \\test "a" {
3106 \\ var arr = [_]u32{
3107 \\ 0
3108 \\ // 1,
3109 \\ // 2,
3110 \\ };
3111 \\}
3112 \\
3113 ,
3114 \\test "a" {
3115 \\ var arr = [_]u32{
3116 \\ 0, // 1,
3117 \\ // 2,
3118 \\ };
3119 \\}
3120 \\
3121 );
3122 try testCanonical(
3123 \\test "a" {
3124 \\ var arr = [_]u32{
3125 \\ 0,
3126 \\ // 1,
3127 \\ // 2,
3128 \\ };
3129 \\}
3130 \\
3131 );
3132}
3133
3134test "zig fmt: comment after params" {
3135 try testTransform(
3136 \\fn a(
3137 \\ b: u32
3138 \\ // c: u32,
3139 \\ // d: u32,
3140 \\) void {}
3141 \\
3142 ,
3143 \\fn a(
3144 \\ b: u32, // c: u32,
3145 \\ // d: u32,
3146 \\) void {}
3147 \\
3148 );
3149 try testCanonical(
3150 \\fn a(
3151 \\ b: u32,
3152 \\ // c: u32,
3153 \\ // d: u32,
3154 \\) void {}
3155 \\
3156 );
3157}
3158
3159test "zig fmt: comment in array initializer/access" {
3160 try testCanonical(
3161 \\test "a" {
3162 \\ var a = x{ //aa
3163 \\ //bb
3164 \\ };
3165 \\ var a = []x{ //aa
3166 \\ //bb
3167 \\ };
3168 \\ var b = [ //aa
3169 \\ _
3170 \\ ]x{ //aa
3171 \\ //bb
3172 \\ 9,
3173 \\ };
3174 \\ var c = b[ //aa
3175 \\ 0
3176 \\ ];
3177 \\ var d = [_
3178 \\ //aa
3179 \\ ]x{ //aa
3180 \\ //bb
3181 \\ 9,
3182 \\ };
3183 \\ var e = d[0
3184 \\ //aa
3185 \\ ];
3186 \\}
3187 \\
3188 );
3189}
3190
3191test "zig fmt: comments at several places in struct init" {
3192 try testTransform(
3193 \\var bar = Bar{
3194 \\ .x = 10, // test
3195 \\ .y = "test"
3196 \\ // test
3197 \\};
3198 \\
3199 ,
3200 \\var bar = Bar{
3201 \\ .x = 10, // test
3202 \\ .y = "test", // test
3203 \\};
3204 \\
3205 );
3206
3207 try testCanonical(
3208 \\var bar = Bar{ // test
3209 \\ .x = 10, // test
3210 \\ .y = "test",
3211 \\ // test
3212 \\};
3213 \\
3214 );
3215}
3216
3217test "zig fmt: top level doc comments" {
3218 try testCanonical(
3219 \\//! tld 1
3220 \\//! tld 2
3221 \\//! tld 3
3222 \\
3223 \\// comment
3224 \\
3225 \\/// A doc
3226 \\const A = struct {
3227 \\ //! A tld 1
3228 \\ //! A tld 2
3229 \\ //! A tld 3
3230 \\};
3231 \\
3232 \\/// B doc
3233 \\const B = struct {
3234 \\ //! B tld 1
3235 \\ //! B tld 2
3236 \\ //! B tld 3
3237 \\
3238 \\ /// b doc
3239 \\ b: u32,
3240 \\};
3241 \\
3242 \\/// C doc
3243 \\const C = struct {
3244 \\ //! C tld 1
3245 \\ //! C tld 2
3246 \\ //! C tld 3
3247 \\
3248 \\ /// c1 doc
3249 \\ c1: u32,
3250 \\
3251 \\ //! C tld 4
3252 \\ //! C tld 5
3253 \\ //! C tld 6
3254 \\
3255 \\ /// c2 doc
3256 \\ c2: u32,
3257 \\};
3258 \\
3259 );
3260 try testCanonical(
3261 \\//! Top-level documentation.
3262 \\
3263 \\/// This is A
3264 \\pub const A = usize;
3265 \\
3266 );
3267 try testCanonical(
3268 \\//! Nothing here
3269 \\
3270 );
3271}
3272
3273test "zig fmt: extern without container keyword returns error" {
3274 try testError(
3275 \\const container = extern {};
3276 \\
3277 , &[_]Error{
3278 .ExpectedExpr,
3279 .ExpectedVarDeclOrFn,
3280 });
3281}
3282
3283test "zig fmt: integer literals with underscore separators" {
3284 try testTransform(
3285 \\const
3286 \\ x =
3287 \\ 1_234_567
3288 \\ +(0b0_1-0o7_0+0xff_FF ) + 0_0;
3289 ,
3290 \\const x =
3291 \\ 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0;
3292 \\
3293 );
3294}
3295
3296test "zig fmt: hex literals with underscore separators" {
3297 try testTransform(
3298 \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 {
3299 \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000;
3300 \\ for (c [ 0_0 .. ]) |_, i| {
3301 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
3302 \\ }
3303 \\ return c;
3304 \\}
3305 \\
3306 \\
3307 ,
3308 \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 {
3309 \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000;
3310 \\ for (c[0_0..]) |_, i| {
3311 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
3312 \\ }
3313 \\ return c;
3314 \\}
3315 \\
3316 );
3317}
3318
3319test "zig fmt: decimal float literals with underscore separators" {
3320 try testTransform(
3321 \\pub fn main() void {
3322 \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4;
3323 \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2;
3324 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
3325 \\}
3326 ,
3327 \\pub fn main() void {
3328 \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4;
3329 \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2;
3330 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
3331 \\}
3332 \\
3333 );
3334}
3335
3336test "zig fmt: hexadeciaml float literals with underscore separators" {
3337 try testTransform(
3338 \\pub fn main() void {
3339 \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16;
3340 \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4;
3341 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
3342 \\}
3343 ,
3344 \\pub fn main() void {
3345 \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16;
3346 \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4;
3347 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
3348 \\}
3349 \\
3350 );
3351}
3352
3353test "zig fmt: convert async fn into callconv(.Async)" {
3354 try testTransform(
3355 \\async fn foo() void {}
3356 ,
3357 \\fn foo() callconv(.Async) void {}
3358 \\
3359 );
3360}
3361
3362test "zig fmt: convert extern fn proto into callconv(.C)" {
3363 try testTransform(
3364 \\extern fn foo0() void {}
3365 \\const foo1 = extern fn () void;
3366 ,
3367 \\extern fn foo0() void {}
3368 \\const foo1 = fn () callconv(.C) void;
3369 \\
3370 );
3371}
3372
3373test "zig fmt: C var args" {
3374 try testCanonical(
3375 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3376 \\
3377 );
3378}
3379
3380test "zig fmt: Only indent multiline string literals in function calls" {
3381 try testCanonical(
3382 \\test "zig fmt:" {
3383 \\ try testTransform(
3384 \\ \\const X = struct {
3385 \\ \\ foo: i32, bar: i8 };
3386 \\ ,
3387 \\ \\const X = struct {
3388 \\ \\ foo: i32, bar: i8
3389 \\ \\};
3390 \\ \\
3391 \\ );
3392 \\}
3393 \\
3394 );
3395}
3396
3397test "zig fmt: Don't add extra newline after if" {
3398 try testCanonical(
3399 \\pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
3400 \\ if (cwd().symLink(existing_path, new_path, .{})) {
3401 \\ return;
3402 \\ }
3403 \\}
3404 \\
3405 );
3406}
3407
3408test "zig fmt: comments in ternary ifs" {
3409 try testCanonical(
3410 \\const x = if (true) {
3411 \\ 1;
3412 \\} else if (false)
3413 \\ // Comment
3414 \\ 0;
3415 \\const y = if (true)
3416 \\ // Comment
3417 \\ 1
3418 \\else
3419 \\ 0;
3420 \\
3421 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3422 \\
3423 );
3424}
3425
3426test "zig fmt: test comments in field access chain" {
3427 try testCanonical(
3428 \\pub const str = struct {
3429 \\ pub const Thing = more.more //
3430 \\ .more() //
3431 \\ .more().more() //
3432 \\ .more() //
3433 \\ // .more() //
3434 \\ .more() //
3435 \\ .more();
3436 \\ data: Data,
3437 \\};
3438 \\
3439 \\pub const str = struct {
3440 \\ pub const Thing = more.more //
3441 \\ .more() //
3442 \\ // .more() //
3443 \\ // .more() //
3444 \\ // .more() //
3445 \\ .more() //
3446 \\ .more();
3447 \\ data: Data,
3448 \\};
3449 \\
3450 \\pub const str = struct {
3451 \\ pub const Thing = more //
3452 \\ .more //
3453 \\ .more() //
3454 \\ .more();
3455 \\ data: Data,
3456 \\};
3457 \\
3458 );
3459}
3460
3461test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" {
3462 try testCanonical(
3463 \\fn foo() void {
3464 \\ z.display_message_dialog(
3465 \\ *const [323:0]u8,
3466 \\ \\Message Text
3467 \\ \\------------
3468 \\ \\xxxxxxxxxxxx
3469 \\ \\xxxxxxxxxxxx
3470 \\ ,
3471 \\ g.GtkMessageType.GTK_MESSAGE_WARNING,
3472 \\ null,
3473 \\ );
3474 \\
3475 \\ z.display_message_dialog(*const [323:0]u8,
3476 \\ \\Message Text
3477 \\ \\------------
3478 \\ \\xxxxxxxxxxxx
3479 \\ \\xxxxxxxxxxxx
3480 \\ , g.GtkMessageType.GTK_MESSAGE_WARNING, null);
3481 \\}
3482 \\
3483 );
3484}
3485
3486test "zig fmt: Control flow statement as body of blockless if" {
3487 try testCanonical(
3488 \\pub fn main() void {
3489 \\ const zoom_node = if (focused_node == layout_first)
3490 \\ if (it.next()) {
3491 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3492 \\ } else null
3493 \\ else
3494 \\ focused_node;
3495 \\
3496 \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
3497 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3498 \\ } else null else
3499 \\ focused_node;
3500 \\
3501 \\ const zoom_node = if (focused_node == layout_first)
3502 \\ if (it.next()) {
3503 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3504 \\ } else null;
3505 \\
3506 \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
3507 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3508 \\ };
3509 \\
3510 \\ const zoom_node = if (focused_node == layout_first) for (nodes) |node| {
3511 \\ break node;
3512 \\ };
3513 \\
3514 \\ const zoom_node = if (focused_node == layout_first) switch (nodes) {
3515 \\ 0 => 0,
3516 \\ } else
3517 \\ focused_node;
3518 \\}
3519 \\
3520 );
3521}
3522
3523test "zig fmt: " {
3524 try testCanonical(
3525 \\pub fn sendViewTags(self: Self) void {
3526 \\ var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
3527 \\ while (it.next()) |node|
3528 \\ view_tags.append(node.view.current_tags) catch {
3529 \\ c.wl_resource_post_no_memory(self.wl_resource);
3530 \\ log.crit(.river_status, "out of memory", .{});
3531 \\ return;
3532 \\ };
3533 \\}
3534 \\
3535 );
3536}
3537
3538test "zig fmt: allow trailing line comments to do manual array formatting" {
3539 try testCanonical(
3540 \\fn foo() void {
3541 \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3542 \\ 0x55, // push rbp
3543 \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3544 \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3545 \\ });
3546 \\
3547 \\ di_buf.appendAssumeCapacity(&[_]u8{
3548 \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header
3549 \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs
3550 \\ DW.AT_low_pc, DW_FORM_addr,
3551 \\ DW.AT_high_pc, DW_FORM_addr,
3552 \\ DW.AT_name, DW_FORM_strp,
3553 \\ DW.AT_comp_dir, DW_FORM_strp,
3554 \\ DW.AT_producer, DW_FORM_strp,
3555 \\ DW.AT_language, DW_FORM_data2,
3556 \\ 0, 0, // sentinel
3557 \\ });
3558 \\
3559 \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3560 \\ 0x55, // push rbp
3561 \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3562 \\ // How do we handle this?
3563 \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3564 \\ // Here's a blank line, should that be allowed?
3565 \\
3566 \\ 0x48, 0x89, 0xe5,
3567 \\ 0x33, 0x45,
3568 \\ // Now the comment breaks a single line -- how do we handle this?
3569 \\ 0x88,
3570 \\ });
3571 \\}
3572 \\
3573 );
3574}
3575
3576test "zig fmt: multiline string literals should play nice with array initializers" {
3577 try testCanonical(
3578 \\fn main() void {
3579 \\ var a = .{.{.{.{.{.{.{.{
3580 \\ 0,
3581 \\ }}}}}}}};
3582 \\ myFunc(.{
3583 \\ "aaaaaaa", "bbbbbb", "ccccc",
3584 \\ "dddd", ("eee"), ("fff"),
3585 \\ ("gggg"),
3586 \\ // Line comment
3587 \\ \\Multiline String Literals can be quite long
3588 \\ ,
3589 \\ \\Multiline String Literals can be quite long
3590 \\ \\Multiline String Literals can be quite long
3591 \\ ,
3592 \\ \\Multiline String Literals can be quite long
3593 \\ \\Multiline String Literals can be quite long
3594 \\ \\Multiline String Literals can be quite long
3595 \\ \\Multiline String Literals can be quite long
3596 \\ ,
3597 \\ (
3598 \\ \\Multiline String Literals can be quite long
3599 \\ ),
3600 \\ .{
3601 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3602 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3603 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3604 \\ },
3605 \\ .{(
3606 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3607 \\ )},
3608 \\ .{
3609 \\ "xxxxxxx", "xxx",
3610 \\ (
3611 \\ \\ xxx
3612 \\ ),
3613 \\ "xxx", "xxx",
3614 \\ },
3615 \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" },
3616 \\ "aaaaaaa", "bbbbbb", "ccccc", // -
3617 \\ "dddd", ("eee"), ("fff"),
3618 \\ .{
3619 \\ "xxx", "xxx",
3620 \\ (
3621 \\ \\ xxx
3622 \\ ),
3623 \\ "xxxxxxxxxxxxxx", "xxx",
3624 \\ },
3625 \\ .{
3626 \\ (
3627 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3628 \\ ),
3629 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3630 \\ },
3631 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3632 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3633 \\ });
3634 \\}
3635 \\
3636 );
3637}
3638
3639test "zig fmt: use of comments and Multiline string literals may force the parameters over multiple lines" {
3640 try testCanonical(
3641 \\pub fn makeMemUndefined(qzz: []u8) i1 {
3642 \\ cases.add( // fixed bug #2032
3643 \\ "compile diagnostic string for top level decl type",
3644 \\ \\export fn entry() void {
3645 \\ \\ var foo: u32 = @This(){};
3646 \\ \\}
3647 \\ , &[_][]const u8{
3648 \\ "tmp.zig:2:27: error: type 'u32' does not support array initialization",
3649 \\ });
3650 \\ @compileError(
3651 \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
3652 \\ \\ Consider providing your own hash function.
3653 \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
3654 \\ \\ Consider providing your own hash function.
3655 \\ );
3656 \\ return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
3657 \\ .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
3658 \\}
3659 \\
3660 \\// This looks like garbage don't do this
3661 \\const rparen = tree.prevToken(
3662 \\// the first token for the annotation expressions is the left
3663 \\// parenthesis, hence the need for two prevToken
3664 \\ if (fn_proto.getAlignExpr()) |align_expr|
3665 \\ tree.prevToken(tree.prevToken(align_expr.firstToken()))
3666 \\else if (fn_proto.getSectionExpr()) |section_expr|
3667 \\ tree.prevToken(tree.prevToken(section_expr.firstToken()))
3668 \\else if (fn_proto.getCallconvExpr()) |callconv_expr|
3669 \\ tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
3670 \\else switch (fn_proto.return_type) {
3671 \\ .Explicit => |node| node.firstToken(),
3672 \\ .InferErrorSet => |node| tree.prevToken(node.firstToken()),
3673 \\ .Invalid => unreachable,
3674 \\});
3675 \\
3676 );
3677}
3678
3679test "zig fmt: single argument trailing commas in @builtins()" {
3680 try testCanonical(
3681 \\pub fn foo(qzz: []u8) i1 {
3682 \\ @panic(
3683 \\ foo,
3684 \\ );
3685 \\ panic(
3686 \\ foo,
3687 \\ );
3688 \\ @panic(
3689 \\ foo,
3690 \\ bar,
3691 \\ );
3692 \\}
3693 \\
3694 );
3695}
3696
3697test "zig fmt: trailing comma should force multiline 1 column" {
3698 try testTransform(
3699 \\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,};
3700 \\
3701 ,
3702 \\pub const UUID_NULL: uuid_t = [16]u8{
3703 \\ 0,
3704 \\ 0,
3705 \\ 0,
3706 \\ 0,
3707 \\};
3708 \\
3709 );
3710}
3711
3712test "zig fmt: function params should align nicely" {
3713 try testCanonical(
3714 \\pub fn foo() void {
3715 \\ cases.addRuntimeSafety("slicing operator with sentinel",
3716 \\ \\const std = @import("std");
3717 \\ ++ check_panic_msg ++
3718 \\ \\pub fn main() void {
3719 \\ \\ var buf = [4]u8{'a','b','c',0};
3720 \\ \\ const slice = buf[0..:0];
3721 \\ \\}
3722 \\ );
3723 \\}
3724 \\
3725 );
3726}
6test "zig fmt: simple top level comptime block" {
7 try testCanonical(
8 \\comptime {}
9 \\
10 );
11}
12
13//test "recovery: top level" {
14// try testError(
15// \\test "" {inline}
16// \\test "" {inline}
17// , &[_]Error{
18// .ExpectedInlinable,
19// .ExpectedInlinable,
20// });
21//}
22//
23//test "recovery: block statements" {
24// try testError(
25// \\test "" {
26// \\ foo + +;
27// \\ inline;
28// \\}
29// , &[_]Error{
30// .InvalidToken,
31// .ExpectedInlinable,
32// });
33//}
34//
35//test "recovery: missing comma" {
36// try testError(
37// \\test "" {
38// \\ switch (foo) {
39// \\ 2 => {}
40// \\ 3 => {}
41// \\ else => {
42// \\ foo && bar +;
43// \\ }
44// \\ }
45// \\}
46// , &[_]Error{
47// .ExpectedToken,
48// .ExpectedToken,
49// .InvalidAnd,
50// .InvalidToken,
51// });
52//}
53//
54//test "recovery: extra qualifier" {
55// try testError(
56// \\const a: *const const u8;
57// \\test ""
58// , &[_]Error{
59// .ExtraConstQualifier,
60// .ExpectedLBrace,
61// });
62//}
63//
64//test "recovery: missing return type" {
65// try testError(
66// \\fn foo() {
67// \\ a && b;
68// \\}
69// \\test ""
70// , &[_]Error{
71// .ExpectedReturnType,
72// .InvalidAnd,
73// .ExpectedLBrace,
74// });
75//}
76//
77//test "recovery: continue after invalid decl" {
78// try testError(
79// \\fn foo {
80// \\ inline;
81// \\}
82// \\pub test "" {
83// \\ async a && b;
84// \\}
85// , &[_]Error{
86// .ExpectedToken,
87// .ExpectedPubItem,
88// .ExpectedParamList,
89// .InvalidAnd,
90// });
91// try testError(
92// \\threadlocal test "" {
93// \\ @a && b;
94// \\}
95// , &[_]Error{
96// .ExpectedVarDecl,
97// .ExpectedParamList,
98// .InvalidAnd,
99// });
100//}
101//
102//test "recovery: invalid extern/inline" {
103// try testError(
104// \\inline test "" { a && b; }
105// , &[_]Error{
106// .ExpectedFn,
107// .InvalidAnd,
108// });
109// try testError(
110// \\extern "" test "" { a && b; }
111// , &[_]Error{
112// .ExpectedVarDeclOrFn,
113// .InvalidAnd,
114// });
115//}
116//
117//test "recovery: missing semicolon" {
118// try testError(
119// \\test "" {
120// \\ comptime a && b
121// \\ c && d
122// \\ @foo
123// \\}
124// , &[_]Error{
125// .InvalidAnd,
126// .ExpectedToken,
127// .InvalidAnd,
128// .ExpectedToken,
129// .ExpectedParamList,
130// .ExpectedToken,
131// });
132//}
133//
134//test "recovery: invalid container members" {
135// try testError(
136// \\usingnamespace;
137// \\foo+
138// \\bar@,
139// \\while (a == 2) { test "" {}}
140// \\test "" {
141// \\ a && b
142// \\}
143// , &[_]Error{
144// .ExpectedExpr,
145// .ExpectedToken,
146// .ExpectedToken,
147// .ExpectedContainerMembers,
148// .InvalidAnd,
149// .ExpectedToken,
150// });
151//}
152//
153//test "recovery: invalid parameter" {
154// try testError(
155// \\fn main() void {
156// \\ a(comptime T: type)
157// \\}
158// , &[_]Error{
159// .ExpectedToken,
160// });
161//}
162//
163//test "recovery: extra '}' at top level" {
164// try testError(
165// \\}}}
166// \\test "" {
167// \\ a && b;
168// \\}
169// , &[_]Error{
170// .ExpectedContainerMembers,
171// .ExpectedContainerMembers,
172// .ExpectedContainerMembers,
173// .InvalidAnd,
174// });
175//}
176//
177//test "recovery: mismatched bracket at top level" {
178// try testError(
179// \\const S = struct {
180// \\ arr: 128]?G
181// \\};
182// , &[_]Error{
183// .ExpectedToken,
184// });
185//}
186//
187//test "recovery: invalid global error set access" {
188// try testError(
189// \\test "" {
190// \\ error && foo;
191// \\}
192// , &[_]Error{
193// .ExpectedToken,
194// .ExpectedIdentifier,
195// .InvalidAnd,
196// });
197//}
198//
199//test "recovery: invalid asterisk after pointer dereference" {
200// try testError(
201// \\test "" {
202// \\ var sequence = "repeat".*** 10;
203// \\}
204// , &[_]Error{
205// .AsteriskAfterPointerDereference,
206// });
207// try testError(
208// \\test "" {
209// \\ var sequence = "repeat".** 10&&a;
210// \\}
211// , &[_]Error{
212// .AsteriskAfterPointerDereference,
213// .InvalidAnd,
214// });
215//}
216//
217//test "recovery: missing semicolon after if, for, while stmt" {
218// try testError(
219// \\test "" {
220// \\ if (foo) bar
221// \\ for (foo) |a| bar
222// \\ while (foo) bar
223// \\ a && b;
224// \\}
225// , &[_]Error{
226// .ExpectedSemiOrElse,
227// .ExpectedSemiOrElse,
228// .ExpectedSemiOrElse,
229// .InvalidAnd,
230// });
231//}
232//
233//test "recovery: invalid comptime" {
234// try testError(
235// \\comptime
236// , &[_]Error{
237// .ExpectedBlockOrField,
238// });
239//}
240//
241//test "recovery: missing block after for/while loops" {
242// try testError(
243// \\test "" { while (foo) }
244// , &[_]Error{
245// .ExpectedBlockOrAssignment,
246// });
247// try testError(
248// \\test "" { for (foo) |bar| }
249// , &[_]Error{
250// .ExpectedBlockOrAssignment,
251// });
252//}
253//
254//test "zig fmt: respect line breaks after var declarations" {
255// try testCanonical(
256// \\const crc =
257// \\ lookup_tables[0][p[7]] ^
258// \\ lookup_tables[1][p[6]] ^
259// \\ lookup_tables[2][p[5]] ^
260// \\ lookup_tables[3][p[4]] ^
261// \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
262// \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
263// \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
264// \\ lookup_tables[7][@truncate(u8, self.crc >> 0)];
265// \\
266// );
267//}
268//
269//test "zig fmt: multiline string mixed with comments" {
270// try testCanonical(
271// \\const s1 =
272// \\ //\\one
273// \\ \\two)
274// \\ \\three
275// \\;
276// \\const s2 =
277// \\ \\one
278// \\ \\two)
279// \\ //\\three
280// \\;
281// \\const s3 =
282// \\ \\one
283// \\ //\\two)
284// \\ \\three
285// \\;
286// \\const s4 =
287// \\ \\one
288// \\ //\\two
289// \\ \\three
290// \\ //\\four
291// \\ \\five
292// \\;
293// \\const a =
294// \\ 1;
295// \\
296// );
297//}
298//
299//test "zig fmt: empty file" {
300// try testCanonical(
301// \\
302// );
303//}
304//
305//test "zig fmt: if statment" {
306// try testCanonical(
307// \\test "" {
308// \\ if (optional()) |some|
309// \\ bar = some.foo();
310// \\}
311// \\
312// );
313//}
314//
315//test "zig fmt: top-level fields" {
316// try testCanonical(
317// \\a: did_you_know,
318// \\b: all_files_are,
319// \\structs: ?x,
320// \\
321// );
322//}
323//
324//test "zig fmt: decl between fields" {
325// try testError(
326// \\const S = struct {
327// \\ const foo = 2;
328// \\ const bar = 2;
329// \\ const baz = 2;
330// \\ a: usize,
331// \\ const foo1 = 2;
332// \\ const bar1 = 2;
333// \\ const baz1 = 2;
334// \\ b: usize,
335// \\};
336// , &[_]Error{
337// .DeclBetweenFields,
338// });
339//}
340//
341//test "zig fmt: eof after missing comma" {
342// try testError(
343// \\foo()
344// , &[_]Error{
345// .ExpectedToken,
346// });
347//}
348//
349//test "zig fmt: errdefer with payload" {
350// try testCanonical(
351// \\pub fn main() anyerror!void {
352// \\ errdefer |a| x += 1;
353// \\ errdefer |a| {}
354// \\ errdefer |a| {
355// \\ x += 1;
356// \\ }
357// \\}
358// \\
359// );
360//}
361//
362//test "zig fmt: nosuspend block" {
363// try testCanonical(
364// \\pub fn main() anyerror!void {
365// \\ nosuspend {
366// \\ var foo: Foo = .{ .bar = 42 };
367// \\ }
368// \\}
369// \\
370// );
371//}
372//
373//test "zig fmt: nosuspend await" {
374// try testCanonical(
375// \\fn foo() void {
376// \\ x = nosuspend await y;
377// \\}
378// \\
379// );
380//}
381//
382//test "zig fmt: trailing comma in container declaration" {
383// try testCanonical(
384// \\const X = struct { foo: i32 };
385// \\const X = struct { foo: i32, bar: i32 };
386// \\const X = struct { foo: i32 = 1, bar: i32 = 2 };
387// \\const X = struct { foo: i32 align(4), bar: i32 align(4) };
388// \\const X = struct { foo: i32 align(4) = 1, bar: i32 align(4) = 2 };
389// \\
390// );
391// try testCanonical(
392// \\test "" {
393// \\ comptime {
394// \\ const X = struct {
395// \\ x: i32
396// \\ };
397// \\ }
398// \\}
399// \\
400// );
401// try testTransform(
402// \\const X = struct {
403// \\ foo: i32, bar: i8 };
404// ,
405// \\const X = struct {
406// \\ foo: i32, bar: i8
407// \\};
408// \\
409// );
410//}
411//
412//test "zig fmt: trailing comma in fn parameter list" {
413// try testCanonical(
414// \\pub fn f(
415// \\ a: i32,
416// \\ b: i32,
417// \\) i32 {}
418// \\pub fn f(
419// \\ a: i32,
420// \\ b: i32,
421// \\) align(8) i32 {}
422// \\pub fn f(
423// \\ a: i32,
424// \\ b: i32,
425// \\) linksection(".text") i32 {}
426// \\pub fn f(
427// \\ a: i32,
428// \\ b: i32,
429// \\) callconv(.C) i32 {}
430// \\pub fn f(
431// \\ a: i32,
432// \\ b: i32,
433// \\) align(8) linksection(".text") i32 {}
434// \\pub fn f(
435// \\ a: i32,
436// \\ b: i32,
437// \\) align(8) callconv(.C) i32 {}
438// \\pub fn f(
439// \\ a: i32,
440// \\ b: i32,
441// \\) align(8) linksection(".text") callconv(.C) i32 {}
442// \\pub fn f(
443// \\ a: i32,
444// \\ b: i32,
445// \\) linksection(".text") callconv(.C) i32 {}
446// \\
447// );
448//}
449//
450//test "zig fmt: comptime struct field" {
451// try testCanonical(
452// \\const Foo = struct {
453// \\ a: i32,
454// \\ comptime b: i32 = 1234,
455// \\};
456// \\
457// );
458//}
459//
460//test "zig fmt: c pointer type" {
461// try testCanonical(
462// \\pub extern fn repro() [*c]const u8;
463// \\
464// );
465//}
466//
467//test "zig fmt: builtin call with trailing comma" {
468// try testCanonical(
469// \\pub fn main() void {
470// \\ @breakpoint();
471// \\ _ = @boolToInt(a);
472// \\ _ = @call(
473// \\ a,
474// \\ b,
475// \\ c,
476// \\ );
477// \\}
478// \\
479// );
480//}
481//
482//test "zig fmt: asm expression with comptime content" {
483// try testCanonical(
484// \\comptime {
485// \\ asm ("foo" ++ "bar");
486// \\}
487// \\pub fn main() void {
488// \\ asm volatile ("foo" ++ "bar");
489// \\ asm volatile ("foo" ++ "bar"
490// \\ : [_] "" (x)
491// \\ );
492// \\ asm volatile ("foo" ++ "bar"
493// \\ : [_] "" (x)
494// \\ : [_] "" (y)
495// \\ );
496// \\ asm volatile ("foo" ++ "bar"
497// \\ : [_] "" (x)
498// \\ : [_] "" (y)
499// \\ : "h", "e", "l", "l", "o"
500// \\ );
501// \\}
502// \\
503// );
504//}
505//
506//test "zig fmt: anytype struct field" {
507// try testCanonical(
508// \\pub const Pointer = struct {
509// \\ sentinel: anytype,
510// \\};
511// \\
512// );
513//}
514//
515//test "zig fmt: sentinel-terminated array type" {
516// try testCanonical(
517// \\pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 {
518// \\ return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
519// \\}
520// \\
521// );
522//}
523//
524//test "zig fmt: sentinel-terminated slice type" {
525// try testCanonical(
526// \\pub fn toSlice(self: Buffer) [:0]u8 {
527// \\ return self.list.toSlice()[0..self.len()];
528// \\}
529// \\
530// );
531//}
532//
533//test "zig fmt: anon literal in array" {
534// try testCanonical(
535// \\var arr: [2]Foo = .{
536// \\ .{ .a = 2 },
537// \\ .{ .b = 3 },
538// \\};
539// \\
540// );
541//}
542//
543//test "zig fmt: alignment in anonymous literal" {
544// try testTransform(
545// \\const a = .{
546// \\ "U", "L", "F",
547// \\ "U'",
548// \\ "L'",
549// \\ "F'",
550// \\};
551// \\
552// ,
553// \\const a = .{
554// \\ "U", "L", "F",
555// \\ "U'", "L'", "F'",
556// \\};
557// \\
558// );
559//}
560//
561//test "zig fmt: anon struct literal syntax" {
562// try testCanonical(
563// \\const x = .{
564// \\ .a = b,
565// \\ .c = d,
566// \\};
567// \\
568// );
569//}
570//
571//test "zig fmt: anon list literal syntax" {
572// try testCanonical(
573// \\const x = .{ a, b, c };
574// \\
575// );
576//}
577//
578//test "zig fmt: async function" {
579// try testCanonical(
580// \\pub const Server = struct {
581// \\ handleRequestFn: fn (*Server, *const std.net.Address, File) callconv(.Async) void,
582// \\};
583// \\test "hi" {
584// \\ var ptr = @ptrCast(fn (i32) callconv(.Async) void, other);
585// \\}
586// \\
587// );
588//}
589//
590//test "zig fmt: whitespace fixes" {
591// try testTransform("test \"\" {\r\n\tconst hi = x;\r\n}\n// zig fmt: off\ntest \"\"{\r\n\tconst a = b;}\r\n",
592// \\test "" {
593// \\ const hi = x;
594// \\}
595// \\// zig fmt: off
596// \\test ""{
597// \\ const a = b;}
598// \\
599// );
600//}
601//
602//test "zig fmt: while else err prong with no block" {
603// try testCanonical(
604// \\test "" {
605// \\ const result = while (returnError()) |value| {
606// \\ break value;
607// \\ } else |err| @as(i32, 2);
608// \\ expect(result == 2);
609// \\}
610// \\
611// );
612//}
613//
614//test "zig fmt: tagged union with enum values" {
615// try testCanonical(
616// \\const MultipleChoice2 = union(enum(u32)) {
617// \\ Unspecified1: i32,
618// \\ A: f32 = 20,
619// \\ Unspecified2: void,
620// \\ B: bool = 40,
621// \\ Unspecified3: i32,
622// \\ C: i8 = 60,
623// \\ Unspecified4: void,
624// \\ D: void = 1000,
625// \\ Unspecified5: i32,
626// \\};
627// \\
628// );
629//}
630//
631//test "zig fmt: allowzero pointer" {
632// try testCanonical(
633// \\const T = [*]allowzero const u8;
634// \\
635// );
636//}
637//
638//test "zig fmt: enum literal" {
639// try testCanonical(
640// \\const x = .hi;
641// \\
642// );
643//}
644//
645//test "zig fmt: enum literal inside array literal" {
646// try testCanonical(
647// \\test "enums in arrays" {
648// \\ var colors = []Color{.Green};
649// \\ colors = []Colors{ .Green, .Cyan };
650// \\ colors = []Colors{
651// \\ .Grey,
652// \\ .Green,
653// \\ .Cyan,
654// \\ };
655// \\}
656// \\
657// );
658//}
659//
660//test "zig fmt: character literal larger than u8" {
661// try testCanonical(
662// \\const x = '\u{01f4a9}';
663// \\
664// );
665//}
666//
667//test "zig fmt: infix operator and then multiline string literal" {
668// try testCanonical(
669// \\const x = "" ++
670// \\ \\ hi
671// \\;
672// \\
673// );
674//}
675//
676//test "zig fmt: infix operator and then multiline string literal" {
677// try testCanonical(
678// \\const x = "" ++
679// \\ \\ hi0
680// \\ \\ hi1
681// \\ \\ hi2
682// \\;
683// \\
684// );
685//}
686//
687//test "zig fmt: C pointers" {
688// try testCanonical(
689// \\const Ptr = [*c]i32;
690// \\
691// );
692//}
693//
694//test "zig fmt: threadlocal" {
695// try testCanonical(
696// \\threadlocal var x: i32 = 1234;
697// \\
698// );
699//}
700//
701//test "zig fmt: linksection" {
702// try testCanonical(
703// \\export var aoeu: u64 linksection(".text.derp") = 1234;
704// \\export fn _start() linksection(".text.boot") callconv(.Naked) noreturn {}
705// \\
706// );
707//}
708//
709//test "zig fmt: correctly move doc comments on struct fields" {
710// try testTransform(
711// \\pub const section_64 = extern struct {
712// \\ sectname: [16]u8, /// name of this section
713// \\ segname: [16]u8, /// segment this section goes in
714// \\};
715// ,
716// \\pub const section_64 = extern struct {
717// \\ /// name of this section
718// \\ sectname: [16]u8,
719// \\ /// segment this section goes in
720// \\ segname: [16]u8,
721// \\};
722// \\
723// );
724//}
725//
726//test "zig fmt: correctly space struct fields with doc comments" {
727// try testTransform(
728// \\pub const S = struct {
729// \\ /// A
730// \\ a: u8,
731// \\ /// B
732// \\ /// B (cont)
733// \\ b: u8,
734// \\
735// \\
736// \\ /// C
737// \\ c: u8,
738// \\};
739// \\
740// ,
741// \\pub const S = struct {
742// \\ /// A
743// \\ a: u8,
744// \\ /// B
745// \\ /// B (cont)
746// \\ b: u8,
747// \\
748// \\ /// C
749// \\ c: u8,
750// \\};
751// \\
752// );
753//}
754//
755//test "zig fmt: doc comments on param decl" {
756// try testCanonical(
757// \\pub const Allocator = struct {
758// \\ shrinkFn: fn (
759// \\ self: *Allocator,
760// \\ /// Guaranteed to be the same as what was returned from most recent call to
761// \\ /// `allocFn`, `reallocFn`, or `shrinkFn`.
762// \\ old_mem: []u8,
763// \\ /// Guaranteed to be the same as what was returned from most recent call to
764// \\ /// `allocFn`, `reallocFn`, or `shrinkFn`.
765// \\ old_alignment: u29,
766// \\ /// Guaranteed to be less than or equal to `old_mem.len`.
767// \\ new_byte_count: usize,
768// \\ /// Guaranteed to be less than or equal to `old_alignment`.
769// \\ new_alignment: u29,
770// \\ ) []u8,
771// \\};
772// \\
773// );
774//}
775//
776//test "zig fmt: aligned struct field" {
777// try testCanonical(
778// \\pub const S = struct {
779// \\ f: i32 align(32),
780// \\};
781// \\
782// );
783// try testCanonical(
784// \\pub const S = struct {
785// \\ f: i32 align(32) = 1,
786// \\};
787// \\
788// );
789//}
790//
791//test "zig fmt: comment to disable/enable zig fmt first" {
792// try testCanonical(
793// \\// Test trailing comma syntax
794// \\// zig fmt: off
795// \\
796// \\const struct_trailing_comma = struct { x: i32, y: i32, };
797// );
798//}
799//
800//test "zig fmt: comment to disable/enable zig fmt" {
801// try testTransform(
802// \\const a = b;
803// \\// zig fmt: off
804// \\const c = d;
805// \\// zig fmt: on
806// \\const e = f;
807// ,
808// \\const a = b;
809// \\// zig fmt: off
810// \\const c = d;
811// \\// zig fmt: on
812// \\const e = f;
813// \\
814// );
815//}
816//
817//test "zig fmt: line comment following 'zig fmt: off'" {
818// try testCanonical(
819// \\// zig fmt: off
820// \\// Test
821// \\const e = f;
822// );
823//}
824//
825//test "zig fmt: doc comment following 'zig fmt: off'" {
826// try testCanonical(
827// \\// zig fmt: off
828// \\/// test
829// \\const e = f;
830// );
831//}
832//
833//test "zig fmt: line and doc comment following 'zig fmt: off'" {
834// try testCanonical(
835// \\// zig fmt: off
836// \\// test 1
837// \\/// test 2
838// \\const e = f;
839// );
840//}
841//
842//test "zig fmt: doc and line comment following 'zig fmt: off'" {
843// try testCanonical(
844// \\// zig fmt: off
845// \\/// test 1
846// \\// test 2
847// \\const e = f;
848// );
849//}
850//
851//test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" {
852// try testCanonical(
853// \\// zig fmt: off
854// \\// zig fmt: on
855// \\// zig fmt: off
856// \\const e = f;
857// \\// zig fmt: off
858// \\// zig fmt: on
859// \\// zig fmt: off
860// \\const a = b;
861// \\// zig fmt: on
862// \\const c = d;
863// \\// zig fmt: on
864// \\
865// );
866//}
867//
868//test "zig fmt: line comment following 'zig fmt: on'" {
869// try testCanonical(
870// \\// zig fmt: off
871// \\const e = f;
872// \\// zig fmt: on
873// \\// test
874// \\const e = f;
875// \\
876// );
877//}
878//
879//test "zig fmt: doc comment following 'zig fmt: on'" {
880// try testCanonical(
881// \\// zig fmt: off
882// \\const e = f;
883// \\// zig fmt: on
884// \\/// test
885// \\const e = f;
886// \\
887// );
888//}
889//
890//test "zig fmt: line and doc comment following 'zig fmt: on'" {
891// try testCanonical(
892// \\// zig fmt: off
893// \\const e = f;
894// \\// zig fmt: on
895// \\// test1
896// \\/// test2
897// \\const e = f;
898// \\
899// );
900//}
901//
902//test "zig fmt: doc and line comment following 'zig fmt: on'" {
903// try testCanonical(
904// \\// zig fmt: off
905// \\const e = f;
906// \\// zig fmt: on
907// \\/// test1
908// \\// test2
909// \\const e = f;
910// \\
911// );
912//}
913//
914//test "zig fmt: pointer of unknown length" {
915// try testCanonical(
916// \\fn foo(ptr: [*]u8) void {}
917// \\
918// );
919//}
920//
921//test "zig fmt: spaces around slice operator" {
922// try testCanonical(
923// \\var a = b[c..d];
924// \\var a = b[c..d :0];
925// \\var a = b[c + 1 .. d];
926// \\var a = b[c + 1 ..];
927// \\var a = b[c .. d + 1];
928// \\var a = b[c .. d + 1 :0];
929// \\var a = b[c.a..d.e];
930// \\var a = b[c.a..d.e :0];
931// \\
932// );
933//}
934//
935//test "zig fmt: async call in if condition" {
936// try testCanonical(
937// \\comptime {
938// \\ if (async b()) {
939// \\ a();
940// \\ }
941// \\}
942// \\
943// );
944//}
945//
946//test "zig fmt: 2nd arg multiline string" {
947// try testCanonical(
948// \\comptime {
949// \\ cases.addAsm("hello world linux x86_64",
950// \\ \\.text
951// \\ , "Hello, world!\n");
952// \\}
953// \\
954// );
955//}
956//
957//test "zig fmt: 2nd arg multiline string many args" {
958// try testCanonical(
959// \\comptime {
960// \\ cases.addAsm("hello world linux x86_64",
961// \\ \\.text
962// \\ , "Hello, world!\n", "Hello, world!\n");
963// \\}
964// \\
965// );
966//}
967//
968//test "zig fmt: final arg multiline string" {
969// try testCanonical(
970// \\comptime {
971// \\ cases.addAsm("hello world linux x86_64", "Hello, world!\n",
972// \\ \\.text
973// \\ );
974// \\}
975// \\
976// );
977//}
978//
979//test "zig fmt: if condition wraps" {
980// try testTransform(
981// \\comptime {
982// \\ if (cond and
983// \\ cond) {
984// \\ return x;
985// \\ }
986// \\ while (cond and
987// \\ cond) {
988// \\ return x;
989// \\ }
990// \\ if (a == b and
991// \\ c) {
992// \\ a = b;
993// \\ }
994// \\ while (a == b and
995// \\ c) {
996// \\ a = b;
997// \\ }
998// \\ if ((cond and
999// \\ cond)) {
1000// \\ return x;
1001// \\ }
1002// \\ while ((cond and
1003// \\ cond)) {
1004// \\ return x;
1005// \\ }
1006// \\ var a = if (a) |*f| x: {
1007// \\ break :x &a.b;
1008// \\ } else |err| err;
1009// \\ var a = if (cond and
1010// \\ cond) |*f|
1011// \\ x: {
1012// \\ break :x &a.b;
1013// \\ } else |err| err;
1014// \\}
1015// ,
1016// \\comptime {
1017// \\ if (cond and
1018// \\ cond)
1019// \\ {
1020// \\ return x;
1021// \\ }
1022// \\ while (cond and
1023// \\ cond)
1024// \\ {
1025// \\ return x;
1026// \\ }
1027// \\ if (a == b and
1028// \\ c)
1029// \\ {
1030// \\ a = b;
1031// \\ }
1032// \\ while (a == b and
1033// \\ c)
1034// \\ {
1035// \\ a = b;
1036// \\ }
1037// \\ if ((cond and
1038// \\ cond))
1039// \\ {
1040// \\ return x;
1041// \\ }
1042// \\ while ((cond and
1043// \\ cond))
1044// \\ {
1045// \\ return x;
1046// \\ }
1047// \\ var a = if (a) |*f| x: {
1048// \\ break :x &a.b;
1049// \\ } else |err| err;
1050// \\ var a = if (cond and
1051// \\ cond) |*f|
1052// \\ x: {
1053// \\ break :x &a.b;
1054// \\ } else |err| err;
1055// \\}
1056// \\
1057// );
1058//}
1059//
1060//test "zig fmt: if condition has line break but must not wrap" {
1061// try testCanonical(
1062// \\comptime {
1063// \\ if (self.user_input_options.put(
1064// \\ name,
1065// \\ UserInputOption{
1066// \\ .name = name,
1067// \\ .used = false,
1068// \\ },
1069// \\ ) catch unreachable) |*prev_value| {
1070// \\ foo();
1071// \\ bar();
1072// \\ }
1073// \\ if (put(
1074// \\ a,
1075// \\ b,
1076// \\ )) {
1077// \\ foo();
1078// \\ }
1079// \\}
1080// \\
1081// );
1082//}
1083//
1084//test "zig fmt: if condition has line break but must not wrap" {
1085// try testCanonical(
1086// \\comptime {
1087// \\ if (self.user_input_options.put(name, UserInputOption{
1088// \\ .name = name,
1089// \\ .used = false,
1090// \\ }) catch unreachable) |*prev_value| {
1091// \\ foo();
1092// \\ bar();
1093// \\ }
1094// \\ if (put(
1095// \\ a,
1096// \\ b,
1097// \\ )) {
1098// \\ foo();
1099// \\ }
1100// \\}
1101// \\
1102// );
1103//}
1104//
1105//test "zig fmt: function call with multiline argument" {
1106// try testCanonical(
1107// \\comptime {
1108// \\ self.user_input_options.put(name, UserInputOption{
1109// \\ .name = name,
1110// \\ .used = false,
1111// \\ });
1112// \\}
1113// \\
1114// );
1115//}
1116//
1117//test "zig fmt: same-line doc comment on variable declaration" {
1118// try testTransform(
1119// \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
1120// \\pub const MAP_FILE = 0x0000; /// map from file (default)
1121// \\
1122// \\pub const EMEDIUMTYPE = 124; /// Wrong medium type
1123// \\
1124// \\// nameserver query return codes
1125// \\pub const ENSROK = 0; /// DNS server returned answer with no data
1126// ,
1127// \\/// allocated from memory, swap space
1128// \\pub const MAP_ANONYMOUS = 0x1000;
1129// \\/// map from file (default)
1130// \\pub const MAP_FILE = 0x0000;
1131// \\
1132// \\/// Wrong medium type
1133// \\pub const EMEDIUMTYPE = 124;
1134// \\
1135// \\// nameserver query return codes
1136// \\/// DNS server returned answer with no data
1137// \\pub const ENSROK = 0;
1138// \\
1139// );
1140//}
1141//
1142//test "zig fmt: if-else with comment before else" {
1143// try testCanonical(
1144// \\comptime {
1145// \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
1146// \\ if ((hx & 0x7fffffff) != 0x7f800000) {
1147// \\ return Complex(f32).new(y - y, y - y);
1148// \\ } // cexp(-inf +- i inf|nan) = 0 + i0
1149// \\ else if (hx & 0x80000000 != 0) {
1150// \\ return Complex(f32).new(0, 0);
1151// \\ } // cexp(+inf +- i inf|nan) = inf + i nan
1152// \\ else {
1153// \\ return Complex(f32).new(x, y - y);
1154// \\ }
1155// \\}
1156// \\
1157// );
1158//}
1159//
1160//test "zig fmt: if nested" {
1161// try testCanonical(
1162// \\pub fn foo() void {
1163// \\ return if ((aInt & bInt) >= 0)
1164// \\ if (aInt < bInt)
1165// \\ GE_LESS
1166// \\ else if (aInt == bInt)
1167// \\ GE_EQUAL
1168// \\ else
1169// \\ GE_GREATER
1170// \\ else if (aInt > bInt)
1171// \\ GE_LESS
1172// \\ else if (aInt == bInt)
1173// \\ GE_EQUAL
1174// \\ else
1175// \\ GE_GREATER;
1176// \\}
1177// \\
1178// );
1179//}
1180//
1181//test "zig fmt: respect line breaks in if-else" {
1182// try testCanonical(
1183// \\comptime {
1184// \\ return if (cond) a else b;
1185// \\ return if (cond)
1186// \\ a
1187// \\ else
1188// \\ b;
1189// \\ return if (cond)
1190// \\ a
1191// \\ else if (cond)
1192// \\ b
1193// \\ else
1194// \\ c;
1195// \\}
1196// \\
1197// );
1198//}
1199//
1200//test "zig fmt: respect line breaks after infix operators" {
1201// try testCanonical(
1202// \\comptime {
1203// \\ self.crc =
1204// \\ lookup_tables[0][p[7]] ^
1205// \\ lookup_tables[1][p[6]] ^
1206// \\ lookup_tables[2][p[5]] ^
1207// \\ lookup_tables[3][p[4]] ^
1208// \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
1209// \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
1210// \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
1211// \\ lookup_tables[7][@truncate(u8, self.crc >> 0)];
1212// \\}
1213// \\
1214// );
1215//}
1216//
1217//test "zig fmt: fn decl with trailing comma" {
1218// try testTransform(
1219// \\fn foo(a: i32, b: i32,) void {}
1220// ,
1221// \\fn foo(
1222// \\ a: i32,
1223// \\ b: i32,
1224// \\) void {}
1225// \\
1226// );
1227//}
1228//
1229//test "zig fmt: enum decl with no trailing comma" {
1230// try testTransform(
1231// \\const StrLitKind = enum {Normal, C};
1232// ,
1233// \\const StrLitKind = enum { Normal, C };
1234// \\
1235// );
1236//}
1237//
1238//test "zig fmt: switch comment before prong" {
1239// try testCanonical(
1240// \\comptime {
1241// \\ switch (a) {
1242// \\ // hi
1243// \\ 0 => {},
1244// \\ }
1245// \\}
1246// \\
1247// );
1248//}
1249//
1250//test "zig fmt: struct literal no trailing comma" {
1251// try testTransform(
1252// \\const a = foo{ .x = 1, .y = 2 };
1253// \\const a = foo{ .x = 1,
1254// \\ .y = 2 };
1255// ,
1256// \\const a = foo{ .x = 1, .y = 2 };
1257// \\const a = foo{
1258// \\ .x = 1,
1259// \\ .y = 2,
1260// \\};
1261// \\
1262// );
1263//}
1264//
1265//test "zig fmt: struct literal containing a multiline expression" {
1266// try testTransform(
1267// \\const a = A{ .x = if (f1()) 10 else 20 };
1268// \\const a = A{ .x = if (f1()) 10 else 20, };
1269// \\const a = A{ .x = if (f1())
1270// \\ 10 else 20 };
1271// \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 };
1272// \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100, };
1273// \\const a = A{ .x = if (f1())
1274// \\ 10 else 20};
1275// \\const a = A{ .x = switch(g) {0 => "ok", else => "no"} };
1276// \\
1277// ,
1278// \\const a = A{ .x = if (f1()) 10 else 20 };
1279// \\const a = A{
1280// \\ .x = if (f1()) 10 else 20,
1281// \\};
1282// \\const a = A{
1283// \\ .x = if (f1())
1284// \\ 10
1285// \\ else
1286// \\ 20,
1287// \\};
1288// \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 };
1289// \\const a = A{
1290// \\ .x = if (f1()) 10 else 20,
1291// \\ .y = f2() + 100,
1292// \\};
1293// \\const a = A{
1294// \\ .x = if (f1())
1295// \\ 10
1296// \\ else
1297// \\ 20,
1298// \\};
1299// \\const a = A{
1300// \\ .x = switch (g) {
1301// \\ 0 => "ok",
1302// \\ else => "no",
1303// \\ },
1304// \\};
1305// \\
1306// );
1307//}
1308//
1309//test "zig fmt: array literal with hint" {
1310// try testTransform(
1311// \\const a = []u8{
1312// \\ 1, 2, //
1313// \\ 3,
1314// \\ 4,
1315// \\ 5,
1316// \\ 6,
1317// \\ 7 };
1318// \\const a = []u8{
1319// \\ 1, 2, //
1320// \\ 3,
1321// \\ 4,
1322// \\ 5,
1323// \\ 6,
1324// \\ 7, 8 };
1325// \\const a = []u8{
1326// \\ 1, 2, //
1327// \\ 3,
1328// \\ 4,
1329// \\ 5,
1330// \\ 6, // blah
1331// \\ 7, 8 };
1332// \\const a = []u8{
1333// \\ 1, 2, //
1334// \\ 3, //
1335// \\ 4,
1336// \\ 5,
1337// \\ 6,
1338// \\ 7 };
1339// \\const a = []u8{
1340// \\ 1,
1341// \\ 2,
1342// \\ 3, 4, //
1343// \\ 5, 6, //
1344// \\ 7, 8, //
1345// \\};
1346// ,
1347// \\const a = []u8{
1348// \\ 1, 2,
1349// \\ 3, 4,
1350// \\ 5, 6,
1351// \\ 7,
1352// \\};
1353// \\const a = []u8{
1354// \\ 1, 2,
1355// \\ 3, 4,
1356// \\ 5, 6,
1357// \\ 7, 8,
1358// \\};
1359// \\const a = []u8{
1360// \\ 1, 2,
1361// \\ 3, 4,
1362// \\ 5,
1363// \\ 6, // blah
1364// \\ 7,
1365// \\ 8,
1366// \\};
1367// \\const a = []u8{
1368// \\ 1, 2,
1369// \\ 3, //
1370// \\ 4,
1371// \\ 5, 6,
1372// \\ 7,
1373// \\};
1374// \\const a = []u8{
1375// \\ 1,
1376// \\ 2,
1377// \\ 3,
1378// \\ 4,
1379// \\ 5,
1380// \\ 6,
1381// \\ 7,
1382// \\ 8,
1383// \\};
1384// \\
1385// );
1386//}
1387//
1388//test "zig fmt: array literal veritical column alignment" {
1389// try testTransform(
1390// \\const a = []u8{
1391// \\ 1000, 200,
1392// \\ 30, 4,
1393// \\ 50000, 60
1394// \\};
1395// \\const a = []u8{0, 1, 2, 3, 40,
1396// \\ 4,5,600,7,
1397// \\ 80,
1398// \\ 9, 10, 11, 0, 13, 14, 15};
1399// \\
1400// ,
1401// \\const a = []u8{
1402// \\ 1000, 200,
1403// \\ 30, 4,
1404// \\ 50000, 60,
1405// \\};
1406// \\const a = []u8{
1407// \\ 0, 1, 2, 3, 40,
1408// \\ 4, 5, 600, 7, 80,
1409// \\ 9, 10, 11, 0, 13,
1410// \\ 14, 15,
1411// \\};
1412// \\
1413// );
1414//}
1415//
1416//test "zig fmt: multiline string with backslash at end of line" {
1417// try testCanonical(
1418// \\comptime {
1419// \\ err(
1420// \\ \\\
1421// \\ );
1422// \\}
1423// \\
1424// );
1425//}
1426//
1427//test "zig fmt: multiline string parameter in fn call with trailing comma" {
1428// try testCanonical(
1429// \\fn foo() void {
1430// \\ try stdout.print(
1431// \\ \\ZIG_CMAKE_BINARY_DIR {}
1432// \\ \\ZIG_C_HEADER_FILES {}
1433// \\ \\ZIG_DIA_GUIDS_LIB {}
1434// \\ \\
1435// \\ ,
1436// \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
1437// \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
1438// \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
1439// \\ );
1440// \\}
1441// \\
1442// );
1443//}
1444//
1445//test "zig fmt: trailing comma on fn call" {
1446// try testCanonical(
1447// \\comptime {
1448// \\ var module = try Module.create(
1449// \\ allocator,
1450// \\ zig_lib_dir,
1451// \\ full_cache_dir,
1452// \\ );
1453// \\}
1454// \\
1455// );
1456//}
1457//
1458//test "zig fmt: multi line arguments without last comma" {
1459// try testTransform(
1460// \\pub fn foo(
1461// \\ a: usize,
1462// \\ b: usize,
1463// \\ c: usize,
1464// \\ d: usize
1465// \\) usize {
1466// \\ return a + b + c + d;
1467// \\}
1468// \\
1469// ,
1470// \\pub fn foo(a: usize, b: usize, c: usize, d: usize) usize {
1471// \\ return a + b + c + d;
1472// \\}
1473// \\
1474// );
1475//}
1476//
1477//test "zig fmt: empty block with only comment" {
1478// try testCanonical(
1479// \\comptime {
1480// \\ {
1481// \\ // comment
1482// \\ }
1483// \\}
1484// \\
1485// );
1486//}
1487//
1488//test "zig fmt: no trailing comma on struct decl" {
1489// try testCanonical(
1490// \\const RoundParam = struct {
1491// \\ k: usize, s: u32, t: u32
1492// \\};
1493// \\
1494// );
1495//}
1496//
1497//test "zig fmt: extra newlines at the end" {
1498// try testTransform(
1499// \\const a = b;
1500// \\
1501// \\
1502// \\
1503// ,
1504// \\const a = b;
1505// \\
1506// );
1507//}
1508//
1509//test "zig fmt: simple asm" {
1510// try testTransform(
1511// \\comptime {
1512// \\ asm volatile (
1513// \\ \\.globl aoeu;
1514// \\ \\.type aoeu, @function;
1515// \\ \\.set aoeu, derp;
1516// \\ );
1517// \\
1518// \\ asm ("not real assembly"
1519// \\ :[a] "x" (x),);
1520// \\ asm ("not real assembly"
1521// \\ :[a] "x" (->i32),:[a] "x" (1),);
1522// \\ asm ("still not real assembly"
1523// \\ :::"a","b",);
1524// \\}
1525// ,
1526// \\comptime {
1527// \\ asm volatile (
1528// \\ \\.globl aoeu;
1529// \\ \\.type aoeu, @function;
1530// \\ \\.set aoeu, derp;
1531// \\ );
1532// \\
1533// \\ asm ("not real assembly"
1534// \\ : [a] "x" (x)
1535// \\ );
1536// \\ asm ("not real assembly"
1537// \\ : [a] "x" (-> i32)
1538// \\ : [a] "x" (1)
1539// \\ );
1540// \\ asm ("still not real assembly"
1541// \\ :
1542// \\ :
1543// \\ : "a", "b"
1544// \\ );
1545// \\}
1546// \\
1547// );
1548//}
1549//
1550//test "zig fmt: nested struct literal with one item" {
1551// try testCanonical(
1552// \\const a = foo{
1553// \\ .item = bar{ .a = b },
1554// \\};
1555// \\
1556// );
1557//}
1558//
1559//test "zig fmt: switch cases trailing comma" {
1560// try testTransform(
1561// \\fn switch_cases(x: i32) void {
1562// \\ switch (x) {
1563// \\ 1,2,3 => {},
1564// \\ 4,5, => {},
1565// \\ 6... 8, => {},
1566// \\ else => {},
1567// \\ }
1568// \\}
1569// ,
1570// \\fn switch_cases(x: i32) void {
1571// \\ switch (x) {
1572// \\ 1, 2, 3 => {},
1573// \\ 4,
1574// \\ 5,
1575// \\ => {},
1576// \\ 6...8 => {},
1577// \\ else => {},
1578// \\ }
1579// \\}
1580// \\
1581// );
1582//}
1583//
1584//test "zig fmt: slice align" {
1585// try testCanonical(
1586// \\const A = struct {
1587// \\ items: []align(A) T,
1588// \\};
1589// \\
1590// );
1591//}
1592//
1593//test "zig fmt: add trailing comma to array literal" {
1594// try testTransform(
1595// \\comptime {
1596// \\ return []u16{'m', 's', 'y', 's', '-' // hi
1597// \\ };
1598// \\ return []u16{'m', 's', 'y', 's',
1599// \\ '-'};
1600// \\ return []u16{'m', 's', 'y', 's', '-'};
1601// \\}
1602// ,
1603// \\comptime {
1604// \\ return []u16{
1605// \\ 'm', 's', 'y', 's', '-', // hi
1606// \\ };
1607// \\ return []u16{
1608// \\ 'm', 's', 'y', 's',
1609// \\ '-',
1610// \\ };
1611// \\ return []u16{ 'm', 's', 'y', 's', '-' };
1612// \\}
1613// \\
1614// );
1615//}
1616//
1617//test "zig fmt: first thing in file is line comment" {
1618// try testCanonical(
1619// \\// Introspection and determination of system libraries needed by zig.
1620// \\
1621// \\// Introspection and determination of system libraries needed by zig.
1622// \\
1623// \\const std = @import("std");
1624// \\
1625// );
1626//}
1627//
1628//test "zig fmt: line comment after doc comment" {
1629// try testCanonical(
1630// \\/// doc comment
1631// \\// line comment
1632// \\fn foo() void {}
1633// \\
1634// );
1635//}
1636//
1637//test "zig fmt: float literal with exponent" {
1638// try testCanonical(
1639// \\test "bit field alignment" {
1640// \\ assert(@TypeOf(&blah.b) == *align(1:3:6) const u3);
1641// \\}
1642// \\
1643// );
1644//}
1645//
1646//test "zig fmt: float literal with exponent" {
1647// try testCanonical(
1648// \\test "aoeu" {
1649// \\ switch (state) {
1650// \\ TermState.Start => switch (c) {
1651// \\ '\x1b' => state = TermState.Escape,
1652// \\ else => try out.writeByte(c),
1653// \\ },
1654// \\ }
1655// \\}
1656// \\
1657// );
1658//}
1659//test "zig fmt: float literal with exponent" {
1660// try testCanonical(
1661// \\pub const f64_true_min = 4.94065645841246544177e-324;
1662// \\const threshold = 0x1.a827999fcef32p+1022;
1663// \\
1664// );
1665//}
1666//
1667//test "zig fmt: if-else end of comptime" {
1668// try testCanonical(
1669// \\comptime {
1670// \\ if (a) {
1671// \\ b();
1672// \\ } else {
1673// \\ b();
1674// \\ }
1675// \\}
1676// \\
1677// );
1678//}
1679//
1680//test "zig fmt: nested blocks" {
1681// try testCanonical(
1682// \\comptime {
1683// \\ {
1684// \\ {
1685// \\ {
1686// \\ a();
1687// \\ }
1688// \\ }
1689// \\ }
1690// \\}
1691// \\
1692// );
1693//}
1694//
1695//test "zig fmt: block with same line comment after end brace" {
1696// try testCanonical(
1697// \\comptime {
1698// \\ {
1699// \\ b();
1700// \\ } // comment
1701// \\}
1702// \\
1703// );
1704//}
1705//
1706//test "zig fmt: statements with comment between" {
1707// try testCanonical(
1708// \\comptime {
1709// \\ a = b;
1710// \\ // comment
1711// \\ a = b;
1712// \\}
1713// \\
1714// );
1715//}
1716//
1717//test "zig fmt: statements with empty line between" {
1718// try testCanonical(
1719// \\comptime {
1720// \\ a = b;
1721// \\
1722// \\ a = b;
1723// \\}
1724// \\
1725// );
1726//}
1727//
1728//test "zig fmt: ptr deref operator and unwrap optional operator" {
1729// try testCanonical(
1730// \\const a = b.*;
1731// \\const a = b.?;
1732// \\
1733// );
1734//}
1735//
1736//test "zig fmt: comment after if before another if" {
1737// try testCanonical(
1738// \\test "aoeu" {
1739// \\ // comment
1740// \\ if (x) {
1741// \\ bar();
1742// \\ }
1743// \\}
1744// \\
1745// \\test "aoeu" {
1746// \\ if (x) {
1747// \\ foo();
1748// \\ }
1749// \\ // comment
1750// \\ if (x) {
1751// \\ bar();
1752// \\ }
1753// \\}
1754// \\
1755// );
1756//}
1757//
1758//test "zig fmt: line comment between if block and else keyword" {
1759// try testCanonical(
1760// \\test "aoeu" {
1761// \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
1762// \\ if ((hx & 0x7fffffff) != 0x7f800000) {
1763// \\ return Complex(f32).new(y - y, y - y);
1764// \\ }
1765// \\ // cexp(-inf +- i inf|nan) = 0 + i0
1766// \\ else if (hx & 0x80000000 != 0) {
1767// \\ return Complex(f32).new(0, 0);
1768// \\ }
1769// \\ // cexp(+inf +- i inf|nan) = inf + i nan
1770// \\ // another comment
1771// \\ else {
1772// \\ return Complex(f32).new(x, y - y);
1773// \\ }
1774// \\}
1775// \\
1776// );
1777//}
1778//
1779//test "zig fmt: same line comments in expression" {
1780// try testCanonical(
1781// \\test "aoeu" {
1782// \\ const x = ( // a
1783// \\ 0 // b
1784// \\ ); // c
1785// \\}
1786// \\
1787// );
1788//}
1789//
1790//test "zig fmt: add comma on last switch prong" {
1791// try testTransform(
1792// \\test "aoeu" {
1793// \\switch (self.init_arg_expr) {
1794// \\ InitArg.Type => |t| { },
1795// \\ InitArg.None,
1796// \\ InitArg.Enum => { }
1797// \\}
1798// \\ switch (self.init_arg_expr) {
1799// \\ InitArg.Type => |t| { },
1800// \\ InitArg.None,
1801// \\ InitArg.Enum => { }//line comment
1802// \\ }
1803// \\}
1804// ,
1805// \\test "aoeu" {
1806// \\ switch (self.init_arg_expr) {
1807// \\ InitArg.Type => |t| {},
1808// \\ InitArg.None, InitArg.Enum => {},
1809// \\ }
1810// \\ switch (self.init_arg_expr) {
1811// \\ InitArg.Type => |t| {},
1812// \\ InitArg.None, InitArg.Enum => {}, //line comment
1813// \\ }
1814// \\}
1815// \\
1816// );
1817//}
1818//
1819//test "zig fmt: same-line comment after a statement" {
1820// try testCanonical(
1821// \\test "" {
1822// \\ a = b;
1823// \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
1824// \\ a = b;
1825// \\}
1826// \\
1827// );
1828//}
1829//
1830//test "zig fmt: same-line comment after var decl in struct" {
1831// try testCanonical(
1832// \\pub const vfs_cap_data = extern struct {
1833// \\ const Data = struct {}; // when on disk.
1834// \\};
1835// \\
1836// );
1837//}
1838//
1839//test "zig fmt: same-line comment after field decl" {
1840// try testCanonical(
1841// \\pub const dirent = extern struct {
1842// \\ d_name: u8,
1843// \\ d_name: u8, // comment 1
1844// \\ d_name: u8,
1845// \\ d_name: u8, // comment 2
1846// \\ d_name: u8,
1847// \\};
1848// \\
1849// );
1850//}
1851//
1852//test "zig fmt: same-line comment after switch prong" {
1853// try testCanonical(
1854// \\test "" {
1855// \\ switch (err) {
1856// \\ error.PathAlreadyExists => {}, // comment 2
1857// \\ else => return err, // comment 1
1858// \\ }
1859// \\}
1860// \\
1861// );
1862//}
1863//
1864//test "zig fmt: same-line comment after non-block if expression" {
1865// try testCanonical(
1866// \\comptime {
1867// \\ if (sr > n_uword_bits - 1) // d > r
1868// \\ return 0;
1869// \\}
1870// \\
1871// );
1872//}
1873//
1874//test "zig fmt: same-line comment on comptime expression" {
1875// try testCanonical(
1876// \\test "" {
1877// \\ comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt
1878// \\}
1879// \\
1880// );
1881//}
1882//
1883//test "zig fmt: switch with empty body" {
1884// try testCanonical(
1885// \\test "" {
1886// \\ foo() catch |err| switch (err) {};
1887// \\}
1888// \\
1889// );
1890//}
1891//
1892//test "zig fmt: line comments in struct initializer" {
1893// try testCanonical(
1894// \\fn foo() void {
1895// \\ return Self{
1896// \\ .a = b,
1897// \\
1898// \\ // Initialize these two fields to buffer_size so that
1899// \\ // in `readFn` we treat the state as being able to read
1900// \\ .start_index = buffer_size,
1901// \\ .end_index = buffer_size,
1902// \\
1903// \\ // middle
1904// \\
1905// \\ .a = b,
1906// \\
1907// \\ // end
1908// \\ };
1909// \\}
1910// \\
1911// );
1912//}
1913//
1914//test "zig fmt: first line comment in struct initializer" {
1915// try testCanonical(
1916// \\pub fn acquire(self: *Self) HeldLock {
1917// \\ return HeldLock{
1918// \\ // guaranteed allocation elision
1919// \\ .held = self.lock.acquire(),
1920// \\ .value = &self.private_data,
1921// \\ };
1922// \\}
1923// \\
1924// );
1925//}
1926//
1927//test "zig fmt: doc comments before struct field" {
1928// try testCanonical(
1929// \\pub const Allocator = struct {
1930// \\ /// Allocate byte_count bytes and return them in a slice, with the
1931// \\ /// slice's pointer aligned at least to alignment bytes.
1932// \\ allocFn: fn () void,
1933// \\};
1934// \\
1935// );
1936//}
1937//
1938//test "zig fmt: error set declaration" {
1939// try testCanonical(
1940// \\const E = error{
1941// \\ A,
1942// \\ B,
1943// \\
1944// \\ C,
1945// \\};
1946// \\
1947// \\const Error = error{
1948// \\ /// no more memory
1949// \\ OutOfMemory,
1950// \\};
1951// \\
1952// \\const Error = error{
1953// \\ /// no more memory
1954// \\ OutOfMemory,
1955// \\
1956// \\ /// another
1957// \\ Another,
1958// \\
1959// \\ // end
1960// \\};
1961// \\
1962// \\const Error = error{OutOfMemory};
1963// \\const Error = error{};
1964// \\
1965// \\const Error = error{ OutOfMemory, OutOfTime };
1966// \\
1967// );
1968//}
1969//
1970//test "zig fmt: union(enum(u32)) with assigned enum values" {
1971// try testCanonical(
1972// \\const MultipleChoice = union(enum(u32)) {
1973// \\ A = 20,
1974// \\ B = 40,
1975// \\ C = 60,
1976// \\ D = 1000,
1977// \\};
1978// \\
1979// );
1980//}
1981//
1982//test "zig fmt: resume from suspend block" {
1983// try testCanonical(
1984// \\fn foo() void {
1985// \\ suspend {
1986// \\ resume @frame();
1987// \\ }
1988// \\}
1989// \\
1990// );
1991//}
1992//
1993//test "zig fmt: comments before error set decl" {
1994// try testCanonical(
1995// \\const UnexpectedError = error{
1996// \\ /// The Operating System returned an undocumented error code.
1997// \\ Unexpected,
1998// \\ // another
1999// \\ Another,
2000// \\
2001// \\ // in between
2002// \\
2003// \\ // at end
2004// \\};
2005// \\
2006// );
2007//}
2008//
2009//test "zig fmt: comments before switch prong" {
2010// try testCanonical(
2011// \\test "" {
2012// \\ switch (err) {
2013// \\ error.PathAlreadyExists => continue,
2014// \\
2015// \\ // comment 1
2016// \\
2017// \\ // comment 2
2018// \\ else => return err,
2019// \\ // at end
2020// \\ }
2021// \\}
2022// \\
2023// );
2024//}
2025//
2026//test "zig fmt: comments before var decl in struct" {
2027// try testCanonical(
2028// \\pub const vfs_cap_data = extern struct {
2029// \\ // All of these are mandated as little endian
2030// \\ // when on disk.
2031// \\ const Data = struct {
2032// \\ permitted: u32,
2033// \\ inheritable: u32,
2034// \\ };
2035// \\
2036// \\ // in between
2037// \\
2038// \\ /// All of these are mandated as little endian
2039// \\ /// when on disk.
2040// \\ const Data = struct {
2041// \\ permitted: u32,
2042// \\ inheritable: u32,
2043// \\ };
2044// \\
2045// \\ // at end
2046// \\};
2047// \\
2048// );
2049//}
2050//
2051//test "zig fmt: array literal with 1 item on 1 line" {
2052// try testCanonical(
2053// \\var s = []const u64{0} ** 25;
2054// \\
2055// );
2056//}
2057//
2058//test "zig fmt: comments before global variables" {
2059// try testCanonical(
2060// \\/// Foo copies keys and values before they go into the map, and
2061// \\/// frees them when they get removed.
2062// \\pub const Foo = struct {};
2063// \\
2064// );
2065//}
2066//
2067//test "zig fmt: comments in statements" {
2068// try testCanonical(
2069// \\test "std" {
2070// \\ // statement comment
2071// \\ _ = @import("foo/bar.zig");
2072// \\
2073// \\ // middle
2074// \\ // middle2
2075// \\
2076// \\ // end
2077// \\}
2078// \\
2079// );
2080//}
2081//
2082//test "zig fmt: comments before test decl" {
2083// try testCanonical(
2084// \\/// top level doc comment
2085// \\test "hi" {}
2086// \\
2087// \\// top level normal comment
2088// \\test "hi" {}
2089// \\
2090// \\// middle
2091// \\
2092// \\// end
2093// \\
2094// );
2095//}
2096//
2097//test "zig fmt: preserve spacing" {
2098// try testCanonical(
2099// \\const std = @import("std");
2100// \\
2101// \\pub fn main() !void {
2102// \\ var stdout_file = std.io.getStdOut;
2103// \\ var stdout_file = std.io.getStdOut;
2104// \\
2105// \\ var stdout_file = std.io.getStdOut;
2106// \\ var stdout_file = std.io.getStdOut;
2107// \\}
2108// \\
2109// );
2110//}
2111//
2112//test "zig fmt: return types" {
2113// try testCanonical(
2114// \\pub fn main() !void {}
2115// \\pub fn main() anytype {}
2116// \\pub fn main() i32 {}
2117// \\
2118// );
2119//}
2120//
2121//test "zig fmt: imports" {
2122// try testCanonical(
2123// \\const std = @import("std");
2124// \\const std = @import();
2125// \\
2126// );
2127//}
2128//
2129//test "zig fmt: global declarations" {
2130// try testCanonical(
2131// \\const a = b;
2132// \\pub const a = b;
2133// \\var a = b;
2134// \\pub var a = b;
2135// \\const a: i32 = b;
2136// \\pub const a: i32 = b;
2137// \\var a: i32 = b;
2138// \\pub var a: i32 = b;
2139// \\extern const a: i32 = b;
2140// \\pub extern const a: i32 = b;
2141// \\extern var a: i32 = b;
2142// \\pub extern var a: i32 = b;
2143// \\extern "a" const a: i32 = b;
2144// \\pub extern "a" const a: i32 = b;
2145// \\extern "a" var a: i32 = b;
2146// \\pub extern "a" var a: i32 = b;
2147// \\
2148// );
2149//}
2150//
2151//test "zig fmt: extern declaration" {
2152// try testCanonical(
2153// \\extern var foo: c_int;
2154// \\
2155// );
2156//}
2157//
2158//test "zig fmt: alignment" {
2159// try testCanonical(
2160// \\var foo: c_int align(1);
2161// \\
2162// );
2163//}
2164//
2165//test "zig fmt: C main" {
2166// try testCanonical(
2167// \\fn main(argc: c_int, argv: **u8) c_int {
2168// \\ const a = b;
2169// \\}
2170// \\
2171// );
2172//}
2173//
2174//test "zig fmt: return" {
2175// try testCanonical(
2176// \\fn foo(argc: c_int, argv: **u8) c_int {
2177// \\ return 0;
2178// \\}
2179// \\
2180// \\fn bar() void {
2181// \\ return;
2182// \\}
2183// \\
2184// );
2185//}
2186//
2187//test "zig fmt: pointer attributes" {
2188// try testCanonical(
2189// \\extern fn f1(s: *align(*u8) u8) c_int;
2190// \\extern fn f2(s: **align(1) *const *volatile u8) c_int;
2191// \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
2192// \\extern fn f4(s: *align(1) const volatile u8) c_int;
2193// \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int;
2194// \\
2195// );
2196//}
2197//
2198//test "zig fmt: slice attributes" {
2199// try testCanonical(
2200// \\extern fn f1(s: *align(*u8) u8) c_int;
2201// \\extern fn f2(s: **align(1) *const *volatile u8) c_int;
2202// \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
2203// \\extern fn f4(s: *align(1) const volatile u8) c_int;
2204// \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int;
2205// \\
2206// );
2207//}
2208//
2209//test "zig fmt: test declaration" {
2210// try testCanonical(
2211// \\test "test name" {
2212// \\ const a = 1;
2213// \\ var b = 1;
2214// \\}
2215// \\
2216// );
2217//}
2218//
2219//test "zig fmt: infix operators" {
2220// try testCanonical(
2221// \\test "infix operators" {
2222// \\ var i = undefined;
2223// \\ i = 2;
2224// \\ i *= 2;
2225// \\ i |= 2;
2226// \\ i ^= 2;
2227// \\ i <<= 2;
2228// \\ i >>= 2;
2229// \\ i &= 2;
2230// \\ i *= 2;
2231// \\ i *%= 2;
2232// \\ i -= 2;
2233// \\ i -%= 2;
2234// \\ i += 2;
2235// \\ i +%= 2;
2236// \\ i /= 2;
2237// \\ i %= 2;
2238// \\ _ = i == i;
2239// \\ _ = i != i;
2240// \\ _ = i != i;
2241// \\ _ = i.i;
2242// \\ _ = i || i;
2243// \\ _ = i!i;
2244// \\ _ = i ** i;
2245// \\ _ = i ++ i;
2246// \\ _ = i orelse i;
2247// \\ _ = i % i;
2248// \\ _ = i / i;
2249// \\ _ = i *% i;
2250// \\ _ = i * i;
2251// \\ _ = i -% i;
2252// \\ _ = i - i;
2253// \\ _ = i +% i;
2254// \\ _ = i + i;
2255// \\ _ = i << i;
2256// \\ _ = i >> i;
2257// \\ _ = i & i;
2258// \\ _ = i ^ i;
2259// \\ _ = i | i;
2260// \\ _ = i >= i;
2261// \\ _ = i <= i;
2262// \\ _ = i > i;
2263// \\ _ = i < i;
2264// \\ _ = i and i;
2265// \\ _ = i or i;
2266// \\}
2267// \\
2268// );
2269//}
2270//
2271//test "zig fmt: precedence" {
2272// try testCanonical(
2273// \\test "precedence" {
2274// \\ a!b();
2275// \\ (a!b)();
2276// \\ !a!b;
2277// \\ !(a!b);
2278// \\ !a{};
2279// \\ !(a{});
2280// \\ a + b{};
2281// \\ (a + b){};
2282// \\ a << b + c;
2283// \\ (a << b) + c;
2284// \\ a & b << c;
2285// \\ (a & b) << c;
2286// \\ a ^ b & c;
2287// \\ (a ^ b) & c;
2288// \\ a | b ^ c;
2289// \\ (a | b) ^ c;
2290// \\ a == b | c;
2291// \\ (a == b) | c;
2292// \\ a and b == c;
2293// \\ (a and b) == c;
2294// \\ a or b and c;
2295// \\ (a or b) and c;
2296// \\ (a or b) and c;
2297// \\}
2298// \\
2299// );
2300//}
2301//
2302//test "zig fmt: prefix operators" {
2303// try testCanonical(
2304// \\test "prefix operators" {
2305// \\ try return --%~!&0;
2306// \\}
2307// \\
2308// );
2309//}
2310//
2311//test "zig fmt: call expression" {
2312// try testCanonical(
2313// \\test "test calls" {
2314// \\ a();
2315// \\ a(1);
2316// \\ a(1, 2);
2317// \\ a(1, 2) + a(1, 2);
2318// \\}
2319// \\
2320// );
2321//}
2322//
2323//test "zig fmt: anytype type" {
2324// try testCanonical(
2325// \\fn print(args: anytype) anytype {}
2326// \\
2327// );
2328//}
2329//
2330//test "zig fmt: functions" {
2331// try testCanonical(
2332// \\extern fn puts(s: *const u8) c_int;
2333// \\extern "c" fn puts(s: *const u8) c_int;
2334// \\export fn puts(s: *const u8) c_int;
2335// \\inline fn puts(s: *const u8) c_int;
2336// \\noinline fn puts(s: *const u8) c_int;
2337// \\pub extern fn puts(s: *const u8) c_int;
2338// \\pub extern "c" fn puts(s: *const u8) c_int;
2339// \\pub export fn puts(s: *const u8) c_int;
2340// \\pub inline fn puts(s: *const u8) c_int;
2341// \\pub noinline fn puts(s: *const u8) c_int;
2342// \\pub extern fn puts(s: *const u8) align(2 + 2) c_int;
2343// \\pub extern "c" fn puts(s: *const u8) align(2 + 2) c_int;
2344// \\pub export fn puts(s: *const u8) align(2 + 2) c_int;
2345// \\pub inline fn puts(s: *const u8) align(2 + 2) c_int;
2346// \\pub noinline fn puts(s: *const u8) align(2 + 2) c_int;
2347// \\
2348// );
2349//}
2350//
2351//test "zig fmt: multiline string" {
2352// try testCanonical(
2353// \\test "" {
2354// \\ const s1 =
2355// \\ \\one
2356// \\ \\two)
2357// \\ \\three
2358// \\ ;
2359// \\ const s3 = // hi
2360// \\ \\one
2361// \\ \\two)
2362// \\ \\three
2363// \\ ;
2364// \\}
2365// \\
2366// );
2367//}
2368//
2369//test "zig fmt: values" {
2370// try testCanonical(
2371// \\test "values" {
2372// \\ 1;
2373// \\ 1.0;
2374// \\ "string";
2375// \\ 'c';
2376// \\ true;
2377// \\ false;
2378// \\ null;
2379// \\ undefined;
2380// \\ anyerror;
2381// \\ this;
2382// \\ unreachable;
2383// \\}
2384// \\
2385// );
2386//}
2387//
2388//test "zig fmt: indexing" {
2389// try testCanonical(
2390// \\test "test index" {
2391// \\ a[0];
2392// \\ a[0 + 5];
2393// \\ a[0..];
2394// \\ a[0..5];
2395// \\ a[a[0]];
2396// \\ a[a[0..]];
2397// \\ a[a[0..5]];
2398// \\ a[a[0]..];
2399// \\ a[a[0..5]..];
2400// \\ a[a[0]..a[0]];
2401// \\ a[a[0..5]..a[0]];
2402// \\ a[a[0..5]..a[0..5]];
2403// \\}
2404// \\
2405// );
2406//}
2407//
2408//test "zig fmt: struct declaration" {
2409// try testCanonical(
2410// \\const S = struct {
2411// \\ const Self = @This();
2412// \\ f1: u8,
2413// \\ f3: u8,
2414// \\
2415// \\ f2: u8,
2416// \\
2417// \\ fn method(self: *Self) Self {
2418// \\ return self.*;
2419// \\ }
2420// \\};
2421// \\
2422// \\const Ps = packed struct {
2423// \\ a: u8,
2424// \\ b: u8,
2425// \\
2426// \\ c: u8,
2427// \\};
2428// \\
2429// \\const Es = extern struct {
2430// \\ a: u8,
2431// \\ b: u8,
2432// \\
2433// \\ c: u8,
2434// \\};
2435// \\
2436// );
2437//}
2438//
2439//test "zig fmt: enum declaration" {
2440// try testCanonical(
2441// \\const E = enum {
2442// \\ Ok,
2443// \\ SomethingElse = 0,
2444// \\};
2445// \\
2446// \\const E2 = enum(u8) {
2447// \\ Ok,
2448// \\ SomethingElse = 255,
2449// \\ SomethingThird,
2450// \\};
2451// \\
2452// \\const Ee = extern enum {
2453// \\ Ok,
2454// \\ SomethingElse,
2455// \\ SomethingThird,
2456// \\};
2457// \\
2458// \\const Ep = packed enum {
2459// \\ Ok,
2460// \\ SomethingElse,
2461// \\ SomethingThird,
2462// \\};
2463// \\
2464// );
2465//}
2466//
2467//test "zig fmt: union declaration" {
2468// try testCanonical(
2469// \\const U = union {
2470// \\ Int: u8,
2471// \\ Float: f32,
2472// \\ None,
2473// \\ Bool: bool,
2474// \\};
2475// \\
2476// \\const Ue = union(enum) {
2477// \\ Int: u8,
2478// \\ Float: f32,
2479// \\ None,
2480// \\ Bool: bool,
2481// \\};
2482// \\
2483// \\const E = enum {
2484// \\ Int,
2485// \\ Float,
2486// \\ None,
2487// \\ Bool,
2488// \\};
2489// \\
2490// \\const Ue2 = union(E) {
2491// \\ Int: u8,
2492// \\ Float: f32,
2493// \\ None,
2494// \\ Bool: bool,
2495// \\};
2496// \\
2497// \\const Eu = extern union {
2498// \\ Int: u8,
2499// \\ Float: f32,
2500// \\ None,
2501// \\ Bool: bool,
2502// \\};
2503// \\
2504// );
2505//}
2506//
2507//test "zig fmt: arrays" {
2508// try testCanonical(
2509// \\test "test array" {
2510// \\ const a: [2]u8 = [2]u8{
2511// \\ 1,
2512// \\ 2,
2513// \\ };
2514// \\ const a: [2]u8 = []u8{
2515// \\ 1,
2516// \\ 2,
2517// \\ };
2518// \\ const a: [0]u8 = []u8{};
2519// \\ const x: [4:0]u8 = undefined;
2520// \\}
2521// \\
2522// );
2523//}
2524//
2525//test "zig fmt: container initializers" {
2526// try testCanonical(
2527// \\const a0 = []u8{};
2528// \\const a1 = []u8{1};
2529// \\const a2 = []u8{
2530// \\ 1,
2531// \\ 2,
2532// \\ 3,
2533// \\ 4,
2534// \\};
2535// \\const s0 = S{};
2536// \\const s1 = S{ .a = 1 };
2537// \\const s2 = S{
2538// \\ .a = 1,
2539// \\ .b = 2,
2540// \\};
2541// \\
2542// );
2543//}
2544//
2545//test "zig fmt: catch" {
2546// try testCanonical(
2547// \\test "catch" {
2548// \\ const a: anyerror!u8 = 0;
2549// \\ _ = a catch return;
2550// \\ _ = a catch |err| return;
2551// \\}
2552// \\
2553// );
2554//}
2555//
2556//test "zig fmt: blocks" {
2557// try testCanonical(
2558// \\test "blocks" {
2559// \\ {
2560// \\ const a = 0;
2561// \\ const b = 0;
2562// \\ }
2563// \\
2564// \\ blk: {
2565// \\ const a = 0;
2566// \\ const b = 0;
2567// \\ }
2568// \\
2569// \\ const r = blk: {
2570// \\ const a = 0;
2571// \\ const b = 0;
2572// \\ };
2573// \\}
2574// \\
2575// );
2576//}
2577//
2578//test "zig fmt: switch" {
2579// try testCanonical(
2580// \\test "switch" {
2581// \\ switch (0) {
2582// \\ 0 => {},
2583// \\ 1 => unreachable,
2584// \\ 2, 3 => {},
2585// \\ 4...7 => {},
2586// \\ 1 + 4 * 3 + 22 => {},
2587// \\ else => {
2588// \\ const a = 1;
2589// \\ const b = a;
2590// \\ },
2591// \\ }
2592// \\
2593// \\ const res = switch (0) {
2594// \\ 0 => 0,
2595// \\ 1 => 2,
2596// \\ 1 => a = 4,
2597// \\ else => 4,
2598// \\ };
2599// \\
2600// \\ const Union = union(enum) {
2601// \\ Int: i64,
2602// \\ Float: f64,
2603// \\ };
2604// \\
2605// \\ switch (u) {
2606// \\ Union.Int => |int| {},
2607// \\ Union.Float => |*float| unreachable,
2608// \\ }
2609// \\}
2610// \\
2611// );
2612//}
2613//
2614//test "zig fmt: while" {
2615// try testCanonical(
2616// \\test "while" {
2617// \\ while (10 < 1) unreachable;
2618// \\
2619// \\ while (10 < 1) unreachable else unreachable;
2620// \\
2621// \\ while (10 < 1) {
2622// \\ unreachable;
2623// \\ }
2624// \\
2625// \\ while (10 < 1)
2626// \\ unreachable;
2627// \\
2628// \\ var i: usize = 0;
2629// \\ while (i < 10) : (i += 1) {
2630// \\ continue;
2631// \\ }
2632// \\
2633// \\ i = 0;
2634// \\ while (i < 10) : (i += 1)
2635// \\ continue;
2636// \\
2637// \\ i = 0;
2638// \\ var j: usize = 0;
2639// \\ while (i < 10) : ({
2640// \\ i += 1;
2641// \\ j += 1;
2642// \\ }) {
2643// \\ continue;
2644// \\ }
2645// \\
2646// \\ var a: ?u8 = 2;
2647// \\ while (a) |v| : (a = null) {
2648// \\ continue;
2649// \\ }
2650// \\
2651// \\ while (a) |v| : (a = null)
2652// \\ unreachable;
2653// \\
2654// \\ label: while (10 < 0) {
2655// \\ unreachable;
2656// \\ }
2657// \\
2658// \\ const res = while (0 < 10) {
2659// \\ break 7;
2660// \\ } else {
2661// \\ unreachable;
2662// \\ };
2663// \\
2664// \\ const res = while (0 < 10)
2665// \\ break 7
2666// \\ else
2667// \\ unreachable;
2668// \\
2669// \\ var a: anyerror!u8 = 0;
2670// \\ while (a) |v| {
2671// \\ a = error.Err;
2672// \\ } else |err| {
2673// \\ i = 1;
2674// \\ }
2675// \\
2676// \\ comptime var k: usize = 0;
2677// \\ inline while (i < 10) : (i += 1)
2678// \\ j += 2;
2679// \\}
2680// \\
2681// );
2682//}
2683//
2684//test "zig fmt: for" {
2685// try testCanonical(
2686// \\test "for" {
2687// \\ for (a) |v| {
2688// \\ continue;
2689// \\ }
2690// \\
2691// \\ for (a) |v| continue;
2692// \\
2693// \\ for (a) |v| continue else return;
2694// \\
2695// \\ for (a) |v| {
2696// \\ continue;
2697// \\ } else return;
2698// \\
2699// \\ for (a) |v| continue else {
2700// \\ return;
2701// \\ }
2702// \\
2703// \\ for (a) |v|
2704// \\ continue
2705// \\ else
2706// \\ return;
2707// \\
2708// \\ for (a) |v|
2709// \\ continue;
2710// \\
2711// \\ for (a) |*v|
2712// \\ continue;
2713// \\
2714// \\ for (a) |v, i| {
2715// \\ continue;
2716// \\ }
2717// \\
2718// \\ for (a) |v, i|
2719// \\ continue;
2720// \\
2721// \\ for (a) |b| switch (b) {
2722// \\ c => {},
2723// \\ d => {},
2724// \\ };
2725// \\
2726// \\ for (a) |b|
2727// \\ switch (b) {
2728// \\ c => {},
2729// \\ d => {},
2730// \\ };
2731// \\
2732// \\ const res = for (a) |v, i| {
2733// \\ break v;
2734// \\ } else {
2735// \\ unreachable;
2736// \\ };
2737// \\
2738// \\ var num: usize = 0;
2739// \\ inline for (a) |v, i| {
2740// \\ num += v;
2741// \\ num += i;
2742// \\ }
2743// \\}
2744// \\
2745// );
2746//
2747// try testTransform(
2748// \\test "fix for" {
2749// \\ for (a) |x|
2750// \\ f(x) else continue;
2751// \\}
2752// \\
2753// ,
2754// \\test "fix for" {
2755// \\ for (a) |x|
2756// \\ f(x)
2757// \\ else continue;
2758// \\}
2759// \\
2760// );
2761//}
2762//
2763//test "zig fmt: if" {
2764// try testCanonical(
2765// \\test "if" {
2766// \\ if (10 < 0) {
2767// \\ unreachable;
2768// \\ }
2769// \\
2770// \\ if (10 < 0) unreachable;
2771// \\
2772// \\ if (10 < 0) {
2773// \\ unreachable;
2774// \\ } else {
2775// \\ const a = 20;
2776// \\ }
2777// \\
2778// \\ if (10 < 0) {
2779// \\ unreachable;
2780// \\ } else if (5 < 0) {
2781// \\ unreachable;
2782// \\ } else {
2783// \\ const a = 20;
2784// \\ }
2785// \\
2786// \\ const is_world_broken = if (10 < 0) true else false;
2787// \\ const some_number = 1 + if (10 < 0) 2 else 3;
2788// \\
2789// \\ const a: ?u8 = 10;
2790// \\ const b: ?u8 = null;
2791// \\ if (a) |v| {
2792// \\ const some = v;
2793// \\ } else if (b) |*v| {
2794// \\ unreachable;
2795// \\ } else {
2796// \\ const some = 10;
2797// \\ }
2798// \\
2799// \\ const non_null_a = if (a) |v| v else 0;
2800// \\
2801// \\ const a_err: anyerror!u8 = 0;
2802// \\ if (a_err) |v| {
2803// \\ const p = v;
2804// \\ } else |err| {
2805// \\ unreachable;
2806// \\ }
2807// \\}
2808// \\
2809// );
2810//}
2811//
2812//test "zig fmt: defer" {
2813// try testCanonical(
2814// \\test "defer" {
2815// \\ var i: usize = 0;
2816// \\ defer i = 1;
2817// \\ defer {
2818// \\ i += 2;
2819// \\ i *= i;
2820// \\ }
2821// \\
2822// \\ errdefer i += 3;
2823// \\ errdefer {
2824// \\ i += 2;
2825// \\ i /= i;
2826// \\ }
2827// \\}
2828// \\
2829// );
2830//}
2831//
2832//test "zig fmt: comptime" {
2833// try testCanonical(
2834// \\fn a() u8 {
2835// \\ return 5;
2836// \\}
2837// \\
2838// \\fn b(comptime i: u8) u8 {
2839// \\ return i;
2840// \\}
2841// \\
2842// \\const av = comptime a();
2843// \\const av2 = comptime blk: {
2844// \\ var res = a();
2845// \\ res *= b(2);
2846// \\ break :blk res;
2847// \\};
2848// \\
2849// \\comptime {
2850// \\ _ = a();
2851// \\}
2852// \\
2853// \\test "comptime" {
2854// \\ const av3 = comptime a();
2855// \\ const av4 = comptime blk: {
2856// \\ var res = a();
2857// \\ res *= a();
2858// \\ break :blk res;
2859// \\ };
2860// \\
2861// \\ comptime var i = 0;
2862// \\ comptime {
2863// \\ i = a();
2864// \\ i += b(i);
2865// \\ }
2866// \\}
2867// \\
2868// );
2869//}
2870//
2871//test "zig fmt: fn type" {
2872// try testCanonical(
2873// \\fn a(i: u8) u8 {
2874// \\ return i + 1;
2875// \\}
2876// \\
2877// \\const a: fn (u8) u8 = undefined;
2878// \\const b: fn (u8) callconv(.Naked) u8 = undefined;
2879// \\const ap: fn (u8) u8 = a;
2880// \\
2881// );
2882//}
2883//
2884//test "zig fmt: inline asm" {
2885// try testCanonical(
2886// \\pub fn syscall1(number: usize, arg1: usize) usize {
2887// \\ return asm volatile ("syscall"
2888// \\ : [ret] "={rax}" (-> usize)
2889// \\ : [number] "{rax}" (number),
2890// \\ [arg1] "{rdi}" (arg1)
2891// \\ : "rcx", "r11"
2892// \\ );
2893// \\}
2894// \\
2895// );
2896//}
2897//
2898//test "zig fmt: async functions" {
2899// try testCanonical(
2900// \\fn simpleAsyncFn() void {
2901// \\ const a = async a.b();
2902// \\ x += 1;
2903// \\ suspend;
2904// \\ x += 1;
2905// \\ suspend;
2906// \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable;
2907// \\ await p;
2908// \\}
2909// \\
2910// \\test "suspend, resume, await" {
2911// \\ const p: anyframe = async testAsyncSeq();
2912// \\ resume p;
2913// \\ await p;
2914// \\}
2915// \\
2916// );
2917//}
2918//
2919//test "zig fmt: nosuspend" {
2920// try testCanonical(
2921// \\const a = nosuspend foo();
2922// \\
2923// );
2924//}
2925//
2926//test "zig fmt: Block after if" {
2927// try testCanonical(
2928// \\test "Block after if" {
2929// \\ if (true) {
2930// \\ const a = 0;
2931// \\ }
2932// \\
2933// \\ {
2934// \\ const a = 0;
2935// \\ }
2936// \\}
2937// \\
2938// );
2939//}
2940//
2941//test "zig fmt: use" {
2942// try testCanonical(
2943// \\usingnamespace @import("std");
2944// \\pub usingnamespace @import("std");
2945// \\
2946// );
2947//}
2948//
2949//test "zig fmt: string identifier" {
2950// try testCanonical(
2951// \\const @"a b" = @"c d".@"e f";
2952// \\fn @"g h"() void {}
2953// \\
2954// );
2955//}
2956//
2957//test "zig fmt: error return" {
2958// try testCanonical(
2959// \\fn err() anyerror {
2960// \\ call();
2961// \\ return error.InvalidArgs;
2962// \\}
2963// \\
2964// );
2965//}
2966//
2967//test "zig fmt: comptime block in container" {
2968// try testCanonical(
2969// \\pub fn container() type {
2970// \\ return struct {
2971// \\ comptime {
2972// \\ if (false) {
2973// \\ unreachable;
2974// \\ }
2975// \\ }
2976// \\ };
2977// \\}
2978// \\
2979// );
2980//}
2981//
2982//test "zig fmt: inline asm parameter alignment" {
2983// try testCanonical(
2984// \\pub fn main() void {
2985// \\ asm volatile (
2986// \\ \\ foo
2987// \\ \\ bar
2988// \\ );
2989// \\ asm volatile (
2990// \\ \\ foo
2991// \\ \\ bar
2992// \\ : [_] "" (-> usize),
2993// \\ [_] "" (-> usize)
2994// \\ );
2995// \\ asm volatile (
2996// \\ \\ foo
2997// \\ \\ bar
2998// \\ :
2999// \\ : [_] "" (0),
3000// \\ [_] "" (0)
3001// \\ );
3002// \\ asm volatile (
3003// \\ \\ foo
3004// \\ \\ bar
3005// \\ :
3006// \\ :
3007// \\ : "", ""
3008// \\ );
3009// \\ asm volatile (
3010// \\ \\ foo
3011// \\ \\ bar
3012// \\ : [_] "" (-> usize),
3013// \\ [_] "" (-> usize)
3014// \\ : [_] "" (0),
3015// \\ [_] "" (0)
3016// \\ : "", ""
3017// \\ );
3018// \\}
3019// \\
3020// );
3021//}
3022//
3023//test "zig fmt: multiline string in array" {
3024// try testCanonical(
3025// \\const Foo = [][]const u8{
3026// \\ \\aaa
3027// \\ ,
3028// \\ \\bbb
3029// \\};
3030// \\
3031// \\fn bar() void {
3032// \\ const Foo = [][]const u8{
3033// \\ \\aaa
3034// \\ ,
3035// \\ \\bbb
3036// \\ };
3037// \\ const Bar = [][]const u8{ // comment here
3038// \\ \\aaa
3039// \\ \\
3040// \\ , // and another comment can go here
3041// \\ \\bbb
3042// \\ };
3043// \\}
3044// \\
3045// );
3046//}
3047//
3048//test "zig fmt: if type expr" {
3049// try testCanonical(
3050// \\const mycond = true;
3051// \\pub fn foo() if (mycond) i32 else void {
3052// \\ if (mycond) {
3053// \\ return 42;
3054// \\ }
3055// \\}
3056// \\
3057// );
3058//}
3059//test "zig fmt: file ends with struct field" {
3060// try testCanonical(
3061// \\a: bool
3062// \\
3063// );
3064//}
3065//
3066//test "zig fmt: comment after empty comment" {
3067// try testTransform(
3068// \\const x = true; //
3069// \\//
3070// \\//
3071// \\//a
3072// \\
3073// ,
3074// \\const x = true;
3075// \\//a
3076// \\
3077// );
3078//}
3079//
3080//test "zig fmt: line comment in array" {
3081// try testTransform(
3082// \\test "a" {
3083// \\ var arr = [_]u32{
3084// \\ 0
3085// \\ // 1,
3086// \\ // 2,
3087// \\ };
3088// \\}
3089// \\
3090// ,
3091// \\test "a" {
3092// \\ var arr = [_]u32{
3093// \\ 0, // 1,
3094// \\ // 2,
3095// \\ };
3096// \\}
3097// \\
3098// );
3099// try testCanonical(
3100// \\test "a" {
3101// \\ var arr = [_]u32{
3102// \\ 0,
3103// \\ // 1,
3104// \\ // 2,
3105// \\ };
3106// \\}
3107// \\
3108// );
3109//}
3110//
3111//test "zig fmt: comment after params" {
3112// try testTransform(
3113// \\fn a(
3114// \\ b: u32
3115// \\ // c: u32,
3116// \\ // d: u32,
3117// \\) void {}
3118// \\
3119// ,
3120// \\fn a(
3121// \\ b: u32, // c: u32,
3122// \\ // d: u32,
3123// \\) void {}
3124// \\
3125// );
3126// try testCanonical(
3127// \\fn a(
3128// \\ b: u32,
3129// \\ // c: u32,
3130// \\ // d: u32,
3131// \\) void {}
3132// \\
3133// );
3134//}
3135//
3136//test "zig fmt: comment in array initializer/access" {
3137// try testCanonical(
3138// \\test "a" {
3139// \\ var a = x{ //aa
3140// \\ //bb
3141// \\ };
3142// \\ var a = []x{ //aa
3143// \\ //bb
3144// \\ };
3145// \\ var b = [ //aa
3146// \\ _
3147// \\ ]x{ //aa
3148// \\ //bb
3149// \\ 9,
3150// \\ };
3151// \\ var c = b[ //aa
3152// \\ 0
3153// \\ ];
3154// \\ var d = [_
3155// \\ //aa
3156// \\ ]x{ //aa
3157// \\ //bb
3158// \\ 9,
3159// \\ };
3160// \\ var e = d[0
3161// \\ //aa
3162// \\ ];
3163// \\}
3164// \\
3165// );
3166//}
3167//
3168//test "zig fmt: comments at several places in struct init" {
3169// try testTransform(
3170// \\var bar = Bar{
3171// \\ .x = 10, // test
3172// \\ .y = "test"
3173// \\ // test
3174// \\};
3175// \\
3176// ,
3177// \\var bar = Bar{
3178// \\ .x = 10, // test
3179// \\ .y = "test", // test
3180// \\};
3181// \\
3182// );
3183//
3184// try testCanonical(
3185// \\var bar = Bar{ // test
3186// \\ .x = 10, // test
3187// \\ .y = "test",
3188// \\ // test
3189// \\};
3190// \\
3191// );
3192//}
3193//
3194//test "zig fmt: top level doc comments" {
3195// try testCanonical(
3196// \\//! tld 1
3197// \\//! tld 2
3198// \\//! tld 3
3199// \\
3200// \\// comment
3201// \\
3202// \\/// A doc
3203// \\const A = struct {
3204// \\ //! A tld 1
3205// \\ //! A tld 2
3206// \\ //! A tld 3
3207// \\};
3208// \\
3209// \\/// B doc
3210// \\const B = struct {
3211// \\ //! B tld 1
3212// \\ //! B tld 2
3213// \\ //! B tld 3
3214// \\
3215// \\ /// b doc
3216// \\ b: u32,
3217// \\};
3218// \\
3219// \\/// C doc
3220// \\const C = struct {
3221// \\ //! C tld 1
3222// \\ //! C tld 2
3223// \\ //! C tld 3
3224// \\
3225// \\ /// c1 doc
3226// \\ c1: u32,
3227// \\
3228// \\ //! C tld 4
3229// \\ //! C tld 5
3230// \\ //! C tld 6
3231// \\
3232// \\ /// c2 doc
3233// \\ c2: u32,
3234// \\};
3235// \\
3236// );
3237// try testCanonical(
3238// \\//! Top-level documentation.
3239// \\
3240// \\/// This is A
3241// \\pub const A = usize;
3242// \\
3243// );
3244// try testCanonical(
3245// \\//! Nothing here
3246// \\
3247// );
3248//}
3249//
3250//test "zig fmt: extern without container keyword returns error" {
3251// try testError(
3252// \\const container = extern {};
3253// \\
3254// , &[_]Error{
3255// .ExpectedExpr,
3256// .ExpectedVarDeclOrFn,
3257// });
3258//}
3259//
3260//test "zig fmt: integer literals with underscore separators" {
3261// try testTransform(
3262// \\const
3263// \\ x =
3264// \\ 1_234_567
3265// \\ +(0b0_1-0o7_0+0xff_FF ) + 0_0;
3266// ,
3267// \\const x =
3268// \\ 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0;
3269// \\
3270// );
3271//}
3272//
3273//test "zig fmt: hex literals with underscore separators" {
3274// try testTransform(
3275// \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 {
3276// \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000;
3277// \\ for (c [ 0_0 .. ]) |_, i| {
3278// \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
3279// \\ }
3280// \\ return c;
3281// \\}
3282// \\
3283// \\
3284// ,
3285// \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 {
3286// \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000;
3287// \\ for (c[0_0..]) |_, i| {
3288// \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
3289// \\ }
3290// \\ return c;
3291// \\}
3292// \\
3293// );
3294//}
3295//
3296//test "zig fmt: decimal float literals with underscore separators" {
3297// try testTransform(
3298// \\pub fn main() void {
3299// \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4;
3300// \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2;
3301// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
3302// \\}
3303// ,
3304// \\pub fn main() void {
3305// \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4;
3306// \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2;
3307// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
3308// \\}
3309// \\
3310// );
3311//}
3312//
3313//test "zig fmt: hexadeciaml float literals with underscore separators" {
3314// try testTransform(
3315// \\pub fn main() void {
3316// \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16;
3317// \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4;
3318// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
3319// \\}
3320// ,
3321// \\pub fn main() void {
3322// \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16;
3323// \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4;
3324// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
3325// \\}
3326// \\
3327// );
3328//}
3329//
3330//test "zig fmt: convert async fn into callconv(.Async)" {
3331// try testTransform(
3332// \\async fn foo() void {}
3333// ,
3334// \\fn foo() callconv(.Async) void {}
3335// \\
3336// );
3337//}
3338//
3339//test "zig fmt: convert extern fn proto into callconv(.C)" {
3340// try testTransform(
3341// \\extern fn foo0() void {}
3342// \\const foo1 = extern fn () void;
3343// ,
3344// \\extern fn foo0() void {}
3345// \\const foo1 = fn () callconv(.C) void;
3346// \\
3347// );
3348//}
3349//
3350//test "zig fmt: C var args" {
3351// try testCanonical(
3352// \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3353// \\
3354// );
3355//}
3356//
3357//test "zig fmt: Only indent multiline string literals in function calls" {
3358// try testCanonical(
3359// \\test "zig fmt:" {
3360// \\ try testTransform(
3361// \\ \\const X = struct {
3362// \\ \\ foo: i32, bar: i8 };
3363// \\ ,
3364// \\ \\const X = struct {
3365// \\ \\ foo: i32, bar: i8
3366// \\ \\};
3367// \\ \\
3368// \\ );
3369// \\}
3370// \\
3371// );
3372//}
3373//
3374//test "zig fmt: Don't add extra newline after if" {
3375// try testCanonical(
3376// \\pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
3377// \\ if (cwd().symLink(existing_path, new_path, .{})) {
3378// \\ return;
3379// \\ }
3380// \\}
3381// \\
3382// );
3383//}
3384//
3385//test "zig fmt: comments in ternary ifs" {
3386// try testCanonical(
3387// \\const x = if (true) {
3388// \\ 1;
3389// \\} else if (false)
3390// \\ // Comment
3391// \\ 0;
3392// \\const y = if (true)
3393// \\ // Comment
3394// \\ 1
3395// \\else
3396// \\ 0;
3397// \\
3398// \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3399// \\
3400// );
3401//}
3402//
3403//test "zig fmt: test comments in field access chain" {
3404// try testCanonical(
3405// \\pub const str = struct {
3406// \\ pub const Thing = more.more //
3407// \\ .more() //
3408// \\ .more().more() //
3409// \\ .more() //
3410// \\ // .more() //
3411// \\ .more() //
3412// \\ .more();
3413// \\ data: Data,
3414// \\};
3415// \\
3416// \\pub const str = struct {
3417// \\ pub const Thing = more.more //
3418// \\ .more() //
3419// \\ // .more() //
3420// \\ // .more() //
3421// \\ // .more() //
3422// \\ .more() //
3423// \\ .more();
3424// \\ data: Data,
3425// \\};
3426// \\
3427// \\pub const str = struct {
3428// \\ pub const Thing = more //
3429// \\ .more //
3430// \\ .more() //
3431// \\ .more();
3432// \\ data: Data,
3433// \\};
3434// \\
3435// );
3436//}
3437//
3438//test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" {
3439// try testCanonical(
3440// \\fn foo() void {
3441// \\ z.display_message_dialog(
3442// \\ *const [323:0]u8,
3443// \\ \\Message Text
3444// \\ \\------------
3445// \\ \\xxxxxxxxxxxx
3446// \\ \\xxxxxxxxxxxx
3447// \\ ,
3448// \\ g.GtkMessageType.GTK_MESSAGE_WARNING,
3449// \\ null,
3450// \\ );
3451// \\
3452// \\ z.display_message_dialog(*const [323:0]u8,
3453// \\ \\Message Text
3454// \\ \\------------
3455// \\ \\xxxxxxxxxxxx
3456// \\ \\xxxxxxxxxxxx
3457// \\ , g.GtkMessageType.GTK_MESSAGE_WARNING, null);
3458// \\}
3459// \\
3460// );
3461//}
3462//
3463//test "zig fmt: Control flow statement as body of blockless if" {
3464// try testCanonical(
3465// \\pub fn main() void {
3466// \\ const zoom_node = if (focused_node == layout_first)
3467// \\ if (it.next()) {
3468// \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3469// \\ } else null
3470// \\ else
3471// \\ focused_node;
3472// \\
3473// \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
3474// \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3475// \\ } else null else
3476// \\ focused_node;
3477// \\
3478// \\ const zoom_node = if (focused_node == layout_first)
3479// \\ if (it.next()) {
3480// \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3481// \\ } else null;
3482// \\
3483// \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
3484// \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3485// \\ };
3486// \\
3487// \\ const zoom_node = if (focused_node == layout_first) for (nodes) |node| {
3488// \\ break node;
3489// \\ };
3490// \\
3491// \\ const zoom_node = if (focused_node == layout_first) switch (nodes) {
3492// \\ 0 => 0,
3493// \\ } else
3494// \\ focused_node;
3495// \\}
3496// \\
3497// );
3498//}
3499//
3500//test "zig fmt: " {
3501// try testCanonical(
3502// \\pub fn sendViewTags(self: Self) void {
3503// \\ var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
3504// \\ while (it.next()) |node|
3505// \\ view_tags.append(node.view.current_tags) catch {
3506// \\ c.wl_resource_post_no_memory(self.wl_resource);
3507// \\ log.crit(.river_status, "out of memory", .{});
3508// \\ return;
3509// \\ };
3510// \\}
3511// \\
3512// );
3513//}
3514//
3515//test "zig fmt: allow trailing line comments to do manual array formatting" {
3516// try testCanonical(
3517// \\fn foo() void {
3518// \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3519// \\ 0x55, // push rbp
3520// \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3521// \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3522// \\ });
3523// \\
3524// \\ di_buf.appendAssumeCapacity(&[_]u8{
3525// \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header
3526// \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs
3527// \\ DW.AT_low_pc, DW_FORM_addr,
3528// \\ DW.AT_high_pc, DW_FORM_addr,
3529// \\ DW.AT_name, DW_FORM_strp,
3530// \\ DW.AT_comp_dir, DW_FORM_strp,
3531// \\ DW.AT_producer, DW_FORM_strp,
3532// \\ DW.AT_language, DW_FORM_data2,
3533// \\ 0, 0, // sentinel
3534// \\ });
3535// \\
3536// \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3537// \\ 0x55, // push rbp
3538// \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3539// \\ // How do we handle this?
3540// \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3541// \\ // Here's a blank line, should that be allowed?
3542// \\
3543// \\ 0x48, 0x89, 0xe5,
3544// \\ 0x33, 0x45,
3545// \\ // Now the comment breaks a single line -- how do we handle this?
3546// \\ 0x88,
3547// \\ });
3548// \\}
3549// \\
3550// );
3551//}
3552//
3553//test "zig fmt: multiline string literals should play nice with array initializers" {
3554// try testCanonical(
3555// \\fn main() void {
3556// \\ var a = .{.{.{.{.{.{.{.{
3557// \\ 0,
3558// \\ }}}}}}}};
3559// \\ myFunc(.{
3560// \\ "aaaaaaa", "bbbbbb", "ccccc",
3561// \\ "dddd", ("eee"), ("fff"),
3562// \\ ("gggg"),
3563// \\ // Line comment
3564// \\ \\Multiline String Literals can be quite long
3565// \\ ,
3566// \\ \\Multiline String Literals can be quite long
3567// \\ \\Multiline String Literals can be quite long
3568// \\ ,
3569// \\ \\Multiline String Literals can be quite long
3570// \\ \\Multiline String Literals can be quite long
3571// \\ \\Multiline String Literals can be quite long
3572// \\ \\Multiline String Literals can be quite long
3573// \\ ,
3574// \\ (
3575// \\ \\Multiline String Literals can be quite long
3576// \\ ),
3577// \\ .{
3578// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3579// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3580// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3581// \\ },
3582// \\ .{(
3583// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3584// \\ )},
3585// \\ .{
3586// \\ "xxxxxxx", "xxx",
3587// \\ (
3588// \\ \\ xxx
3589// \\ ),
3590// \\ "xxx", "xxx",
3591// \\ },
3592// \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" },
3593// \\ "aaaaaaa", "bbbbbb", "ccccc", // -
3594// \\ "dddd", ("eee"), ("fff"),
3595// \\ .{
3596// \\ "xxx", "xxx",
3597// \\ (
3598// \\ \\ xxx
3599// \\ ),
3600// \\ "xxxxxxxxxxxxxx", "xxx",
3601// \\ },
3602// \\ .{
3603// \\ (
3604// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3605// \\ ),
3606// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3607// \\ },
3608// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3609// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3610// \\ });
3611// \\}
3612// \\
3613// );
3614//}
3615//
3616//test "zig fmt: use of comments and Multiline string literals may force the parameters over multiple lines" {
3617// try testCanonical(
3618// \\pub fn makeMemUndefined(qzz: []u8) i1 {
3619// \\ cases.add( // fixed bug #2032
3620// \\ "compile diagnostic string for top level decl type",
3621// \\ \\export fn entry() void {
3622// \\ \\ var foo: u32 = @This(){};
3623// \\ \\}
3624// \\ , &[_][]const u8{
3625// \\ "tmp.zig:2:27: error: type 'u32' does not support array initialization",
3626// \\ });
3627// \\ @compileError(
3628// \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
3629// \\ \\ Consider providing your own hash function.
3630// \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
3631// \\ \\ Consider providing your own hash function.
3632// \\ );
3633// \\ return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
3634// \\ .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
3635// \\}
3636// \\
3637// \\// This looks like garbage don't do this
3638// \\const rparen = tree.prevToken(
3639// \\// the first token for the annotation expressions is the left
3640// \\// parenthesis, hence the need for two prevToken
3641// \\ if (fn_proto.getAlignExpr()) |align_expr|
3642// \\ tree.prevToken(tree.prevToken(align_expr.firstToken()))
3643// \\else if (fn_proto.getSectionExpr()) |section_expr|
3644// \\ tree.prevToken(tree.prevToken(section_expr.firstToken()))
3645// \\else if (fn_proto.getCallconvExpr()) |callconv_expr|
3646// \\ tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
3647// \\else switch (fn_proto.return_type) {
3648// \\ .Explicit => |node| node.firstToken(),
3649// \\ .InferErrorSet => |node| tree.prevToken(node.firstToken()),
3650// \\ .Invalid => unreachable,
3651// \\});
3652// \\
3653// );
3654//}
3655//
3656//test "zig fmt: single argument trailing commas in @builtins()" {
3657// try testCanonical(
3658// \\pub fn foo(qzz: []u8) i1 {
3659// \\ @panic(
3660// \\ foo,
3661// \\ );
3662// \\ panic(
3663// \\ foo,
3664// \\ );
3665// \\ @panic(
3666// \\ foo,
3667// \\ bar,
3668// \\ );
3669// \\}
3670// \\
3671// );
3672//}
3673//
3674//test "zig fmt: trailing comma should force multiline 1 column" {
3675// try testTransform(
3676// \\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,};
3677// \\
3678// ,
3679// \\pub const UUID_NULL: uuid_t = [16]u8{
3680// \\ 0,
3681// \\ 0,
3682// \\ 0,
3683// \\ 0,
3684// \\};
3685// \\
3686// );
3687//}
3688//
3689//test "zig fmt: function params should align nicely" {
3690// try testCanonical(
3691// \\pub fn foo() void {
3692// \\ cases.addRuntimeSafety("slicing operator with sentinel",
3693// \\ \\const std = @import("std");
3694// \\ ++ check_panic_msg ++
3695// \\ \\pub fn main() void {
3696// \\ \\ var buf = [4]u8{'a','b','c',0};
3697// \\ \\ const slice = buf[0..:0];
3698// \\ \\}
3699// \\ );
3700// \\}
3701// \\
3702// );
3703//}
37273704
37283705const std = @import("std");
37293706const mem = std.mem;
......@@ -3763,8 +3740,10 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
37633740 errdefer buffer.deinit();
37643741
37653742 const writer = buffer.writer();
3766 anything_changed.* = try std.zig.render(allocator, writer, tree);
3767 return buffer.toOwnedSlice();
3743 try std.zig.render(allocator, writer, tree);
3744 const result = buffer.toOwnedSlice();
3745 anything_changed.* = !mem.eql(u8, result, source);
3746 return result;
37683747}
37693748fn testTransform(source: []const u8, expected_source: []const u8) !void {
37703749 const needed_alloc_count = x: {
lib/std/zig/render.zig+2128-2341
......@@ -14,2167 +14,2072 @@ const indent_delta = 4;
1414const asm_indent_delta = 2;
1515
1616pub const Error = error{
17 /// Ran out of memory allocating call stack frames to complete rendering.
17 /// Ran out of memory allocating call stack frames to complete rendering, or
18 /// ran out of memory allocating space in the output buffer.
1819 OutOfMemory,
1920};
2021
21/// Returns whether anything changed
22pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (@TypeOf(stream).Error || Error)!bool {
23 // cannot render an invalid tree
24 std.debug.assert(tree.errors.len == 0);
22const Writer = std.ArrayList(u8).Writer;
23const Ais = std.io.AutoIndentingStream(Writer);
2524
26 var change_detection_stream = std.io.changeDetectionStream(tree.source, stream);
27 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, change_detection_stream.writer());
28
29 try renderRoot(allocator, &auto_indenting_stream, tree);
30
31 return change_detection_stream.changeDetected();
32}
33
34fn renderRoot(
35 allocator: *mem.Allocator,
36 ais: anytype,
37 tree: *ast.Tree,
38) (@TypeOf(ais.*).Error || Error)!void {
39
40 // render all the line comments at the beginning of the file
41 for (tree.token_ids) |token_id, i| {
42 if (token_id != .LineComment) break;
43 const token_loc = tree.token_locs[i];
44 try ais.writer().print("{s}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
45 const next_token = tree.token_locs[i + 1];
46 const loc = tree.tokenLocationLoc(token_loc.end, next_token);
47 if (loc.line >= 2) {
48 try ais.insertNewline();
49 }
50 }
51
52 var decl_i: ast.NodeIndex = 0;
53 const root_decls = tree.root_node.decls();
54
55 if (root_decls.len == 0) return;
56 while (true) {
57 var decl = root_decls[decl_i];
58
59 // This loop does the following:
60 //
61 // - Iterates through line/doc comment tokens that precedes the current
62 // decl.
63 // - Figures out the first token index (`copy_start_token_index`) which
64 // hasn't been copied to the output stream yet.
65 // - Detects `zig fmt: (off|on)` in the line comment tokens, and
66 // determines whether the current decl should be reformatted or not.
67 //
68 var token_index = decl.firstToken();
69 var fmt_active = true;
70 var found_fmt_directive = false;
71
72 var copy_start_token_index = token_index;
73
74 while (token_index != 0) {
75 token_index -= 1;
76 const token_id = tree.token_ids[token_index];
77 switch (token_id) {
78 .LineComment => {},
79 .DocComment => {
80 copy_start_token_index = token_index;
81 continue;
82 },
83 else => break,
84 }
85
86 const token_loc = tree.token_locs[token_index];
87 if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) {
88 if (!found_fmt_directive) {
89 fmt_active = false;
90 found_fmt_directive = true;
91 }
92 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) {
93 if (!found_fmt_directive) {
94 fmt_active = true;
95 found_fmt_directive = true;
96 }
97 }
98 }
99
100 if (!fmt_active) {
101 // Reformatting is disabled for the current decl and possibly some
102 // more decls that follow.
103 // Find the next `decl` for which reformatting is re-enabled.
104 token_index = decl.firstToken();
105
106 while (!fmt_active) {
107 decl_i += 1;
108 if (decl_i >= root_decls.len) {
109 // If there's no next reformatted `decl`, just copy the
110 // remaining input tokens and bail out.
111 const start = tree.token_locs[copy_start_token_index].start;
112 try copyFixingWhitespace(ais, tree.source[start..]);
113 return;
114 }
115 decl = root_decls[decl_i];
116 var decl_first_token_index = decl.firstToken();
117
118 while (token_index < decl_first_token_index) : (token_index += 1) {
119 const token_id = tree.token_ids[token_index];
120 switch (token_id) {
121 .LineComment => {},
122 .Eof => unreachable,
123 else => continue,
124 }
125 const token_loc = tree.token_locs[token_index];
126 if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) {
127 fmt_active = true;
128 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) {
129 fmt_active = false;
130 }
131 }
132 }
133
134 // Found the next `decl` for which reformatting is enabled. Copy
135 // the input tokens before the `decl` that haven't been copied yet.
136 var copy_end_token_index = decl.firstToken();
137 token_index = copy_end_token_index;
138 while (token_index != 0) {
139 token_index -= 1;
140 const token_id = tree.token_ids[token_index];
141 switch (token_id) {
142 .LineComment => {},
143 .DocComment => {
144 copy_end_token_index = token_index;
145 continue;
146 },
147 else => break,
148 }
149 }
150
151 const start = tree.token_locs[copy_start_token_index].start;
152 const end = tree.token_locs[copy_end_token_index].start;
153 try copyFixingWhitespace(ais, tree.source[start..end]);
154 }
155
156 try renderTopLevelDecl(allocator, ais, tree, decl);
157 decl_i += 1;
158 if (decl_i >= root_decls.len) return;
159 try renderExtraNewline(tree, ais, root_decls[decl_i]);
160 }
161}
162
163fn renderExtraNewline(tree: *ast.Tree, ais: anytype, node: *ast.Node) @TypeOf(ais.*).Error!void {
164 return renderExtraNewlineToken(tree, ais, node.firstToken());
165}
166
167fn renderExtraNewlineToken(
168 tree: *ast.Tree,
169 ais: anytype,
170 first_token: ast.TokenIndex,
171) @TypeOf(ais.*).Error!void {
172 var prev_token = first_token;
173 if (prev_token == 0) return;
174 var newline_threshold: usize = 2;
175 while (tree.token_ids[prev_token - 1] == .DocComment) {
176 if (tree.tokenLocation(tree.token_locs[prev_token - 1].end, prev_token).line == 1) {
177 newline_threshold += 1;
178 }
179 prev_token -= 1;
180 }
181 const prev_token_end = tree.token_locs[prev_token - 1].end;
182 const loc = tree.tokenLocation(prev_token_end, first_token);
183 if (loc.line >= newline_threshold) {
184 try ais.insertNewline();
185 }
186}
187
188fn renderTopLevelDecl(allocator: *mem.Allocator, ais: anytype, tree: *ast.Tree, decl: *ast.Node) (@TypeOf(ais.*).Error || Error)!void {
189 try renderContainerDecl(allocator, ais, tree, decl, .Newline);
190}
191
192fn renderContainerDecl(allocator: *mem.Allocator, ais: anytype, tree: *ast.Tree, decl: *ast.Node, space: Space) (@TypeOf(ais.*).Error || Error)!void {
193 switch (decl.tag) {
194 .FnProto => {
195 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
196
197 try renderDocComments(tree, ais, fn_proto, fn_proto.getDocComments());
198
199 if (fn_proto.getBodyNode()) |body_node| {
200 try renderExpression(allocator, ais, tree, decl, .Space);
201 try renderExpression(allocator, ais, tree, body_node, space);
202 } else {
203 try renderExpression(allocator, ais, tree, decl, .None);
204 try renderToken(tree, ais, tree.nextToken(decl.lastToken()), space);
205 }
206 },
207
208 .Use => {
209 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
210
211 if (use_decl.visib_token) |visib_token| {
212 try renderToken(tree, ais, visib_token, .Space); // pub
213 }
214 try renderToken(tree, ais, use_decl.use_token, .Space); // usingnamespace
215 try renderExpression(allocator, ais, tree, use_decl.expr, .None);
216 try renderToken(tree, ais, use_decl.semicolon_token, space); // ;
217 },
218
219 .VarDecl => {
220 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
221
222 try renderDocComments(tree, ais, var_decl, var_decl.getDocComments());
223 try renderVarDecl(allocator, ais, tree, var_decl);
224 },
225
226 .TestDecl => {
227 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
228
229 try renderDocComments(tree, ais, test_decl, test_decl.doc_comments);
230 try renderToken(tree, ais, test_decl.test_token, .Space);
231 if (test_decl.name) |name|
232 try renderExpression(allocator, ais, tree, name, .Space);
233 try renderExpression(allocator, ais, tree, test_decl.body_node, space);
234 },
235
236 .ContainerField => {
237 const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
238
239 try renderDocComments(tree, ais, field, field.doc_comments);
240 if (field.comptime_token) |t| {
241 try renderToken(tree, ais, t, .Space); // comptime
242 }
243
244 const src_has_trailing_comma = blk: {
245 const maybe_comma = tree.nextToken(field.lastToken());
246 break :blk tree.token_ids[maybe_comma] == .Comma;
247 };
248
249 // The trailing comma is emitted at the end, but if it's not present
250 // we still have to respect the specified `space` parameter
251 const last_token_space: Space = if (src_has_trailing_comma) .None else space;
252
253 if (field.type_expr == null and field.value_expr == null) {
254 try renderToken(tree, ais, field.name_token, last_token_space); // name
255 } else if (field.type_expr != null and field.value_expr == null) {
256 try renderToken(tree, ais, field.name_token, .None); // name
257 try renderToken(tree, ais, tree.nextToken(field.name_token), .Space); // :
258
259 if (field.align_expr) |align_value_expr| {
260 try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type
261 const lparen_token = tree.prevToken(align_value_expr.firstToken());
262 const align_kw = tree.prevToken(lparen_token);
263 const rparen_token = tree.nextToken(align_value_expr.lastToken());
264 try renderToken(tree, ais, align_kw, .None); // align
265 try renderToken(tree, ais, lparen_token, .None); // (
266 try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment
267 try renderToken(tree, ais, rparen_token, last_token_space); // )
268 } else {
269 try renderExpression(allocator, ais, tree, field.type_expr.?, last_token_space); // type
270 }
271 } else if (field.type_expr == null and field.value_expr != null) {
272 try renderToken(tree, ais, field.name_token, .Space); // name
273 try renderToken(tree, ais, tree.nextToken(field.name_token), .Space); // =
274 try renderExpression(allocator, ais, tree, field.value_expr.?, last_token_space); // value
275 } else {
276 try renderToken(tree, ais, field.name_token, .None); // name
277 try renderToken(tree, ais, tree.nextToken(field.name_token), .Space); // :
278
279 if (field.align_expr) |align_value_expr| {
280 try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type
281 const lparen_token = tree.prevToken(align_value_expr.firstToken());
282 const align_kw = tree.prevToken(lparen_token);
283 const rparen_token = tree.nextToken(align_value_expr.lastToken());
284 try renderToken(tree, ais, align_kw, .None); // align
285 try renderToken(tree, ais, lparen_token, .None); // (
286 try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment
287 try renderToken(tree, ais, rparen_token, .Space); // )
288 } else {
289 try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type
290 }
291 try renderToken(tree, ais, tree.prevToken(field.value_expr.?.firstToken()), .Space); // =
292 try renderExpression(allocator, ais, tree, field.value_expr.?, last_token_space); // value
293 }
294
295 if (src_has_trailing_comma) {
296 const comma = tree.nextToken(field.lastToken());
297 try renderToken(tree, ais, comma, space);
298 }
299 },
300
301 .Comptime => {
302 assert(!decl.requireSemiColon());
303 try renderExpression(allocator, ais, tree, decl, space);
304 },
305
306 .DocComment => {
307 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);
308 const kind = tree.token_ids[comment.first_line];
309 try renderToken(tree, ais, comment.first_line, .Newline);
310 var tok_i = comment.first_line + 1;
311 while (true) : (tok_i += 1) {
312 const tok_id = tree.token_ids[tok_i];
313 if (tok_id == kind) {
314 try renderToken(tree, ais, tok_i, .Newline);
315 } else if (tok_id == .LineComment) {
316 continue;
317 } else {
318 break;
319 }
320 }
321 },
322 else => unreachable,
323 }
324}
325
326fn renderExpression(
327 allocator: *mem.Allocator,
328 ais: anytype,
329 tree: *ast.Tree,
330 base: *ast.Node,
331 space: Space,
332) (@TypeOf(ais.*).Error || Error)!void {
333 switch (base.tag) {
334 .Identifier,
335 .IntegerLiteral,
336 .FloatLiteral,
337 .StringLiteral,
338 .CharLiteral,
339 .BoolLiteral,
340 .NullLiteral,
341 .Unreachable,
342 .ErrorType,
343 .UndefinedLiteral,
344 => {
345 const casted_node = base.cast(ast.Node.OneToken).?;
346 return renderToken(tree, ais, casted_node.token, space);
347 },
348
349 .AnyType => {
350 const any_type = base.castTag(.AnyType).?;
351 if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {
352 // TODO remove in next release cycle
353 try ais.writer().writeAll("anytype");
354 if (space == .Comma) try ais.writer().writeAll(",\n");
355 return;
356 }
357 return renderToken(tree, ais, any_type.token, space);
358 },
359
360 .Block, .LabeledBlock => {
361 const block: struct {
362 label: ?ast.TokenIndex,
363 statements: []*ast.Node,
364 lbrace: ast.TokenIndex,
365 rbrace: ast.TokenIndex,
366 } = b: {
367 if (base.castTag(.Block)) |block| {
368 break :b .{
369 .label = null,
370 .statements = block.statements(),
371 .lbrace = block.lbrace,
372 .rbrace = block.rbrace,
373 };
374 } else if (base.castTag(.LabeledBlock)) |block| {
375 break :b .{
376 .label = block.label,
377 .statements = block.statements(),
378 .lbrace = block.lbrace,
379 .rbrace = block.rbrace,
380 };
381 } else {
382 unreachable;
383 }
384 };
385
386 if (block.label) |label| {
387 try renderToken(tree, ais, label, Space.None);
388 try renderToken(tree, ais, tree.nextToken(label), Space.Space);
389 }
390
391 if (block.statements.len == 0) {
392 ais.pushIndentNextLine();
393 defer ais.popIndent();
394 try renderToken(tree, ais, block.lbrace, Space.None);
395 } else {
396 ais.pushIndentNextLine();
397 defer ais.popIndent();
398
399 try renderToken(tree, ais, block.lbrace, Space.Newline);
400
401 for (block.statements) |statement, i| {
402 try renderStatement(allocator, ais, tree, statement);
403
404 if (i + 1 < block.statements.len) {
405 try renderExtraNewline(tree, ais, block.statements[i + 1]);
406 }
407 }
408 }
409 return renderToken(tree, ais, block.rbrace, space);
410 },
411
412 .Defer => {
413 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
414
415 try renderToken(tree, ais, defer_node.defer_token, Space.Space);
416 if (defer_node.payload) |payload| {
417 try renderExpression(allocator, ais, tree, payload, Space.Space);
418 }
419 return renderExpression(allocator, ais, tree, defer_node.expr, space);
420 },
421 .Comptime => {
422 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
423
424 try renderToken(tree, ais, comptime_node.comptime_token, Space.Space);
425 return renderExpression(allocator, ais, tree, comptime_node.expr, space);
426 },
427 .Nosuspend => {
428 const nosuspend_node = @fieldParentPtr(ast.Node.Nosuspend, "base", base);
429 if (mem.eql(u8, tree.tokenSlice(nosuspend_node.nosuspend_token), "noasync")) {
430 // TODO: remove this
431 try ais.writer().writeAll("nosuspend ");
432 } else {
433 try renderToken(tree, ais, nosuspend_node.nosuspend_token, Space.Space);
434 }
435 return renderExpression(allocator, ais, tree, nosuspend_node.expr, space);
436 },
437
438 .Suspend => {
439 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
440
441 if (suspend_node.body) |body| {
442 try renderToken(tree, ais, suspend_node.suspend_token, Space.Space);
443 return renderExpression(allocator, ais, tree, body, space);
444 } else {
445 return renderToken(tree, ais, suspend_node.suspend_token, space);
446 }
447 },
448
449 .Catch => {
450 const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base);
451
452 const op_space = Space.Space;
453 try renderExpression(allocator, ais, tree, infix_op_node.lhs, op_space);
454
455 const after_op_space = blk: {
456 const same_line = tree.tokensOnSameLine(infix_op_node.op_token, tree.nextToken(infix_op_node.op_token));
457 break :blk if (same_line) op_space else Space.Newline;
458 };
459
460 try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
461
462 if (infix_op_node.payload) |payload| {
463 try renderExpression(allocator, ais, tree, payload, Space.Space);
464 }
465
466 ais.pushIndentOneShot();
467 return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
468 },
469
470 .Add,
471 .AddWrap,
472 .ArrayCat,
473 .ArrayMult,
474 .Assign,
475 .AssignBitAnd,
476 .AssignBitOr,
477 .AssignBitShiftLeft,
478 .AssignBitShiftRight,
479 .AssignBitXor,
480 .AssignDiv,
481 .AssignSub,
482 .AssignSubWrap,
483 .AssignMod,
484 .AssignAdd,
485 .AssignAddWrap,
486 .AssignMul,
487 .AssignMulWrap,
488 .BangEqual,
489 .BitAnd,
490 .BitOr,
491 .BitShiftLeft,
492 .BitShiftRight,
493 .BitXor,
494 .BoolAnd,
495 .BoolOr,
496 .Div,
497 .EqualEqual,
498 .ErrorUnion,
499 .GreaterOrEqual,
500 .GreaterThan,
501 .LessOrEqual,
502 .LessThan,
503 .MergeErrorSets,
504 .Mod,
505 .Mul,
506 .MulWrap,
507 .Period,
508 .Range,
509 .Sub,
510 .SubWrap,
511 .OrElse,
512 => {
513 const infix_op_node = @fieldParentPtr(ast.Node.SimpleInfixOp, "base", base);
514
515 const op_space = switch (base.tag) {
516 .Period, .ErrorUnion, .Range => Space.None,
517 else => Space.Space,
518 };
519 try renderExpression(allocator, ais, tree, infix_op_node.lhs, op_space);
520
521 const after_op_space = blk: {
522 const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
523 break :blk if (loc.line == 0) op_space else Space.Newline;
524 };
525
526 {
527 ais.pushIndent();
528 defer ais.popIndent();
529 try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
530 }
531 ais.pushIndentOneShot();
532 return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
533 },
534
535 .BitNot,
536 .BoolNot,
537 .Negation,
538 .NegationWrap,
539 .OptionalType,
540 .AddressOf,
541 => {
542 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
543 try renderToken(tree, ais, casted_node.op_token, Space.None);
544 return renderExpression(allocator, ais, tree, casted_node.rhs, space);
545 },
546
547 .Try,
548 .Resume,
549 .Await,
550 => {
551 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
552 try renderToken(tree, ais, casted_node.op_token, Space.Space);
553 return renderExpression(allocator, ais, tree, casted_node.rhs, space);
554 },
555
556 .ArrayType => {
557 const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base);
558 return renderArrayType(
559 allocator,
560 ais,
561 tree,
562 array_type.op_token,
563 array_type.rhs,
564 array_type.len_expr,
565 null,
566 space,
567 );
568 },
569 .ArrayTypeSentinel => {
570 const array_type = @fieldParentPtr(ast.Node.ArrayTypeSentinel, "base", base);
571 return renderArrayType(
572 allocator,
573 ais,
574 tree,
575 array_type.op_token,
576 array_type.rhs,
577 array_type.len_expr,
578 array_type.sentinel,
579 space,
580 );
581 },
582
583 .PtrType => {
584 const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
585 const op_tok_id = tree.token_ids[ptr_type.op_token];
586 switch (op_tok_id) {
587 .Asterisk, .AsteriskAsterisk => try ais.writer().writeByte('*'),
588 .LBracket => if (tree.token_ids[ptr_type.op_token + 2] == .Identifier)
589 try ais.writer().writeAll("[*c")
590 else
591 try ais.writer().writeAll("[*"),
592 else => unreachable,
593 }
594 if (ptr_type.ptr_info.sentinel) |sentinel| {
595 const colon_token = tree.prevToken(sentinel.firstToken());
596 try renderToken(tree, ais, colon_token, Space.None); // :
597 const sentinel_space = switch (op_tok_id) {
598 .LBracket => Space.None,
599 else => Space.Space,
600 };
601 try renderExpression(allocator, ais, tree, sentinel, sentinel_space);
602 }
603 switch (op_tok_id) {
604 .Asterisk, .AsteriskAsterisk => {},
605 .LBracket => try ais.writer().writeByte(']'),
606 else => unreachable,
607 }
608 if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {
609 try renderToken(tree, ais, allowzero_token, Space.Space); // allowzero
610 }
611 if (ptr_type.ptr_info.align_info) |align_info| {
612 const lparen_token = tree.prevToken(align_info.node.firstToken());
613 const align_token = tree.prevToken(lparen_token);
614
615 try renderToken(tree, ais, align_token, Space.None); // align
616 try renderToken(tree, ais, lparen_token, Space.None); // (
617
618 try renderExpression(allocator, ais, tree, align_info.node, Space.None);
619
620 if (align_info.bit_range) |bit_range| {
621 const colon1 = tree.prevToken(bit_range.start.firstToken());
622 const colon2 = tree.prevToken(bit_range.end.firstToken());
623
624 try renderToken(tree, ais, colon1, Space.None); // :
625 try renderExpression(allocator, ais, tree, bit_range.start, Space.None);
626 try renderToken(tree, ais, colon2, Space.None); // :
627 try renderExpression(allocator, ais, tree, bit_range.end, Space.None);
628
629 const rparen_token = tree.nextToken(bit_range.end.lastToken());
630 try renderToken(tree, ais, rparen_token, Space.Space); // )
631 } else {
632 const rparen_token = tree.nextToken(align_info.node.lastToken());
633 try renderToken(tree, ais, rparen_token, Space.Space); // )
634 }
635 }
636 if (ptr_type.ptr_info.const_token) |const_token| {
637 try renderToken(tree, ais, const_token, Space.Space); // const
638 }
639 if (ptr_type.ptr_info.volatile_token) |volatile_token| {
640 try renderToken(tree, ais, volatile_token, Space.Space); // volatile
641 }
642 return renderExpression(allocator, ais, tree, ptr_type.rhs, space);
643 },
644
645 .SliceType => {
646 const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
647 try renderToken(tree, ais, slice_type.op_token, Space.None); // [
648 if (slice_type.ptr_info.sentinel) |sentinel| {
649 const colon_token = tree.prevToken(sentinel.firstToken());
650 try renderToken(tree, ais, colon_token, Space.None); // :
651 try renderExpression(allocator, ais, tree, sentinel, Space.None);
652 try renderToken(tree, ais, tree.nextToken(sentinel.lastToken()), Space.None); // ]
653 } else {
654 try renderToken(tree, ais, tree.nextToken(slice_type.op_token), Space.None); // ]
655 }
656
657 if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
658 try renderToken(tree, ais, allowzero_token, Space.Space); // allowzero
659 }
660 if (slice_type.ptr_info.align_info) |align_info| {
661 const lparen_token = tree.prevToken(align_info.node.firstToken());
662 const align_token = tree.prevToken(lparen_token);
663
664 try renderToken(tree, ais, align_token, Space.None); // align
665 try renderToken(tree, ais, lparen_token, Space.None); // (
666
667 try renderExpression(allocator, ais, tree, align_info.node, Space.None);
668
669 if (align_info.bit_range) |bit_range| {
670 const colon1 = tree.prevToken(bit_range.start.firstToken());
671 const colon2 = tree.prevToken(bit_range.end.firstToken());
672
673 try renderToken(tree, ais, colon1, Space.None); // :
674 try renderExpression(allocator, ais, tree, bit_range.start, Space.None);
675 try renderToken(tree, ais, colon2, Space.None); // :
676 try renderExpression(allocator, ais, tree, bit_range.end, Space.None);
677
678 const rparen_token = tree.nextToken(bit_range.end.lastToken());
679 try renderToken(tree, ais, rparen_token, Space.Space); // )
680 } else {
681 const rparen_token = tree.nextToken(align_info.node.lastToken());
682 try renderToken(tree, ais, rparen_token, Space.Space); // )
683 }
684 }
685 if (slice_type.ptr_info.const_token) |const_token| {
686 try renderToken(tree, ais, const_token, Space.Space);
687 }
688 if (slice_type.ptr_info.volatile_token) |volatile_token| {
689 try renderToken(tree, ais, volatile_token, Space.Space);
690 }
691 return renderExpression(allocator, ais, tree, slice_type.rhs, space);
692 },
693
694 .ArrayInitializer, .ArrayInitializerDot => {
695 var rtoken: ast.TokenIndex = undefined;
696 var exprs: []*ast.Node = undefined;
697 const lhs: union(enum) { dot: ast.TokenIndex, node: *ast.Node } = switch (base.tag) {
698 .ArrayInitializerDot => blk: {
699 const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);
700 rtoken = casted.rtoken;
701 exprs = casted.list();
702 break :blk .{ .dot = casted.dot };
703 },
704 .ArrayInitializer => blk: {
705 const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base);
706 rtoken = casted.rtoken;
707 exprs = casted.list();
708 break :blk .{ .node = casted.lhs };
709 },
710 else => unreachable,
711 };
712
713 const lbrace = switch (lhs) {
714 .dot => |dot| tree.nextToken(dot),
715 .node => |node| tree.nextToken(node.lastToken()),
716 };
717
718 switch (lhs) {
719 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
720 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
721 }
722
723 if (exprs.len == 0) {
724 try renderToken(tree, ais, lbrace, Space.None);
725 return renderToken(tree, ais, rtoken, space);
726 }
727
728 if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
729 const expr = exprs[0];
730
731 try renderToken(tree, ais, lbrace, Space.None);
732 try renderExpression(allocator, ais, tree, expr, Space.None);
733 return renderToken(tree, ais, rtoken, space);
734 }
735
736 // scan to find row size
737 if (rowSize(tree, exprs, rtoken) != null) {
738 {
739 ais.pushIndentNextLine();
740 defer ais.popIndent();
741 try renderToken(tree, ais, lbrace, Space.Newline);
742
743 var expr_index: usize = 0;
744 while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| {
745 const row_exprs = exprs[expr_index..];
746 // A place to store the width of each expression and its column's maximum
747 var widths = try allocator.alloc(usize, row_exprs.len + row_size);
748 defer allocator.free(widths);
749 mem.set(usize, widths, 0);
750
751 var expr_newlines = try allocator.alloc(bool, row_exprs.len);
752 defer allocator.free(expr_newlines);
753 mem.set(bool, expr_newlines, false);
754
755 var expr_widths = widths[0 .. widths.len - row_size];
756 var column_widths = widths[widths.len - row_size ..];
757
758 // Find next row with trailing comment (if any) to end the current section
759 var section_end = sec_end: {
760 var this_line_first_expr: usize = 0;
761 var this_line_size = rowSize(tree, row_exprs, rtoken);
762 for (row_exprs) |expr, i| {
763 // Ignore comment on first line of this section
764 if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue;
765 // Track start of line containing comment
766 if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) {
767 this_line_first_expr = i;
768 this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken);
769 }
770
771 const maybe_comma = expr.lastToken() + 1;
772 const maybe_comment = expr.lastToken() + 2;
773 if (maybe_comment < tree.token_ids.len) {
774 if (tree.token_ids[maybe_comma] == .Comma and
775 tree.token_ids[maybe_comment] == .LineComment and
776 tree.tokensOnSameLine(expr.lastToken(), maybe_comment))
777 {
778 var comment_token_loc = tree.token_locs[maybe_comment];
779 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
780 if (!comment_is_empty) {
781 // Found row ending in comment
782 break :sec_end i - this_line_size.? + 1;
783 }
784 }
785 }
786 }
787 break :sec_end row_exprs.len;
788 };
789 expr_index += section_end;
790
791 const section_exprs = row_exprs[0..section_end];
792
793 // Null stream for counting the printed length of each expression
794 var line_find_stream = std.io.findByteWriter('\n', std.io.null_writer);
795 var counting_stream = std.io.countingWriter(line_find_stream.writer());
796 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
797
798 // Calculate size of columns in current section
799 var column_counter: usize = 0;
800 var single_line = true;
801 for (section_exprs) |expr, i| {
802 if (i + 1 < section_exprs.len) {
803 counting_stream.bytes_written = 0;
804 line_find_stream.byte_found = false;
805 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
806 const width = @intCast(usize, counting_stream.bytes_written);
807 expr_widths[i] = width;
808 expr_newlines[i] = line_find_stream.byte_found;
809
810 if (!line_find_stream.byte_found) {
811 const column = column_counter % row_size;
812 column_widths[column] = std.math.max(column_widths[column], width);
813
814 const expr_last_token = expr.*.lastToken() + 1;
815 const next_expr = section_exprs[i + 1];
816 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
817
818 column_counter += 1;
819
820 if (loc.line != 0) single_line = false;
821 } else {
822 single_line = false;
823 column_counter = 0;
824 }
825 } else {
826 counting_stream.bytes_written = 0;
827 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
828 const width = @intCast(usize, counting_stream.bytes_written);
829 expr_widths[i] = width;
830 expr_newlines[i] = line_find_stream.byte_found;
831
832 if (!line_find_stream.byte_found) {
833 const column = column_counter % row_size;
834 column_widths[column] = std.math.max(column_widths[column], width);
835 }
836 break;
837 }
838 }
839
840 // Render exprs in current section
841 column_counter = 0;
842 var last_col_index: usize = row_size - 1;
843 for (section_exprs) |expr, i| {
844 if (i + 1 < section_exprs.len) {
845 const next_expr = section_exprs[i + 1];
846 try renderExpression(allocator, ais, tree, expr, Space.None);
847
848 const comma = tree.nextToken(expr.*.lastToken());
849
850 if (column_counter != last_col_index) {
851 if (!expr_newlines[i] and !expr_newlines[i + 1]) {
852 // Neither the current or next expression is multiline
853 try renderToken(tree, ais, comma, Space.Space); // ,
854 assert(column_widths[column_counter % row_size] >= expr_widths[i]);
855 const padding = column_widths[column_counter % row_size] - expr_widths[i];
856 try ais.writer().writeByteNTimes(' ', padding);
857
858 column_counter += 1;
859 continue;
860 }
861 }
862 if (single_line and row_size != 1) {
863 try renderToken(tree, ais, comma, Space.Space); // ,
864 continue;
865 }
866
867 column_counter = 0;
868 try renderToken(tree, ais, comma, Space.Newline); // ,
869 try renderExtraNewline(tree, ais, next_expr);
870 } else {
871 const maybe_comma = tree.nextToken(expr.*.lastToken());
872 if (tree.token_ids[maybe_comma] == .Comma) {
873 try renderExpression(allocator, ais, tree, expr, Space.None); // ,
874 try renderToken(tree, ais, maybe_comma, Space.Newline); // ,
875 } else {
876 try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
877 }
878 }
879 }
880
881 if (expr_index == exprs.len) {
882 break;
883 }
884 }
885 }
886
887 return renderToken(tree, ais, rtoken, space);
888 }
889
890 // Single line
891 try renderToken(tree, ais, lbrace, Space.Space);
892 for (exprs) |expr, i| {
893 if (i + 1 < exprs.len) {
894 const next_expr = exprs[i + 1];
895 try renderExpression(allocator, ais, tree, expr, Space.None);
896 const comma = tree.nextToken(expr.*.lastToken());
897 try renderToken(tree, ais, comma, Space.Space); // ,
898 } else {
899 try renderExpression(allocator, ais, tree, expr, Space.Space);
900 }
901 }
902
903 return renderToken(tree, ais, rtoken, space);
904 },
905
906 .StructInitializer, .StructInitializerDot => {
907 var rtoken: ast.TokenIndex = undefined;
908 var field_inits: []*ast.Node = undefined;
909 const lhs: union(enum) { dot: ast.TokenIndex, node: *ast.Node } = switch (base.tag) {
910 .StructInitializerDot => blk: {
911 const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);
912 rtoken = casted.rtoken;
913 field_inits = casted.list();
914 break :blk .{ .dot = casted.dot };
915 },
916 .StructInitializer => blk: {
917 const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base);
918 rtoken = casted.rtoken;
919 field_inits = casted.list();
920 break :blk .{ .node = casted.lhs };
921 },
922 else => unreachable,
923 };
924
925 const lbrace = switch (lhs) {
926 .dot => |dot| tree.nextToken(dot),
927 .node => |node| tree.nextToken(node.lastToken()),
928 };
929
930 if (field_inits.len == 0) {
931 switch (lhs) {
932 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
933 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
934 }
935
936 {
937 ais.pushIndentNextLine();
938 defer ais.popIndent();
939 try renderToken(tree, ais, lbrace, Space.None);
940 }
941
942 return renderToken(tree, ais, rtoken, space);
943 }
944
945 const src_has_trailing_comma = blk: {
946 const maybe_comma = tree.prevToken(rtoken);
947 break :blk tree.token_ids[maybe_comma] == .Comma;
948 };
949
950 const src_same_line = blk: {
951 const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken);
952 break :blk loc.line == 0;
953 };
954
955 const expr_outputs_one_line = blk: {
956 // render field expressions until a LF is found
957 for (field_inits) |field_init| {
958 var find_stream = std.io.findByteWriter('\n', std.io.null_writer);
959 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, find_stream.writer());
960
961 try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None);
962 if (find_stream.byte_found) break :blk false;
963 }
964 break :blk true;
965 };
966
967 if (field_inits.len == 1) blk: {
968 if (field_inits[0].cast(ast.Node.FieldInitializer)) |field_init| {
969 switch (field_init.expr.tag) {
970 .StructInitializer,
971 .StructInitializerDot,
972 => break :blk,
973 else => {},
974 }
975 }
976
977 // if the expression outputs to multiline, make this struct multiline
978 if (!expr_outputs_one_line or src_has_trailing_comma) {
979 break :blk;
980 }
981
982 switch (lhs) {
983 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
984 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
985 }
986 try renderToken(tree, ais, lbrace, Space.Space);
987 try renderExpression(allocator, ais, tree, field_inits[0], Space.Space);
988 return renderToken(tree, ais, rtoken, space);
989 }
990
991 if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
992 // render all on one line, no trailing comma
993 switch (lhs) {
994 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
995 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
996 }
997 try renderToken(tree, ais, lbrace, Space.Space);
998
999 for (field_inits) |field_init, i| {
1000 if (i + 1 < field_inits.len) {
1001 try renderExpression(allocator, ais, tree, field_init, Space.None);
1002
1003 const comma = tree.nextToken(field_init.lastToken());
1004 try renderToken(tree, ais, comma, Space.Space);
1005 } else {
1006 try renderExpression(allocator, ais, tree, field_init, Space.Space);
1007 }
1008 }
1009
1010 return renderToken(tree, ais, rtoken, space);
1011 }
1012
1013 {
1014 switch (lhs) {
1015 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
1016 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
1017 }
1018
1019 ais.pushIndentNextLine();
1020 defer ais.popIndent();
1021
1022 try renderToken(tree, ais, lbrace, Space.Newline);
1023
1024 for (field_inits) |field_init, i| {
1025 if (i + 1 < field_inits.len) {
1026 const next_field_init = field_inits[i + 1];
1027 try renderExpression(allocator, ais, tree, field_init, Space.None);
1028
1029 const comma = tree.nextToken(field_init.lastToken());
1030 try renderToken(tree, ais, comma, Space.Newline);
1031
1032 try renderExtraNewline(tree, ais, next_field_init);
1033 } else {
1034 try renderExpression(allocator, ais, tree, field_init, Space.Comma);
1035 }
1036 }
1037 }
1038
1039 return renderToken(tree, ais, rtoken, space);
1040 },
1041
1042 .Call => {
1043 const call = @fieldParentPtr(ast.Node.Call, "base", base);
1044 if (call.async_token) |async_token| {
1045 try renderToken(tree, ais, async_token, Space.Space);
1046 }
1047
1048 try renderExpression(allocator, ais, tree, call.lhs, Space.None);
1049
1050 const lparen = tree.nextToken(call.lhs.lastToken());
1051
1052 if (call.params_len == 0) {
1053 try renderToken(tree, ais, lparen, Space.None);
1054 return renderToken(tree, ais, call.rtoken, space);
1055 }
1056
1057 const src_has_trailing_comma = blk: {
1058 const maybe_comma = tree.prevToken(call.rtoken);
1059 break :blk tree.token_ids[maybe_comma] == .Comma;
1060 };
1061
1062 if (src_has_trailing_comma) {
1063 {
1064 ais.pushIndent();
1065 defer ais.popIndent();
1066
1067 try renderToken(tree, ais, lparen, Space.Newline); // (
1068 const params = call.params();
1069 for (params) |param_node, i| {
1070 if (i + 1 < params.len) {
1071 const next_node = params[i + 1];
1072 try renderExpression(allocator, ais, tree, param_node, Space.None);
1073
1074 // Unindent the comma for multiline string literals
1075 const maybe_multiline_string = param_node.firstToken();
1076 const is_multiline_string = tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine;
1077 if (is_multiline_string) ais.popIndent();
1078 defer if (is_multiline_string) ais.pushIndent();
1079
1080 const comma = tree.nextToken(param_node.lastToken());
1081 try renderToken(tree, ais, comma, Space.Newline); // ,
1082 try renderExtraNewline(tree, ais, next_node);
1083 } else {
1084 try renderExpression(allocator, ais, tree, param_node, Space.Comma);
1085 }
1086 }
1087 }
1088 return renderToken(tree, ais, call.rtoken, space);
1089 }
1090
1091 try renderToken(tree, ais, lparen, Space.None); // (
1092
1093 const params = call.params();
1094 for (params) |param_node, i| {
1095 const maybe_comment = param_node.firstToken() - 1;
1096 const maybe_multiline_string = param_node.firstToken();
1097 if (tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_ids[maybe_comment] == .LineComment) {
1098 ais.pushIndentOneShot();
1099 }
1100
1101 try renderExpression(allocator, ais, tree, param_node, Space.None);
1102
1103 if (i + 1 < params.len) {
1104 const comma = tree.nextToken(param_node.lastToken());
1105 try renderToken(tree, ais, comma, Space.Space);
1106 }
1107 }
1108 return renderToken(tree, ais, call.rtoken, space); // )
1109 },
1110
1111 .ArrayAccess => {
1112 const suffix_op = base.castTag(.ArrayAccess).?;
1113
1114 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
1115 const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());
1116
1117 try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None);
1118 try renderToken(tree, ais, lbracket, Space.None); // [
1119
1120 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
1121 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
1122 {
1123 const new_space = if (ends_with_comment) Space.Newline else Space.None;
1124
1125 ais.pushIndent();
1126 defer ais.popIndent();
1127 try renderExpression(allocator, ais, tree, suffix_op.index_expr, new_space);
1128 }
1129 if (starts_with_comment) try ais.maybeInsertNewline();
1130 return renderToken(tree, ais, rbracket, space); // ]
1131 },
1132
1133 .Slice => {
1134 const suffix_op = base.castTag(.Slice).?;
1135 try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None);
1136
1137 const lbracket = tree.prevToken(suffix_op.start.firstToken());
1138 const dotdot = tree.nextToken(suffix_op.start.lastToken());
1139
1140 const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or
1141 (if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false);
1142 const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
1143 const after_op_space = if (suffix_op.end != null) after_start_space else Space.None;
1144
1145 try renderToken(tree, ais, lbracket, Space.None); // [
1146 try renderExpression(allocator, ais, tree, suffix_op.start, after_start_space);
1147 try renderToken(tree, ais, dotdot, after_op_space); // ..
1148 if (suffix_op.end) |end| {
1149 const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;
1150 try renderExpression(allocator, ais, tree, end, after_end_space);
1151 }
1152 if (suffix_op.sentinel) |sentinel| {
1153 const colon = tree.prevToken(sentinel.firstToken());
1154 try renderToken(tree, ais, colon, Space.None); // :
1155 try renderExpression(allocator, ais, tree, sentinel, Space.None);
1156 }
1157 return renderToken(tree, ais, suffix_op.rtoken, space); // ]
1158 },
1159
1160 .Deref => {
1161 const suffix_op = base.castTag(.Deref).?;
1162
1163 try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None);
1164 return renderToken(tree, ais, suffix_op.rtoken, space); // .*
1165 },
1166 .UnwrapOptional => {
1167 const suffix_op = base.castTag(.UnwrapOptional).?;
1168
1169 try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None);
1170 try renderToken(tree, ais, tree.prevToken(suffix_op.rtoken), Space.None); // .
1171 return renderToken(tree, ais, suffix_op.rtoken, space); // ?
1172 },
1173
1174 .Break => {
1175 const flow_expr = base.castTag(.Break).?;
1176 const maybe_rhs = flow_expr.getRHS();
1177 const maybe_label = flow_expr.getLabel();
1178
1179 if (maybe_label == null and maybe_rhs == null) {
1180 return renderToken(tree, ais, flow_expr.ltoken, space); // break
1181 }
1182
1183 try renderToken(tree, ais, flow_expr.ltoken, Space.Space); // break
1184 if (maybe_label) |label| {
1185 const colon = tree.nextToken(flow_expr.ltoken);
1186 try renderToken(tree, ais, colon, Space.None); // :
1187
1188 if (maybe_rhs == null) {
1189 return renderToken(tree, ais, label, space); // label
1190 }
1191 try renderToken(tree, ais, label, Space.Space); // label
1192 }
1193 return renderExpression(allocator, ais, tree, maybe_rhs.?, space);
1194 },
1195
1196 .Continue => {
1197 const flow_expr = base.castTag(.Continue).?;
1198 if (flow_expr.getLabel()) |label| {
1199 try renderToken(tree, ais, flow_expr.ltoken, Space.Space); // continue
1200 const colon = tree.nextToken(flow_expr.ltoken);
1201 try renderToken(tree, ais, colon, Space.None); // :
1202 return renderToken(tree, ais, label, space); // label
1203 } else {
1204 return renderToken(tree, ais, flow_expr.ltoken, space); // continue
1205 }
1206 },
1207
1208 .Return => {
1209 const flow_expr = base.castTag(.Return).?;
1210 if (flow_expr.getRHS()) |rhs| {
1211 try renderToken(tree, ais, flow_expr.ltoken, Space.Space);
1212 return renderExpression(allocator, ais, tree, rhs, space);
1213 } else {
1214 return renderToken(tree, ais, flow_expr.ltoken, space);
1215 }
1216 },
1217
1218 .Payload => {
1219 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
1220
1221 try renderToken(tree, ais, payload.lpipe, Space.None);
1222 try renderExpression(allocator, ais, tree, payload.error_symbol, Space.None);
1223 return renderToken(tree, ais, payload.rpipe, space);
1224 },
1225
1226 .PointerPayload => {
1227 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
1228
1229 try renderToken(tree, ais, payload.lpipe, Space.None);
1230 if (payload.ptr_token) |ptr_token| {
1231 try renderToken(tree, ais, ptr_token, Space.None);
1232 }
1233 try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None);
1234 return renderToken(tree, ais, payload.rpipe, space);
1235 },
1236
1237 .PointerIndexPayload => {
1238 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
1239
1240 try renderToken(tree, ais, payload.lpipe, Space.None);
1241 if (payload.ptr_token) |ptr_token| {
1242 try renderToken(tree, ais, ptr_token, Space.None);
1243 }
1244 try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None);
1245
1246 if (payload.index_symbol) |index_symbol| {
1247 const comma = tree.nextToken(payload.value_symbol.lastToken());
1248
1249 try renderToken(tree, ais, comma, Space.Space);
1250 try renderExpression(allocator, ais, tree, index_symbol, Space.None);
1251 }
1252
1253 return renderToken(tree, ais, payload.rpipe, space);
1254 },
1255
1256 .GroupedExpression => {
1257 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
1258
1259 try renderToken(tree, ais, grouped_expr.lparen, Space.None);
1260 {
1261 ais.pushIndentOneShot();
1262 try renderExpression(allocator, ais, tree, grouped_expr.expr, Space.None);
1263 }
1264 return renderToken(tree, ais, grouped_expr.rparen, space);
1265 },
1266
1267 .FieldInitializer => {
1268 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
1269
1270 try renderToken(tree, ais, field_init.period_token, Space.None); // .
1271 try renderToken(tree, ais, field_init.name_token, Space.Space); // name
1272 try renderToken(tree, ais, tree.nextToken(field_init.name_token), Space.Space); // =
1273 return renderExpression(allocator, ais, tree, field_init.expr, space);
1274 },
1275
1276 .ContainerDecl => {
1277 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
1278
1279 if (container_decl.layout_token) |layout_token| {
1280 try renderToken(tree, ais, layout_token, Space.Space);
1281 }
1282
1283 switch (container_decl.init_arg_expr) {
1284 .None => {
1285 try renderToken(tree, ais, container_decl.kind_token, Space.Space); // union
1286 },
1287 .Enum => |enum_tag_type| {
1288 try renderToken(tree, ais, container_decl.kind_token, Space.None); // union
1289
1290 const lparen = tree.nextToken(container_decl.kind_token);
1291 const enum_token = tree.nextToken(lparen);
1292
1293 try renderToken(tree, ais, lparen, Space.None); // (
1294 try renderToken(tree, ais, enum_token, Space.None); // enum
1295
1296 if (enum_tag_type) |expr| {
1297 try renderToken(tree, ais, tree.nextToken(enum_token), Space.None); // (
1298 try renderExpression(allocator, ais, tree, expr, Space.None);
1299
1300 const rparen = tree.nextToken(expr.lastToken());
1301 try renderToken(tree, ais, rparen, Space.None); // )
1302 try renderToken(tree, ais, tree.nextToken(rparen), Space.Space); // )
1303 } else {
1304 try renderToken(tree, ais, tree.nextToken(enum_token), Space.Space); // )
1305 }
1306 },
1307 .Type => |type_expr| {
1308 try renderToken(tree, ais, container_decl.kind_token, Space.None); // union
1309
1310 const lparen = tree.nextToken(container_decl.kind_token);
1311 const rparen = tree.nextToken(type_expr.lastToken());
1312
1313 try renderToken(tree, ais, lparen, Space.None); // (
1314 try renderExpression(allocator, ais, tree, type_expr, Space.None);
1315 try renderToken(tree, ais, rparen, Space.Space); // )
1316 },
1317 }
1318
1319 if (container_decl.fields_and_decls_len == 0) {
1320 {
1321 ais.pushIndentNextLine();
1322 defer ais.popIndent();
1323 try renderToken(tree, ais, container_decl.lbrace_token, Space.None); // {
1324 }
1325 return renderToken(tree, ais, container_decl.rbrace_token, space); // }
1326 }
1327
1328 const src_has_trailing_comma = blk: {
1329 var maybe_comma = tree.prevToken(container_decl.lastToken());
1330 // Doc comments for a field may also appear after the comma, eg.
1331 // field_name: T, // comment attached to field_name
1332 if (tree.token_ids[maybe_comma] == .DocComment)
1333 maybe_comma = tree.prevToken(maybe_comma);
1334 break :blk tree.token_ids[maybe_comma] == .Comma;
1335 };
1336
1337 const fields_and_decls = container_decl.fieldsAndDecls();
1338
1339 // Check if the first declaration and the { are on the same line
1340 const src_has_newline = !tree.tokensOnSameLine(
1341 container_decl.lbrace_token,
1342 fields_and_decls[0].firstToken(),
1343 );
1344
1345 // We can only print all the elements in-line if all the
1346 // declarations inside are fields
1347 const src_has_only_fields = blk: {
1348 for (fields_and_decls) |decl| {
1349 if (decl.tag != .ContainerField) break :blk false;
1350 }
1351 break :blk true;
1352 };
1353
1354 if (src_has_trailing_comma or !src_has_only_fields) {
1355 // One declaration per line
1356 ais.pushIndentNextLine();
1357 defer ais.popIndent();
1358 try renderToken(tree, ais, container_decl.lbrace_token, .Newline); // {
1359
1360 for (fields_and_decls) |decl, i| {
1361 try renderContainerDecl(allocator, ais, tree, decl, .Newline);
1362
1363 if (i + 1 < fields_and_decls.len) {
1364 try renderExtraNewline(tree, ais, fields_and_decls[i + 1]);
1365 }
1366 }
1367 } else if (src_has_newline) {
1368 // All the declarations on the same line, but place the items on
1369 // their own line
1370 try renderToken(tree, ais, container_decl.lbrace_token, .Newline); // {
1371
1372 ais.pushIndent();
1373 defer ais.popIndent();
1374
1375 for (fields_and_decls) |decl, i| {
1376 const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space;
1377 try renderContainerDecl(allocator, ais, tree, decl, space_after_decl);
1378 }
1379 } else {
1380 // All the declarations on the same line
1381 try renderToken(tree, ais, container_decl.lbrace_token, .Space); // {
1382
1383 for (fields_and_decls) |decl| {
1384 try renderContainerDecl(allocator, ais, tree, decl, .Space);
1385 }
1386 }
1387
1388 return renderToken(tree, ais, container_decl.rbrace_token, space); // }
1389 },
1390
1391 .ErrorSetDecl => {
1392 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
1393
1394 const lbrace = tree.nextToken(err_set_decl.error_token);
1395
1396 if (err_set_decl.decls_len == 0) {
1397 try renderToken(tree, ais, err_set_decl.error_token, Space.None);
1398 try renderToken(tree, ais, lbrace, Space.None);
1399 return renderToken(tree, ais, err_set_decl.rbrace_token, space);
1400 }
1401
1402 if (err_set_decl.decls_len == 1) blk: {
1403 const node = err_set_decl.decls()[0];
1404
1405 // if there are any doc comments or same line comments
1406 // don't try to put it all on one line
1407 if (node.cast(ast.Node.ErrorTag)) |tag| {
1408 if (tag.doc_comments != null) break :blk;
1409 } else {
1410 break :blk;
1411 }
1412
1413 try renderToken(tree, ais, err_set_decl.error_token, Space.None); // error
1414 try renderToken(tree, ais, lbrace, Space.None); // {
1415 try renderExpression(allocator, ais, tree, node, Space.None);
1416 return renderToken(tree, ais, err_set_decl.rbrace_token, space); // }
1417 }
1418
1419 try renderToken(tree, ais, err_set_decl.error_token, Space.None); // error
1420
1421 const src_has_trailing_comma = blk: {
1422 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
1423 break :blk tree.token_ids[maybe_comma] == .Comma;
1424 };
1425
1426 if (src_has_trailing_comma) {
1427 {
1428 ais.pushIndent();
1429 defer ais.popIndent();
1430
1431 try renderToken(tree, ais, lbrace, Space.Newline); // {
1432 const decls = err_set_decl.decls();
1433 for (decls) |node, i| {
1434 if (i + 1 < decls.len) {
1435 try renderExpression(allocator, ais, tree, node, Space.None);
1436 try renderToken(tree, ais, tree.nextToken(node.lastToken()), Space.Newline); // ,
1437
1438 try renderExtraNewline(tree, ais, decls[i + 1]);
1439 } else {
1440 try renderExpression(allocator, ais, tree, node, Space.Comma);
1441 }
1442 }
1443 }
1444
1445 return renderToken(tree, ais, err_set_decl.rbrace_token, space); // }
1446 } else {
1447 try renderToken(tree, ais, lbrace, Space.Space); // {
1448
1449 const decls = err_set_decl.decls();
1450 for (decls) |node, i| {
1451 if (i + 1 < decls.len) {
1452 try renderExpression(allocator, ais, tree, node, Space.None);
1453
1454 const comma_token = tree.nextToken(node.lastToken());
1455 assert(tree.token_ids[comma_token] == .Comma);
1456 try renderToken(tree, ais, comma_token, Space.Space); // ,
1457 try renderExtraNewline(tree, ais, decls[i + 1]);
1458 } else {
1459 try renderExpression(allocator, ais, tree, node, Space.Space);
1460 }
1461 }
1462
1463 return renderToken(tree, ais, err_set_decl.rbrace_token, space); // }
1464 }
1465 },
1466
1467 .ErrorTag => {
1468 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
1469
1470 try renderDocComments(tree, ais, tag, tag.doc_comments);
1471 return renderToken(tree, ais, tag.name_token, space); // name
1472 },
1473
1474 .MultilineStringLiteral => {
1475 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
1476
1477 {
1478 const locked_indents = ais.lockOneShotIndent();
1479 defer {
1480 var i: u8 = 0;
1481 while (i < locked_indents) : (i += 1) ais.popIndent();
1482 }
1483 try ais.maybeInsertNewline();
1484
1485 for (multiline_str_literal.lines()) |t| try renderToken(tree, ais, t, Space.None);
1486 }
1487 },
1488
1489 .BuiltinCall => {
1490 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
1491
1492 // TODO remove after 0.7.0 release
1493 if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))
1494 return ais.writer().writeAll("opaque {}");
1495
1496 // TODO remove after 0.7.0 release
1497 {
1498 const params = builtin_call.paramsConst();
1499 if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and
1500 params.len == 1)
1501 {
1502 if (params[0].castTag(.EnumLiteral)) |enum_literal|
1503 if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque"))
1504 return ais.writer().writeAll("opaque {}");
1505 }
1506 }
1507
1508 try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
1509
1510 const src_params_trailing_comma = blk: {
1511 if (builtin_call.params_len == 0) break :blk false;
1512 const last_node = builtin_call.params()[builtin_call.params_len - 1];
1513 const maybe_comma = tree.nextToken(last_node.lastToken());
1514 break :blk tree.token_ids[maybe_comma] == .Comma;
1515 };
1516
1517 const lparen = tree.nextToken(builtin_call.builtin_token);
1518
1519 if (!src_params_trailing_comma) {
1520 try renderToken(tree, ais, lparen, Space.None); // (
1521
1522 // render all on one line, no trailing comma
1523 const params = builtin_call.params();
1524 for (params) |param_node, i| {
1525 const maybe_comment = param_node.firstToken() - 1;
1526 if (param_node.*.tag == .MultilineStringLiteral or tree.token_ids[maybe_comment] == .LineComment) {
1527 ais.pushIndentOneShot();
1528 }
1529 try renderExpression(allocator, ais, tree, param_node, Space.None);
1530
1531 if (i + 1 < params.len) {
1532 const comma_token = tree.nextToken(param_node.lastToken());
1533 try renderToken(tree, ais, comma_token, Space.Space); // ,
1534 }
1535 }
1536 } else {
1537 // one param per line
1538 ais.pushIndent();
1539 defer ais.popIndent();
1540 try renderToken(tree, ais, lparen, Space.Newline); // (
1541
1542 for (builtin_call.params()) |param_node| {
1543 try renderExpression(allocator, ais, tree, param_node, Space.Comma);
1544 }
1545 }
1546
1547 return renderToken(tree, ais, builtin_call.rparen_token, space); // )
1548 },
1549
1550 .FnProto => {
1551 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
1552
1553 if (fn_proto.getVisibToken()) |visib_token_index| {
1554 const visib_token = tree.token_ids[visib_token_index];
1555 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
1556
1557 try renderToken(tree, ais, visib_token_index, Space.Space); // pub
1558 }
1559
1560 if (fn_proto.getExternExportInlineToken()) |extern_export_inline_token| {
1561 if (fn_proto.getIsExternPrototype() == null)
1562 try renderToken(tree, ais, extern_export_inline_token, Space.Space); // extern/export/inline
1563 }
1564
1565 if (fn_proto.getLibName()) |lib_name| {
1566 try renderExpression(allocator, ais, tree, lib_name, Space.Space);
1567 }
1568
1569 const lparen = if (fn_proto.getNameToken()) |name_token| blk: {
1570 try renderToken(tree, ais, fn_proto.fn_token, Space.Space); // fn
1571 try renderToken(tree, ais, name_token, Space.None); // name
1572 break :blk tree.nextToken(name_token);
1573 } else blk: {
1574 try renderToken(tree, ais, fn_proto.fn_token, Space.Space); // fn
1575 break :blk tree.nextToken(fn_proto.fn_token);
1576 };
1577 assert(tree.token_ids[lparen] == .LParen);
1578
1579 const rparen = tree.prevToken(
1580 // the first token for the annotation expressions is the left
1581 // parenthesis, hence the need for two prevToken
1582 if (fn_proto.getAlignExpr()) |align_expr|
1583 tree.prevToken(tree.prevToken(align_expr.firstToken()))
1584 else if (fn_proto.getSectionExpr()) |section_expr|
1585 tree.prevToken(tree.prevToken(section_expr.firstToken()))
1586 else if (fn_proto.getCallconvExpr()) |callconv_expr|
1587 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
1588 else switch (fn_proto.return_type) {
1589 .Explicit => |node| node.firstToken(),
1590 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1591 .Invalid => unreachable,
1592 },
1593 );
1594 assert(tree.token_ids[rparen] == .RParen);
1595
1596 const src_params_trailing_comma = blk: {
1597 const maybe_comma = tree.token_ids[rparen - 1];
1598 break :blk maybe_comma == .Comma or maybe_comma == .LineComment;
1599 };
1600
1601 if (!src_params_trailing_comma) {
1602 try renderToken(tree, ais, lparen, Space.None); // (
1603
1604 // render all on one line, no trailing comma
1605 for (fn_proto.params()) |param_decl, i| {
1606 try renderParamDecl(allocator, ais, tree, param_decl, Space.None);
1607
1608 if (i + 1 < fn_proto.params_len or fn_proto.getVarArgsToken() != null) {
1609 const comma = tree.nextToken(param_decl.lastToken());
1610 try renderToken(tree, ais, comma, Space.Space); // ,
1611 }
1612 }
1613 if (fn_proto.getVarArgsToken()) |var_args_token| {
1614 try renderToken(tree, ais, var_args_token, Space.None);
1615 }
1616 } else {
1617 // one param per line
1618 ais.pushIndent();
1619 defer ais.popIndent();
1620 try renderToken(tree, ais, lparen, Space.Newline); // (
1621
1622 for (fn_proto.params()) |param_decl| {
1623 try renderParamDecl(allocator, ais, tree, param_decl, Space.Comma);
1624 }
1625 if (fn_proto.getVarArgsToken()) |var_args_token| {
1626 try renderToken(tree, ais, var_args_token, Space.Comma);
1627 }
1628 }
1629
1630 try renderToken(tree, ais, rparen, Space.Space); // )
1631
1632 if (fn_proto.getAlignExpr()) |align_expr| {
1633 const align_rparen = tree.nextToken(align_expr.lastToken());
1634 const align_lparen = tree.prevToken(align_expr.firstToken());
1635 const align_kw = tree.prevToken(align_lparen);
1636
1637 try renderToken(tree, ais, align_kw, Space.None); // align
1638 try renderToken(tree, ais, align_lparen, Space.None); // (
1639 try renderExpression(allocator, ais, tree, align_expr, Space.None);
1640 try renderToken(tree, ais, align_rparen, Space.Space); // )
1641 }
1642
1643 if (fn_proto.getSectionExpr()) |section_expr| {
1644 const section_rparen = tree.nextToken(section_expr.lastToken());
1645 const section_lparen = tree.prevToken(section_expr.firstToken());
1646 const section_kw = tree.prevToken(section_lparen);
1647
1648 try renderToken(tree, ais, section_kw, Space.None); // section
1649 try renderToken(tree, ais, section_lparen, Space.None); // (
1650 try renderExpression(allocator, ais, tree, section_expr, Space.None);
1651 try renderToken(tree, ais, section_rparen, Space.Space); // )
1652 }
1653
1654 if (fn_proto.getCallconvExpr()) |callconv_expr| {
1655 const callconv_rparen = tree.nextToken(callconv_expr.lastToken());
1656 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
1657 const callconv_kw = tree.prevToken(callconv_lparen);
1658
1659 try renderToken(tree, ais, callconv_kw, Space.None); // callconv
1660 try renderToken(tree, ais, callconv_lparen, Space.None); // (
1661 try renderExpression(allocator, ais, tree, callconv_expr, Space.None);
1662 try renderToken(tree, ais, callconv_rparen, Space.Space); // )
1663 } else if (fn_proto.getIsExternPrototype() != null) {
1664 try ais.writer().writeAll("callconv(.C) ");
1665 } else if (fn_proto.getIsAsync() != null) {
1666 try ais.writer().writeAll("callconv(.Async) ");
1667 }
1668
1669 switch (fn_proto.return_type) {
1670 .Explicit => |node| {
1671 return renderExpression(allocator, ais, tree, node, space);
1672 },
1673 .InferErrorSet => |node| {
1674 try renderToken(tree, ais, tree.prevToken(node.firstToken()), Space.None); // !
1675 return renderExpression(allocator, ais, tree, node, space);
1676 },
1677 .Invalid => unreachable,
1678 }
1679 },
1680
1681 .AnyFrameType => {
1682 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
1683
1684 if (anyframe_type.result) |result| {
1685 try renderToken(tree, ais, anyframe_type.anyframe_token, Space.None); // anyframe
1686 try renderToken(tree, ais, result.arrow_token, Space.None); // ->
1687 return renderExpression(allocator, ais, tree, result.return_type, space);
1688 } else {
1689 return renderToken(tree, ais, anyframe_type.anyframe_token, space); // anyframe
1690 }
1691 },
1692
1693 .DocComment => unreachable, // doc comments are attached to nodes
1694
1695 .Switch => {
1696 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
1697
1698 try renderToken(tree, ais, switch_node.switch_token, Space.Space); // switch
1699 try renderToken(tree, ais, tree.nextToken(switch_node.switch_token), Space.None); // (
1700
1701 const rparen = tree.nextToken(switch_node.expr.lastToken());
1702 const lbrace = tree.nextToken(rparen);
1703
1704 if (switch_node.cases_len == 0) {
1705 try renderExpression(allocator, ais, tree, switch_node.expr, Space.None);
1706 try renderToken(tree, ais, rparen, Space.Space); // )
1707 try renderToken(tree, ais, lbrace, Space.None); // {
1708 return renderToken(tree, ais, switch_node.rbrace, space); // }
1709 }
1710
1711 try renderExpression(allocator, ais, tree, switch_node.expr, Space.None);
1712 try renderToken(tree, ais, rparen, Space.Space); // )
1713
1714 {
1715 ais.pushIndentNextLine();
1716 defer ais.popIndent();
1717 try renderToken(tree, ais, lbrace, Space.Newline); // {
1718
1719 const cases = switch_node.cases();
1720 for (cases) |node, i| {
1721 try renderExpression(allocator, ais, tree, node, Space.Comma);
1722
1723 if (i + 1 < cases.len) {
1724 try renderExtraNewline(tree, ais, cases[i + 1]);
1725 }
1726 }
1727 }
1728
1729 return renderToken(tree, ais, switch_node.rbrace, space); // }
1730 },
1731
1732 .SwitchCase => {
1733 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
1734
1735 assert(switch_case.items_len != 0);
1736 const src_has_trailing_comma = blk: {
1737 const last_node = switch_case.items()[switch_case.items_len - 1];
1738 const maybe_comma = tree.nextToken(last_node.lastToken());
1739 break :blk tree.token_ids[maybe_comma] == .Comma;
1740 };
1741
1742 if (switch_case.items_len == 1 or !src_has_trailing_comma) {
1743 const items = switch_case.items();
1744 for (items) |node, i| {
1745 if (i + 1 < items.len) {
1746 try renderExpression(allocator, ais, tree, node, Space.None);
1747
1748 const comma_token = tree.nextToken(node.lastToken());
1749 try renderToken(tree, ais, comma_token, Space.Space); // ,
1750 try renderExtraNewline(tree, ais, items[i + 1]);
1751 } else {
1752 try renderExpression(allocator, ais, tree, node, Space.Space);
1753 }
1754 }
1755 } else {
1756 const items = switch_case.items();
1757 for (items) |node, i| {
1758 if (i + 1 < items.len) {
1759 try renderExpression(allocator, ais, tree, node, Space.None);
1760
1761 const comma_token = tree.nextToken(node.lastToken());
1762 try renderToken(tree, ais, comma_token, Space.Newline); // ,
1763 try renderExtraNewline(tree, ais, items[i + 1]);
1764 } else {
1765 try renderExpression(allocator, ais, tree, node, Space.Comma);
1766 }
1767 }
1768 }
1769
1770 try renderToken(tree, ais, switch_case.arrow_token, Space.Space); // =>
1771
1772 if (switch_case.payload) |payload| {
1773 try renderExpression(allocator, ais, tree, payload, Space.Space);
1774 }
1775
1776 return renderExpression(allocator, ais, tree, switch_case.expr, space);
1777 },
1778 .SwitchElse => {
1779 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
1780 return renderToken(tree, ais, switch_else.token, space);
1781 },
1782 .Else => {
1783 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
1784
1785 const body_is_block = nodeIsBlock(else_node.body);
1786 const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken());
1787
1788 const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline;
1789 try renderToken(tree, ais, else_node.else_token, after_else_space);
1790
1791 if (else_node.payload) |payload| {
1792 const payload_space = if (same_line) Space.Space else Space.Newline;
1793 try renderExpression(allocator, ais, tree, payload, payload_space);
1794 }
1795
1796 if (same_line) {
1797 return renderExpression(allocator, ais, tree, else_node.body, space);
1798 } else {
1799 ais.pushIndent();
1800 defer ais.popIndent();
1801 return renderExpression(allocator, ais, tree, else_node.body, space);
1802 }
1803 },
1804
1805 .While => {
1806 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
1807
1808 if (while_node.label) |label| {
1809 try renderToken(tree, ais, label, Space.None); // label
1810 try renderToken(tree, ais, tree.nextToken(label), Space.Space); // :
1811 }
1812
1813 if (while_node.inline_token) |inline_token| {
1814 try renderToken(tree, ais, inline_token, Space.Space); // inline
1815 }
1816
1817 try renderToken(tree, ais, while_node.while_token, Space.Space); // while
1818 try renderToken(tree, ais, tree.nextToken(while_node.while_token), Space.None); // (
1819 try renderExpression(allocator, ais, tree, while_node.condition, Space.None);
1820
1821 const cond_rparen = tree.nextToken(while_node.condition.lastToken());
1822
1823 const body_is_block = nodeIsBlock(while_node.body);
1824
1825 var block_start_space: Space = undefined;
1826 var after_body_space: Space = undefined;
1827
1828 if (body_is_block) {
1829 block_start_space = Space.BlockStart;
1830 after_body_space = if (while_node.@"else" == null) space else Space.SpaceOrOutdent;
1831 } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) {
1832 block_start_space = Space.Space;
1833 after_body_space = if (while_node.@"else" == null) space else Space.Space;
1834 } else {
1835 block_start_space = Space.Newline;
1836 after_body_space = if (while_node.@"else" == null) space else Space.Newline;
1837 }
1838
1839 {
1840 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;
1841 try renderToken(tree, ais, cond_rparen, rparen_space); // )
1842 }
1843
1844 if (while_node.payload) |payload| {
1845 const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
1846 try renderExpression(allocator, ais, tree, payload, payload_space);
1847 }
1848
1849 if (while_node.continue_expr) |continue_expr| {
1850 const rparen = tree.nextToken(continue_expr.lastToken());
1851 const lparen = tree.prevToken(continue_expr.firstToken());
1852 const colon = tree.prevToken(lparen);
1853
1854 try renderToken(tree, ais, colon, Space.Space); // :
1855 try renderToken(tree, ais, lparen, Space.None); // (
1856
1857 try renderExpression(allocator, ais, tree, continue_expr, Space.None);
1858
1859 try renderToken(tree, ais, rparen, block_start_space); // )
1860 }
1861
1862 {
1863 if (!body_is_block) ais.pushIndent();
1864 defer if (!body_is_block) ais.popIndent();
1865 try renderExpression(allocator, ais, tree, while_node.body, after_body_space);
1866 }
25/// Returns whether anything changed.
26/// `gpa` is used for allocating extra stack memory if needed, because
27/// this function utilizes recursion.
28pub fn render(gpa: *mem.Allocator, writer: Writer, tree: ast.Tree) Error!void {
29 assert(tree.errors.len == 0); // cannot render an invalid tree
30 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, writer);
31 try renderRoot(&auto_indenting_stream, tree);
32}
186733
1868 if (while_node.@"else") |@"else"| {
1869 return renderExpression(allocator, ais, tree, &@"else".base, space);
34/// Assumes there are no tokens in between start and end.
35fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize, prefix: []const u8) Error!usize {
36 var index: usize = start;
37 var count: usize = 0;
38 while (true) {
39 // Scan forward to the next line comment, counting newlines.
40 const comment_start = mem.indexOf(u8, tree.source[index..end], "//") orelse return count;
41 const newline = mem.indexOfScalar(u8, tree.source[comment_start..end], '\n').?;
42 const untrimmed_comment = tree.source[comment_start..][0..newline];
43 const trimmed_comment = mem.trimRight(u8, untrimmed_comment, " \r\t");
44 if (count == 0) {
45 count += 1;
46 try ais.writer().writeAll(prefix);
47 } else {
48 // If another newline occurs between prev comment and this one
49 // we honor it, but not any additional ones.
50 if (mem.indexOfScalar(u8, tree.source[index..comment_start], '\n') != null) {
51 try ais.insertNewline();
187052 }
1871 },
53 }
54 try ais.writer().print("{s}\n", .{trimmed_comment});
55 index += comment_start + newline;
56 }
57}
187258
1873 .For => {
1874 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
59fn renderRoot(ais: *Ais, tree: ast.Tree) Error!void {
60 // Render all the line comments at the beginning of the file.
61 const src_start: usize = if (mem.startsWith(u8, tree.source, "\xEF\xBB\xBF")) 3 else 0;
62 const comment_end_loc: usize = tree.tokens.items(.start)[0];
63 _ = try renderComments(ais, tree, src_start, comment_end_loc, "");
187564
1876 if (for_node.label) |label| {
1877 try renderToken(tree, ais, label, Space.None); // label
1878 try renderToken(tree, ais, tree.nextToken(label), Space.Space); // :
1879 }
65 // Root is always index 0.
66 const nodes_data = tree.nodes.items(.data);
67 const root_decls = tree.extra_data[nodes_data[0].lhs..nodes_data[0].rhs];
68 if (root_decls.len == 0) return;
188069
1881 if (for_node.inline_token) |inline_token| {
1882 try renderToken(tree, ais, inline_token, Space.Space); // inline
1883 }
70 for (root_decls) |decl| {
71 try renderTopLevelDecl(ais, tree, decl);
72 }
73}
188474
1885 try renderToken(tree, ais, for_node.for_token, Space.Space); // for
1886 try renderToken(tree, ais, tree.nextToken(for_node.for_token), Space.None); // (
1887 try renderExpression(allocator, ais, tree, for_node.array_expr, Space.None);
75fn renderExtraNewline(tree: ast.Tree, ais: *Ais, node: ast.Node.Index) Error!void {
76 return renderExtraNewlineToken(tree, ais, tree.firstToken(node));
77}
188878
1889 const rparen = tree.nextToken(for_node.array_expr.lastToken());
79fn renderExtraNewlineToken(tree: ast.Tree, ais: *Ais, first_token: ast.TokenIndex) Error!void {
80 @panic("TODO implement renderExtraNewlineToken");
81 //var prev_token = first_token;
82 //if (prev_token == 0) return;
83 //const token_tags = tree.tokens.items(.tag);
84 //var newline_threshold: usize = 2;
85 //while (token_tags[prev_token - 1] == .DocComment) {
86 // if (tree.tokenLocation(tree.token_locs[prev_token - 1].end, prev_token).line == 1) {
87 // newline_threshold += 1;
88 // }
89 // prev_token -= 1;
90 //}
91 //const prev_token_end = tree.token_locs[prev_token - 1].end;
92 //const loc = tree.tokenLocation(prev_token_end, first_token);
93 //if (loc.line >= newline_threshold) {
94 // try ais.insertNewline();
95 //}
96}
189097
1891 const body_is_block = for_node.body.tag.isBlock();
1892 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
1893 const body_on_same_line = body_is_block or src_one_line_to_body;
98fn renderTopLevelDecl(ais: *Ais, tree: ast.Tree, decl: ast.Node.Index) Error!void {
99 return renderContainerDecl(ais, tree, decl, .Newline);
100}
1894101
1895 try renderToken(tree, ais, rparen, Space.Space); // )
102fn renderContainerDecl(ais: *Ais, tree: ast.Tree, decl: ast.Node.Index, space: Space) Error!void {
103 switch (tree.nodes.items(.tag)[decl]) {
104 .UsingNamespace,
105 .FnProtoSimple,
106 .FnProtoSimpleMulti,
107 .FnProtoOne,
108 .FnProto,
109 .FnDecl,
110 .GlobalVarDecl,
111 .LocalVarDecl,
112 .SimpleVarDecl,
113 .AlignedVarDecl,
114 .TestDecl,
115 .ContainerFieldInit,
116 .ContainerFieldAlign,
117 .ContainerField,
118 => @panic("TODO implement renderContainerDecl"),
1896119
1897 const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;
1898 try renderExpression(allocator, ais, tree, for_node.payload, space_after_payload); // |x|
120 .Comptime => return renderExpression(ais, tree, decl, space),
1899121
1900 const space_after_body = blk: {
1901 if (for_node.@"else") |@"else"| {
1902 const src_one_line_to_else = tree.tokensOnSameLine(rparen, @"else".firstToken());
1903 if (body_is_block or src_one_line_to_else) {
1904 break :blk Space.Space;
1905 } else {
1906 break :blk Space.Newline;
1907 }
1908 } else {
1909 break :blk space;
1910 }
1911 };
122 else => unreachable,
123 }
124 //switch (tag) {
125 // .FnProto => {
126 // const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
127
128 // try renderDocComments(tree, ais, fn_proto, fn_proto.getDocComments());
129
130 // if (fn_proto.getBodyNode()) |body_node| {
131 // try renderExpression(allocator, ais, tree, decl, .Space);
132 // try renderExpression(allocator, ais, tree, body_node, space);
133 // } else {
134 // try renderExpression(allocator, ais, tree, decl, .None);
135 // try renderToken(ais, tree, tree.nextToken(decl.lastToken()), space);
136 // }
137 // },
138
139 // .Use => {
140 // const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
141
142 // if (use_decl.visib_token) |visib_token| {
143 // try renderToken(ais, tree, visib_token, .Space); // pub
144 // }
145 // try renderToken(ais, tree, use_decl.use_token, .Space); // usingnamespace
146 // try renderExpression(allocator, ais, tree, use_decl.expr, .None);
147 // try renderToken(ais, tree, use_decl.semicolon_token, space); // ;
148 // },
149
150 // .VarDecl => {
151 // const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
152
153 // try renderDocComments(tree, ais, var_decl, var_decl.getDocComments());
154 // try renderVarDecl(allocator, ais, tree, var_decl);
155 // },
156
157 // .TestDecl => {
158 // const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
159
160 // try renderDocComments(tree, ais, test_decl, test_decl.doc_comments);
161 // try renderToken(ais, tree, test_decl.test_token, .Space);
162 // if (test_decl.name) |name|
163 // try renderExpression(allocator, ais, tree, name, .Space);
164 // try renderExpression(allocator, ais, tree, test_decl.body_node, space);
165 // },
166
167 // .ContainerField => {
168 // const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
169
170 // try renderDocComments(tree, ais, field, field.doc_comments);
171 // if (field.comptime_token) |t| {
172 // try renderToken(ais, tree, t, .Space); // comptime
173 // }
174
175 // const src_has_trailing_comma = blk: {
176 // const maybe_comma = tree.nextToken(field.lastToken());
177 // break :blk tree.token_tags[maybe_comma] == .Comma;
178 // };
179
180 // // The trailing comma is emitted at the end, but if it's not present
181 // // we still have to respect the specified `space` parameter
182 // const last_token_space: Space = if (src_has_trailing_comma) .None else space;
183
184 // if (field.type_expr == null and field.value_expr == null) {
185 // try renderToken(ais, tree, field.name_token, last_token_space); // name
186 // } else if (field.type_expr != null and field.value_expr == null) {
187 // try renderToken(ais, tree, field.name_token, .None); // name
188 // try renderToken(ais, tree, tree.nextToken(field.name_token), .Space); // :
189
190 // if (field.align_expr) |align_value_expr| {
191 // try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type
192 // const lparen_token = tree.prevToken(align_value_expr.firstToken());
193 // const align_kw = tree.prevToken(lparen_token);
194 // const rparen_token = tree.nextToken(align_value_expr.lastToken());
195 // try renderToken(ais, tree, align_kw, .None); // align
196 // try renderToken(ais, tree, lparen_token, .None); // (
197 // try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment
198 // try renderToken(ais, tree, rparen_token, last_token_space); // )
199 // } else {
200 // try renderExpression(allocator, ais, tree, field.type_expr.?, last_token_space); // type
201 // }
202 // } else if (field.type_expr == null and field.value_expr != null) {
203 // try renderToken(ais, tree, field.name_token, .Space); // name
204 // try renderToken(ais, tree, tree.nextToken(field.name_token), .Space); // =
205 // try renderExpression(allocator, ais, tree, field.value_expr.?, last_token_space); // value
206 // } else {
207 // try renderToken(ais, tree, field.name_token, .None); // name
208 // try renderToken(ais, tree, tree.nextToken(field.name_token), .Space); // :
209
210 // if (field.align_expr) |align_value_expr| {
211 // try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type
212 // const lparen_token = tree.prevToken(align_value_expr.firstToken());
213 // const align_kw = tree.prevToken(lparen_token);
214 // const rparen_token = tree.nextToken(align_value_expr.lastToken());
215 // try renderToken(ais, tree, align_kw, .None); // align
216 // try renderToken(ais, tree, lparen_token, .None); // (
217 // try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment
218 // try renderToken(ais, tree, rparen_token, .Space); // )
219 // } else {
220 // try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type
221 // }
222 // try renderToken(ais, tree, tree.prevToken(field.value_expr.?.firstToken()), .Space); // =
223 // try renderExpression(allocator, ais, tree, field.value_expr.?, last_token_space); // value
224 // }
225
226 // if (src_has_trailing_comma) {
227 // const comma = tree.nextToken(field.lastToken());
228 // try renderToken(ais, tree, comma, space);
229 // }
230 // },
231
232 // .DocComment => {
233 // const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);
234 // const kind = tree.token_tags[comment.first_line];
235 // try renderToken(ais, tree, comment.first_line, .Newline);
236 // var tok_i = comment.first_line + 1;
237 // while (true) : (tok_i += 1) {
238 // const tok_id = tree.token_tags[tok_i];
239 // if (tok_id == kind) {
240 // try renderToken(ais, tree, tok_i, .Newline);
241 // } else if (tok_id == .LineComment) {
242 // continue;
243 // } else {
244 // break;
245 // }
246 // }
247 // },
248 // else => unreachable,
249 //}
250}
1912251
252fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void {
253 const token_tags = tree.tokens.items(.tag);
254 const main_tokens = tree.nodes.items(.main_token);
255 switch (tree.nodes.items(.tag)[node]) {
256 //.Identifier,
257 //.IntegerLiteral,
258 //.FloatLiteral,
259 //.StringLiteral,
260 //.CharLiteral,
261 //.BoolLiteral,
262 //.NullLiteral,
263 //.Unreachable,
264 //.ErrorType,
265 //.UndefinedLiteral,
266 //=> {
267 // const casted_node = base.cast(ast.Node.OneToken).?;
268 // return renderToken(ais, tree, casted_node.token, space);
269 //},
270
271 //.AnyType => {
272 // const any_type = base.castTag(.AnyType).?;
273 // if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {
274 // // TODO remove in next release cycle
275 // try ais.writer().writeAll("anytype");
276 // if (space == .Comma) try ais.writer().writeAll(",\n");
277 // return;
278 // }
279 // return renderToken(ais, tree, any_type.token, space);
280 //},
281 .Block => {
282 const lbrace = main_tokens[node];
283 if (token_tags[lbrace - 1] == .Colon and
284 token_tags[lbrace - 2] == .Identifier)
1913285 {
1914 if (!body_on_same_line) ais.pushIndent();
1915 defer if (!body_on_same_line) ais.popIndent();
1916 try renderExpression(allocator, ais, tree, for_node.body, space_after_body); // { body }
1917 }
1918
1919 if (for_node.@"else") |@"else"| {
1920 return renderExpression(allocator, ais, tree, &@"else".base, space); // else
1921 }
1922 },
1923
1924 .If => {
1925 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
1926
1927 const lparen = tree.nextToken(if_node.if_token);
1928 const rparen = tree.nextToken(if_node.condition.lastToken());
1929
1930 try renderToken(tree, ais, if_node.if_token, Space.Space); // if
1931 try renderToken(tree, ais, lparen, Space.None); // (
1932
1933 try renderExpression(allocator, ais, tree, if_node.condition, Space.None); // condition
1934
1935 const body_is_if_block = if_node.body.tag == .If;
1936 const body_is_block = nodeIsBlock(if_node.body);
1937
1938 if (body_is_if_block) {
1939 try renderExtraNewline(tree, ais, if_node.body);
1940 } else if (body_is_block) {
1941 const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;
1942 try renderToken(tree, ais, rparen, after_rparen_space); // )
1943
1944 if (if_node.payload) |payload| {
1945 try renderExpression(allocator, ais, tree, payload, Space.BlockStart); // |x|
1946 }
1947
1948 if (if_node.@"else") |@"else"| {
1949 try renderExpression(allocator, ais, tree, if_node.body, Space.SpaceOrOutdent);
1950 return renderExpression(allocator, ais, tree, &@"else".base, space);
1951 } else {
1952 return renderExpression(allocator, ais, tree, if_node.body, space);
1953 }
1954 }
1955
1956 const src_has_newline = !tree.tokensOnSameLine(rparen, if_node.body.lastToken());
1957
1958 if (src_has_newline) {
1959 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
1960
1961 {
1962 ais.pushIndent();
1963 defer ais.popIndent();
1964 try renderToken(tree, ais, rparen, after_rparen_space); // )
1965 }
1966
1967 if (if_node.payload) |payload| {
1968 try renderExpression(allocator, ais, tree, payload, Space.Newline);
1969 }
1970
1971 if (if_node.@"else") |@"else"| {
1972 const else_is_block = nodeIsBlock(@"else".body);
1973
1974 {
1975 ais.pushIndent();
1976 defer ais.popIndent();
1977 try renderExpression(allocator, ais, tree, if_node.body, Space.Newline);
1978 }
1979
1980 if (else_is_block) {
1981 try renderToken(tree, ais, @"else".else_token, Space.Space); // else
1982
1983 if (@"else".payload) |payload| {
1984 try renderExpression(allocator, ais, tree, payload, Space.Space);
1985 }
1986
1987 return renderExpression(allocator, ais, tree, @"else".body, space);
1988 } else {
1989 const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space;
1990 try renderToken(tree, ais, @"else".else_token, after_else_space); // else
1991
1992 if (@"else".payload) |payload| {
1993 try renderExpression(allocator, ais, tree, payload, Space.Newline);
1994 }
1995
1996 ais.pushIndent();
1997 defer ais.popIndent();
1998 return renderExpression(allocator, ais, tree, @"else".body, space);
1999 }
2000 } else {
2001 ais.pushIndent();
2002 defer ais.popIndent();
2003 return renderExpression(allocator, ais, tree, if_node.body, space);
2004 }
2005 }
2006
2007 // Single line if statement
2008
2009 try renderToken(tree, ais, rparen, Space.Space); // )
2010
2011 if (if_node.payload) |payload| {
2012 try renderExpression(allocator, ais, tree, payload, Space.Space);
2013 }
2014
2015 if (if_node.@"else") |@"else"| {
2016 try renderExpression(allocator, ais, tree, if_node.body, Space.Space);
2017 try renderToken(tree, ais, @"else".else_token, Space.Space);
2018
2019 if (@"else".payload) |payload| {
2020 try renderExpression(allocator, ais, tree, payload, Space.Space);
2021 }
2022
2023 return renderExpression(allocator, ais, tree, @"else".body, space);
2024 } else {
2025 return renderExpression(allocator, ais, tree, if_node.body, space);
286 try renderToken(ais, tree, lbrace - 2, .None);
287 try renderToken(ais, tree, lbrace - 1, .Space);
2026288 }
2027 },
289 const nodes_data = tree.nodes.items(.data);
290 const statements = tree.extra_data[nodes_data[node].lhs..nodes_data[node].rhs];
2028291
2029 .Asm => {
2030 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
2031
2032 try renderToken(tree, ais, asm_node.asm_token, Space.Space); // asm
2033
2034 if (asm_node.volatile_token) |volatile_token| {
2035 try renderToken(tree, ais, volatile_token, Space.Space); // volatile
2036 try renderToken(tree, ais, tree.nextToken(volatile_token), Space.None); // (
292 if (statements.len == 0) {
293 ais.pushIndentNextLine();
294 try renderToken(ais, tree, lbrace, .None);
295 ais.popIndent();
296 const rbrace = lbrace + 1;
297 return renderToken(ais, tree, rbrace, space);
2037298 } else {
2038 try renderToken(tree, ais, tree.nextToken(asm_node.asm_token), Space.None); // (
2039 }
299 ais.pushIndentNextLine();
2040300
2041 asmblk: {
2042 ais.pushIndent();
2043 defer ais.popIndent();
301 try renderToken(ais, tree, lbrace, .Newline);
2044302
2045 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
2046 try renderExpression(allocator, ais, tree, asm_node.template, Space.None);
2047 break :asmblk;
2048 }
303 for (statements) |statement, i| {
304 try renderStatement(ais, tree, statement);
2049305
2050 try renderExpression(allocator, ais, tree, asm_node.template, Space.Newline);
2051
2052 ais.setIndentDelta(asm_indent_delta);
2053 defer ais.setIndentDelta(indent_delta);
2054
2055 const colon1 = tree.nextToken(asm_node.template.lastToken());
2056
2057 const colon2 = if (asm_node.outputs.len == 0) blk: {
2058 try renderToken(tree, ais, colon1, Space.Newline); // :
2059
2060 break :blk tree.nextToken(colon1);
2061 } else blk: {
2062 try renderToken(tree, ais, colon1, Space.Space); // :
2063
2064 ais.pushIndent();
2065 defer ais.popIndent();
2066
2067 for (asm_node.outputs) |*asm_output, i| {
2068 if (i + 1 < asm_node.outputs.len) {
2069 const next_asm_output = asm_node.outputs[i + 1];
2070 try renderAsmOutput(allocator, ais, tree, asm_output, Space.None);
2071
2072 const comma = tree.prevToken(next_asm_output.firstToken());
2073 try renderToken(tree, ais, comma, Space.Newline); // ,
2074 try renderExtraNewlineToken(tree, ais, next_asm_output.firstToken());
2075 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
2076 try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline);
2077 break :asmblk;
2078 } else {
2079 try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline);
2080 const comma_or_colon = tree.nextToken(asm_output.lastToken());
2081 break :blk switch (tree.token_ids[comma_or_colon]) {
2082 .Comma => tree.nextToken(comma_or_colon),
2083 else => comma_or_colon,
2084 };
2085 }
2086 }
2087 unreachable;
2088 };
2089
2090 const colon3 = if (asm_node.inputs.len == 0) blk: {
2091 try renderToken(tree, ais, colon2, Space.Newline); // :
2092 break :blk tree.nextToken(colon2);
2093 } else blk: {
2094 try renderToken(tree, ais, colon2, Space.Space); // :
2095 ais.pushIndent();
2096 defer ais.popIndent();
2097 for (asm_node.inputs) |*asm_input, i| {
2098 if (i + 1 < asm_node.inputs.len) {
2099 const next_asm_input = &asm_node.inputs[i + 1];
2100 try renderAsmInput(allocator, ais, tree, asm_input, Space.None);
2101
2102 const comma = tree.prevToken(next_asm_input.firstToken());
2103 try renderToken(tree, ais, comma, Space.Newline); // ,
2104 try renderExtraNewlineToken(tree, ais, next_asm_input.firstToken());
2105 } else if (asm_node.clobbers.len == 0) {
2106 try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline);
2107 break :asmblk;
2108 } else {
2109 try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline);
2110 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2111 break :blk switch (tree.token_ids[comma_or_colon]) {
2112 .Comma => tree.nextToken(comma_or_colon),
2113 else => comma_or_colon,
2114 };
2115 }
2116 }
2117 unreachable;
2118 };
2119
2120 try renderToken(tree, ais, colon3, Space.Space); // :
2121 ais.pushIndent();
2122 defer ais.popIndent();
2123 for (asm_node.clobbers) |clobber_node, i| {
2124 if (i + 1 >= asm_node.clobbers.len) {
2125 try renderExpression(allocator, ais, tree, clobber_node, Space.Newline);
2126 break :asmblk;
2127 } else {
2128 try renderExpression(allocator, ais, tree, clobber_node, Space.None);
2129 const comma = tree.nextToken(clobber_node.lastToken());
2130 try renderToken(tree, ais, comma, Space.Space); // ,
306 if (i + 1 < statements.len) {
307 try renderExtraNewline(tree, ais, statements[i + 1]);
2131308 }
2132309 }
310 ais.popIndent();
311 const rbrace = tree.lastToken(statements[statements.len - 1]) + 1;
312 return renderToken(ais, tree, rbrace, space);
2133313 }
2134
2135 return renderToken(tree, ais, asm_node.rparen, space);
2136314 },
2137315
2138 .EnumLiteral => {
2139 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
316 //.Defer => {
317 // const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
2140318
2141 try renderToken(tree, ais, enum_literal.dot, Space.None); // .
2142 return renderToken(tree, ais, enum_literal.name, space); // name
319 // try renderToken(ais, tree, defer_node.defer_token, Space.Space);
320 // if (defer_node.payload) |payload| {
321 // try renderExpression(allocator, ais, tree, payload, Space.Space);
322 // }
323 // return renderExpression(allocator, ais, tree, defer_node.expr, space);
324 //},
325 .Comptime => {
326 const comptime_token = tree.nodes.items(.main_token)[node];
327 const block = tree.nodes.items(.data)[node].lhs;
328 try renderToken(ais, tree, comptime_token, .Space);
329 return renderExpression(ais, tree, block, space);
2143330 },
2144
2145 .ContainerField,
2146 .Root,
2147 .VarDecl,
2148 .Use,
2149 .TestDecl,
2150 => unreachable,
331 //.Nosuspend => {
332 // const nosuspend_node = @fieldParentPtr(ast.Node.Nosuspend, "base", base);
333 // if (mem.eql(u8, tree.tokenSlice(nosuspend_node.nosuspend_token), "noasync")) {
334 // // TODO: remove this
335 // try ais.writer().writeAll("nosuspend ");
336 // } else {
337 // try renderToken(ais, tree, nosuspend_node.nosuspend_token, Space.Space);
338 // }
339 // return renderExpression(allocator, ais, tree, nosuspend_node.expr, space);
340 //},
341
342 //.Suspend => {
343 // const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
344
345 // if (suspend_node.body) |body| {
346 // try renderToken(ais, tree, suspend_node.suspend_token, Space.Space);
347 // return renderExpression(allocator, ais, tree, body, space);
348 // } else {
349 // return renderToken(ais, tree, suspend_node.suspend_token, space);
350 // }
351 //},
352
353 //.Catch => {
354 // const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base);
355
356 // const op_space = Space.Space;
357 // try renderExpression(allocator, ais, tree, infix_op_node.lhs, op_space);
358
359 // const after_op_space = blk: {
360 // const same_line = tree.tokensOnSameLine(infix_op_node.op_token, tree.nextToken(infix_op_node.op_token));
361 // break :blk if (same_line) op_space else Space.Newline;
362 // };
363
364 // try renderToken(ais, tree, infix_op_node.op_token, after_op_space);
365
366 // if (infix_op_node.payload) |payload| {
367 // try renderExpression(allocator, ais, tree, payload, Space.Space);
368 // }
369
370 // ais.pushIndentOneShot();
371 // return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
372 //},
373
374 //.Add,
375 //.AddWrap,
376 //.ArrayCat,
377 //.ArrayMult,
378 //.Assign,
379 //.AssignBitAnd,
380 //.AssignBitOr,
381 //.AssignBitShiftLeft,
382 //.AssignBitShiftRight,
383 //.AssignBitXor,
384 //.AssignDiv,
385 //.AssignSub,
386 //.AssignSubWrap,
387 //.AssignMod,
388 //.AssignAdd,
389 //.AssignAddWrap,
390 //.AssignMul,
391 //.AssignMulWrap,
392 //.BangEqual,
393 //.BitAnd,
394 //.BitOr,
395 //.BitShiftLeft,
396 //.BitShiftRight,
397 //.BitXor,
398 //.BoolAnd,
399 //.BoolOr,
400 //.Div,
401 //.EqualEqual,
402 //.ErrorUnion,
403 //.GreaterOrEqual,
404 //.GreaterThan,
405 //.LessOrEqual,
406 //.LessThan,
407 //.MergeErrorSets,
408 //.Mod,
409 //.Mul,
410 //.MulWrap,
411 //.Period,
412 //.Range,
413 //.Sub,
414 //.SubWrap,
415 //.OrElse,
416 //=> {
417 // const infix_op_node = @fieldParentPtr(ast.Node.SimpleInfixOp, "base", base);
418
419 // const op_space = switch (base.tag) {
420 // .Period, .ErrorUnion, .Range => Space.None,
421 // else => Space.Space,
422 // };
423 // try renderExpression(allocator, ais, tree, infix_op_node.lhs, op_space);
424
425 // const after_op_space = blk: {
426 // const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
427 // break :blk if (loc.line == 0) op_space else Space.Newline;
428 // };
429
430 // {
431 // ais.pushIndent();
432 // defer ais.popIndent();
433 // try renderToken(ais, tree, infix_op_node.op_token, after_op_space);
434 // }
435 // ais.pushIndentOneShot();
436 // return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
437 //},
438
439 //.BitNot,
440 //.BoolNot,
441 //.Negation,
442 //.NegationWrap,
443 //.OptionalType,
444 //.AddressOf,
445 //=> {
446 // const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
447 // try renderToken(ais, tree, casted_node.op_token, Space.None);
448 // return renderExpression(allocator, ais, tree, casted_node.rhs, space);
449 //},
450
451 //.Try,
452 //.Resume,
453 //.Await,
454 //=> {
455 // const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
456 // try renderToken(ais, tree, casted_node.op_token, Space.Space);
457 // return renderExpression(allocator, ais, tree, casted_node.rhs, space);
458 //},
459
460 //.ArrayType => {
461 // const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base);
462 // return renderArrayType(
463 // allocator,
464 // ais,
465 // tree,
466 // array_type.op_token,
467 // array_type.rhs,
468 // array_type.len_expr,
469 // null,
470 // space,
471 // );
472 //},
473 //.ArrayTypeSentinel => {
474 // const array_type = @fieldParentPtr(ast.Node.ArrayTypeSentinel, "base", base);
475 // return renderArrayType(
476 // allocator,
477 // ais,
478 // tree,
479 // array_type.op_token,
480 // array_type.rhs,
481 // array_type.len_expr,
482 // array_type.sentinel,
483 // space,
484 // );
485 //},
486
487 //.PtrType => {
488 // const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
489 // const op_tok_id = tree.token_tags[ptr_type.op_token];
490 // switch (op_tok_id) {
491 // .Asterisk, .AsteriskAsterisk => try ais.writer().writeByte('*'),
492 // .LBracket => if (tree.token_tags[ptr_type.op_token + 2] == .Identifier)
493 // try ais.writer().writeAll("[*c")
494 // else
495 // try ais.writer().writeAll("[*"),
496 // else => unreachable,
497 // }
498 // if (ptr_type.ptr_info.sentinel) |sentinel| {
499 // const colon_token = tree.prevToken(sentinel.firstToken());
500 // try renderToken(ais, tree, colon_token, Space.None); // :
501 // const sentinel_space = switch (op_tok_id) {
502 // .LBracket => Space.None,
503 // else => Space.Space,
504 // };
505 // try renderExpression(allocator, ais, tree, sentinel, sentinel_space);
506 // }
507 // switch (op_tok_id) {
508 // .Asterisk, .AsteriskAsterisk => {},
509 // .LBracket => try ais.writer().writeByte(']'),
510 // else => unreachable,
511 // }
512 // if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {
513 // try renderToken(ais, tree, allowzero_token, Space.Space); // allowzero
514 // }
515 // if (ptr_type.ptr_info.align_info) |align_info| {
516 // const lparen_token = tree.prevToken(align_info.node.firstToken());
517 // const align_token = tree.prevToken(lparen_token);
518
519 // try renderToken(ais, tree, align_token, Space.None); // align
520 // try renderToken(ais, tree, lparen_token, Space.None); // (
521
522 // try renderExpression(allocator, ais, tree, align_info.node, Space.None);
523
524 // if (align_info.bit_range) |bit_range| {
525 // const colon1 = tree.prevToken(bit_range.start.firstToken());
526 // const colon2 = tree.prevToken(bit_range.end.firstToken());
527
528 // try renderToken(ais, tree, colon1, Space.None); // :
529 // try renderExpression(allocator, ais, tree, bit_range.start, Space.None);
530 // try renderToken(ais, tree, colon2, Space.None); // :
531 // try renderExpression(allocator, ais, tree, bit_range.end, Space.None);
532
533 // const rparen_token = tree.nextToken(bit_range.end.lastToken());
534 // try renderToken(ais, tree, rparen_token, Space.Space); // )
535 // } else {
536 // const rparen_token = tree.nextToken(align_info.node.lastToken());
537 // try renderToken(ais, tree, rparen_token, Space.Space); // )
538 // }
539 // }
540 // if (ptr_type.ptr_info.const_token) |const_token| {
541 // try renderToken(ais, tree, const_token, Space.Space); // const
542 // }
543 // if (ptr_type.ptr_info.volatile_token) |volatile_token| {
544 // try renderToken(ais, tree, volatile_token, Space.Space); // volatile
545 // }
546 // return renderExpression(allocator, ais, tree, ptr_type.rhs, space);
547 //},
548
549 //.SliceType => {
550 // const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
551 // try renderToken(ais, tree, slice_type.op_token, Space.None); // [
552 // if (slice_type.ptr_info.sentinel) |sentinel| {
553 // const colon_token = tree.prevToken(sentinel.firstToken());
554 // try renderToken(ais, tree, colon_token, Space.None); // :
555 // try renderExpression(allocator, ais, tree, sentinel, Space.None);
556 // try renderToken(ais, tree, tree.nextToken(sentinel.lastToken()), Space.None); // ]
557 // } else {
558 // try renderToken(ais, tree, tree.nextToken(slice_type.op_token), Space.None); // ]
559 // }
560
561 // if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
562 // try renderToken(ais, tree, allowzero_token, Space.Space); // allowzero
563 // }
564 // if (slice_type.ptr_info.align_info) |align_info| {
565 // const lparen_token = tree.prevToken(align_info.node.firstToken());
566 // const align_token = tree.prevToken(lparen_token);
567
568 // try renderToken(ais, tree, align_token, Space.None); // align
569 // try renderToken(ais, tree, lparen_token, Space.None); // (
570
571 // try renderExpression(allocator, ais, tree, align_info.node, Space.None);
572
573 // if (align_info.bit_range) |bit_range| {
574 // const colon1 = tree.prevToken(bit_range.start.firstToken());
575 // const colon2 = tree.prevToken(bit_range.end.firstToken());
576
577 // try renderToken(ais, tree, colon1, Space.None); // :
578 // try renderExpression(allocator, ais, tree, bit_range.start, Space.None);
579 // try renderToken(ais, tree, colon2, Space.None); // :
580 // try renderExpression(allocator, ais, tree, bit_range.end, Space.None);
581
582 // const rparen_token = tree.nextToken(bit_range.end.lastToken());
583 // try renderToken(ais, tree, rparen_token, Space.Space); // )
584 // } else {
585 // const rparen_token = tree.nextToken(align_info.node.lastToken());
586 // try renderToken(ais, tree, rparen_token, Space.Space); // )
587 // }
588 // }
589 // if (slice_type.ptr_info.const_token) |const_token| {
590 // try renderToken(ais, tree, const_token, Space.Space);
591 // }
592 // if (slice_type.ptr_info.volatile_token) |volatile_token| {
593 // try renderToken(ais, tree, volatile_token, Space.Space);
594 // }
595 // return renderExpression(allocator, ais, tree, slice_type.rhs, space);
596 //},
597
598 //.ArrayInitializer, .ArrayInitializerDot => {
599 // var rtoken: ast.TokenIndex = undefined;
600 // var exprs: []ast.Node.Index = undefined;
601 // const lhs: union(enum) { dot: ast.TokenIndex, node: ast.Node.Index } = switch (base.tag) {
602 // .ArrayInitializerDot => blk: {
603 // const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);
604 // rtoken = casted.rtoken;
605 // exprs = casted.list();
606 // break :blk .{ .dot = casted.dot };
607 // },
608 // .ArrayInitializer => blk: {
609 // const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base);
610 // rtoken = casted.rtoken;
611 // exprs = casted.list();
612 // break :blk .{ .node = casted.lhs };
613 // },
614 // else => unreachable,
615 // };
616
617 // const lbrace = switch (lhs) {
618 // .dot => |dot| tree.nextToken(dot),
619 // .node => |node| tree.nextToken(node.lastToken()),
620 // };
621
622 // switch (lhs) {
623 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
624 // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
625 // }
626
627 // if (exprs.len == 0) {
628 // try renderToken(ais, tree, lbrace, Space.None);
629 // return renderToken(ais, tree, rtoken, space);
630 // }
631
632 // if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_tags[exprs[0].*.lastToken() + 1] == .RBrace) {
633 // const expr = exprs[0];
634
635 // try renderToken(ais, tree, lbrace, Space.None);
636 // try renderExpression(allocator, ais, tree, expr, Space.None);
637 // return renderToken(ais, tree, rtoken, space);
638 // }
639
640 // // scan to find row size
641 // if (rowSize(tree, exprs, rtoken) != null) {
642 // {
643 // ais.pushIndentNextLine();
644 // defer ais.popIndent();
645 // try renderToken(ais, tree, lbrace, Space.Newline);
646
647 // var expr_index: usize = 0;
648 // while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| {
649 // const row_exprs = exprs[expr_index..];
650 // // A place to store the width of each expression and its column's maximum
651 // var widths = try allocator.alloc(usize, row_exprs.len + row_size);
652 // defer allocator.free(widths);
653 // mem.set(usize, widths, 0);
654
655 // var expr_newlines = try allocator.alloc(bool, row_exprs.len);
656 // defer allocator.free(expr_newlines);
657 // mem.set(bool, expr_newlines, false);
658
659 // var expr_widths = widths[0 .. widths.len - row_size];
660 // var column_widths = widths[widths.len - row_size ..];
661
662 // // Find next row with trailing comment (if any) to end the current section
663 // var section_end = sec_end: {
664 // var this_line_first_expr: usize = 0;
665 // var this_line_size = rowSize(tree, row_exprs, rtoken);
666 // for (row_exprs) |expr, i| {
667 // // Ignore comment on first line of this section
668 // if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue;
669 // // Track start of line containing comment
670 // if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) {
671 // this_line_first_expr = i;
672 // this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken);
673 // }
674
675 // const maybe_comma = expr.lastToken() + 1;
676 // const maybe_comment = expr.lastToken() + 2;
677 // if (maybe_comment < tree.token_tags.len) {
678 // if (tree.token_tags[maybe_comma] == .Comma and
679 // tree.token_tags[maybe_comment] == .LineComment and
680 // tree.tokensOnSameLine(expr.lastToken(), maybe_comment))
681 // {
682 // var comment_token_loc = tree.token_locs[maybe_comment];
683 // const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
684 // if (!comment_is_empty) {
685 // // Found row ending in comment
686 // break :sec_end i - this_line_size.? + 1;
687 // }
688 // }
689 // }
690 // }
691 // break :sec_end row_exprs.len;
692 // };
693 // expr_index += section_end;
694
695 // const section_exprs = row_exprs[0..section_end];
696
697 // // Null stream for counting the printed length of each expression
698 // var line_find_stream = std.io.findByteWriter('\n', std.io.null_writer);
699 // var counting_stream = std.io.countingWriter(line_find_stream.writer());
700 // var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
701
702 // // Calculate size of columns in current section
703 // var column_counter: usize = 0;
704 // var single_line = true;
705 // for (section_exprs) |expr, i| {
706 // if (i + 1 < section_exprs.len) {
707 // counting_stream.bytes_written = 0;
708 // line_find_stream.byte_found = false;
709 // try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
710 // const width = @intCast(usize, counting_stream.bytes_written);
711 // expr_widths[i] = width;
712 // expr_newlines[i] = line_find_stream.byte_found;
713
714 // if (!line_find_stream.byte_found) {
715 // const column = column_counter % row_size;
716 // column_widths[column] = std.math.max(column_widths[column], width);
717
718 // const expr_last_token = expr.*.lastToken() + 1;
719 // const next_expr = section_exprs[i + 1];
720 // const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
721
722 // column_counter += 1;
723
724 // if (loc.line != 0) single_line = false;
725 // } else {
726 // single_line = false;
727 // column_counter = 0;
728 // }
729 // } else {
730 // counting_stream.bytes_written = 0;
731 // try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
732 // const width = @intCast(usize, counting_stream.bytes_written);
733 // expr_widths[i] = width;
734 // expr_newlines[i] = line_find_stream.byte_found;
735
736 // if (!line_find_stream.byte_found) {
737 // const column = column_counter % row_size;
738 // column_widths[column] = std.math.max(column_widths[column], width);
739 // }
740 // break;
741 // }
742 // }
743
744 // // Render exprs in current section
745 // column_counter = 0;
746 // var last_col_index: usize = row_size - 1;
747 // for (section_exprs) |expr, i| {
748 // if (i + 1 < section_exprs.len) {
749 // const next_expr = section_exprs[i + 1];
750 // try renderExpression(allocator, ais, tree, expr, Space.None);
751
752 // const comma = tree.nextToken(expr.*.lastToken());
753
754 // if (column_counter != last_col_index) {
755 // if (!expr_newlines[i] and !expr_newlines[i + 1]) {
756 // // Neither the current or next expression is multiline
757 // try renderToken(ais, tree, comma, Space.Space); // ,
758 // assert(column_widths[column_counter % row_size] >= expr_widths[i]);
759 // const padding = column_widths[column_counter % row_size] - expr_widths[i];
760 // try ais.writer().writeByteNTimes(' ', padding);
761
762 // column_counter += 1;
763 // continue;
764 // }
765 // }
766 // if (single_line and row_size != 1) {
767 // try renderToken(ais, tree, comma, Space.Space); // ,
768 // continue;
769 // }
770
771 // column_counter = 0;
772 // try renderToken(ais, tree, comma, Space.Newline); // ,
773 // try renderExtraNewline(tree, ais, next_expr);
774 // } else {
775 // const maybe_comma = tree.nextToken(expr.*.lastToken());
776 // if (tree.token_tags[maybe_comma] == .Comma) {
777 // try renderExpression(allocator, ais, tree, expr, Space.None); // ,
778 // try renderToken(ais, tree, maybe_comma, Space.Newline); // ,
779 // } else {
780 // try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
781 // }
782 // }
783 // }
784
785 // if (expr_index == exprs.len) {
786 // break;
787 // }
788 // }
789 // }
790
791 // return renderToken(ais, tree, rtoken, space);
792 // }
793
794 // // Single line
795 // try renderToken(ais, tree, lbrace, Space.Space);
796 // for (exprs) |expr, i| {
797 // if (i + 1 < exprs.len) {
798 // const next_expr = exprs[i + 1];
799 // try renderExpression(allocator, ais, tree, expr, Space.None);
800 // const comma = tree.nextToken(expr.*.lastToken());
801 // try renderToken(ais, tree, comma, Space.Space); // ,
802 // } else {
803 // try renderExpression(allocator, ais, tree, expr, Space.Space);
804 // }
805 // }
806
807 // return renderToken(ais, tree, rtoken, space);
808 //},
809
810 //.StructInitializer, .StructInitializerDot => {
811 // var rtoken: ast.TokenIndex = undefined;
812 // var field_inits: []ast.Node.Index = undefined;
813 // const lhs: union(enum) { dot: ast.TokenIndex, node: ast.Node.Index } = switch (base.tag) {
814 // .StructInitializerDot => blk: {
815 // const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);
816 // rtoken = casted.rtoken;
817 // field_inits = casted.list();
818 // break :blk .{ .dot = casted.dot };
819 // },
820 // .StructInitializer => blk: {
821 // const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base);
822 // rtoken = casted.rtoken;
823 // field_inits = casted.list();
824 // break :blk .{ .node = casted.lhs };
825 // },
826 // else => unreachable,
827 // };
828
829 // const lbrace = switch (lhs) {
830 // .dot => |dot| tree.nextToken(dot),
831 // .node => |node| tree.nextToken(node.lastToken()),
832 // };
833
834 // if (field_inits.len == 0) {
835 // switch (lhs) {
836 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
837 // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
838 // }
839
840 // {
841 // ais.pushIndentNextLine();
842 // defer ais.popIndent();
843 // try renderToken(ais, tree, lbrace, Space.None);
844 // }
845
846 // return renderToken(ais, tree, rtoken, space);
847 // }
848
849 // const src_has_trailing_comma = blk: {
850 // const maybe_comma = tree.prevToken(rtoken);
851 // break :blk tree.token_tags[maybe_comma] == .Comma;
852 // };
853
854 // const src_same_line = blk: {
855 // const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken);
856 // break :blk loc.line == 0;
857 // };
858
859 // const expr_outputs_one_line = blk: {
860 // // render field expressions until a LF is found
861 // for (field_inits) |field_init| {
862 // var find_stream = std.io.findByteWriter('\n', std.io.null_writer);
863 // var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, find_stream.writer());
864
865 // try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None);
866 // if (find_stream.byte_found) break :blk false;
867 // }
868 // break :blk true;
869 // };
870
871 // if (field_inits.len == 1) blk: {
872 // if (field_inits[0].cast(ast.Node.FieldInitializer)) |field_init| {
873 // switch (field_init.expr.tag) {
874 // .StructInitializer,
875 // .StructInitializerDot,
876 // => break :blk,
877 // else => {},
878 // }
879 // }
880
881 // // if the expression outputs to multiline, make this struct multiline
882 // if (!expr_outputs_one_line or src_has_trailing_comma) {
883 // break :blk;
884 // }
885
886 // switch (lhs) {
887 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
888 // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
889 // }
890 // try renderToken(ais, tree, lbrace, Space.Space);
891 // try renderExpression(allocator, ais, tree, field_inits[0], Space.Space);
892 // return renderToken(ais, tree, rtoken, space);
893 // }
894
895 // if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
896 // // render all on one line, no trailing comma
897 // switch (lhs) {
898 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
899 // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
900 // }
901 // try renderToken(ais, tree, lbrace, Space.Space);
902
903 // for (field_inits) |field_init, i| {
904 // if (i + 1 < field_inits.len) {
905 // try renderExpression(allocator, ais, tree, field_init, Space.None);
906
907 // const comma = tree.nextToken(field_init.lastToken());
908 // try renderToken(ais, tree, comma, Space.Space);
909 // } else {
910 // try renderExpression(allocator, ais, tree, field_init, Space.Space);
911 // }
912 // }
913
914 // return renderToken(ais, tree, rtoken, space);
915 // }
916
917 // {
918 // switch (lhs) {
919 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
920 // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
921 // }
922
923 // ais.pushIndentNextLine();
924 // defer ais.popIndent();
925
926 // try renderToken(ais, tree, lbrace, Space.Newline);
927
928 // for (field_inits) |field_init, i| {
929 // if (i + 1 < field_inits.len) {
930 // const next_field_init = field_inits[i + 1];
931 // try renderExpression(allocator, ais, tree, field_init, Space.None);
932
933 // const comma = tree.nextToken(field_init.lastToken());
934 // try renderToken(ais, tree, comma, Space.Newline);
935
936 // try renderExtraNewline(tree, ais, next_field_init);
937 // } else {
938 // try renderExpression(allocator, ais, tree, field_init, Space.Comma);
939 // }
940 // }
941 // }
942
943 // return renderToken(ais, tree, rtoken, space);
944 //},
945
946 //.Call => {
947 // const call = @fieldParentPtr(ast.Node.Call, "base", base);
948 // if (call.async_token) |async_token| {
949 // try renderToken(ais, tree, async_token, Space.Space);
950 // }
951
952 // try renderExpression(allocator, ais, tree, call.lhs, Space.None);
953
954 // const lparen = tree.nextToken(call.lhs.lastToken());
955
956 // if (call.params_len == 0) {
957 // try renderToken(ais, tree, lparen, Space.None);
958 // return renderToken(ais, tree, call.rtoken, space);
959 // }
960
961 // const src_has_trailing_comma = blk: {
962 // const maybe_comma = tree.prevToken(call.rtoken);
963 // break :blk tree.token_tags[maybe_comma] == .Comma;
964 // };
965
966 // if (src_has_trailing_comma) {
967 // {
968 // ais.pushIndent();
969 // defer ais.popIndent();
970
971 // try renderToken(ais, tree, lparen, Space.Newline); // (
972 // const params = call.params();
973 // for (params) |param_node, i| {
974 // if (i + 1 < params.len) {
975 // const next_node = params[i + 1];
976 // try renderExpression(allocator, ais, tree, param_node, Space.None);
977
978 // // Unindent the comma for multiline string literals
979 // const maybe_multiline_string = param_node.firstToken();
980 // const is_multiline_string = tree.token_tags[maybe_multiline_string] == .MultilineStringLiteralLine;
981 // if (is_multiline_string) ais.popIndent();
982 // defer if (is_multiline_string) ais.pushIndent();
983
984 // const comma = tree.nextToken(param_node.lastToken());
985 // try renderToken(ais, tree, comma, Space.Newline); // ,
986 // try renderExtraNewline(tree, ais, next_node);
987 // } else {
988 // try renderExpression(allocator, ais, tree, param_node, Space.Comma);
989 // }
990 // }
991 // }
992 // return renderToken(ais, tree, call.rtoken, space);
993 // }
994
995 // try renderToken(ais, tree, lparen, Space.None); // (
996
997 // const params = call.params();
998 // for (params) |param_node, i| {
999 // const maybe_comment = param_node.firstToken() - 1;
1000 // const maybe_multiline_string = param_node.firstToken();
1001 // if (tree.token_tags[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_tags[maybe_comment] == .LineComment) {
1002 // ais.pushIndentOneShot();
1003 // }
1004
1005 // try renderExpression(allocator, ais, tree, param_node, Space.None);
1006
1007 // if (i + 1 < params.len) {
1008 // const comma = tree.nextToken(param_node.lastToken());
1009 // try renderToken(ais, tree, comma, Space.Space);
1010 // }
1011 // }
1012 // return renderToken(ais, tree, call.rtoken, space); // )
1013 //},
1014
1015 //.ArrayAccess => {
1016 // const suffix_op = base.castTag(.ArrayAccess).?;
1017
1018 // const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
1019 // const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());
1020
1021 // try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None);
1022 // try renderToken(ais, tree, lbracket, Space.None); // [
1023
1024 // const starts_with_comment = tree.token_tags[lbracket + 1] == .LineComment;
1025 // const ends_with_comment = tree.token_tags[rbracket - 1] == .LineComment;
1026 // {
1027 // const new_space = if (ends_with_comment) Space.Newline else Space.None;
1028
1029 // ais.pushIndent();
1030 // defer ais.popIndent();
1031 // try renderExpression(allocator, ais, tree, suffix_op.index_expr, new_space);
1032 // }
1033 // if (starts_with_comment) try ais.maybeInsertNewline();
1034 // return renderToken(ais, tree, rbracket, space); // ]
1035 //},
1036
1037 //.Slice => {
1038 // const suffix_op = base.castTag(.Slice).?;
1039 // try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None);
1040
1041 // const lbracket = tree.prevToken(suffix_op.start.firstToken());
1042 // const dotdot = tree.nextToken(suffix_op.start.lastToken());
1043
1044 // const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or
1045 // (if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false);
1046 // const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
1047 // const after_op_space = if (suffix_op.end != null) after_start_space else Space.None;
1048
1049 // try renderToken(ais, tree, lbracket, Space.None); // [
1050 // try renderExpression(allocator, ais, tree, suffix_op.start, after_start_space);
1051 // try renderToken(ais, tree, dotdot, after_op_space); // ..
1052 // if (suffix_op.end) |end| {
1053 // const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;
1054 // try renderExpression(allocator, ais, tree, end, after_end_space);
1055 // }
1056 // if (suffix_op.sentinel) |sentinel| {
1057 // const colon = tree.prevToken(sentinel.firstToken());
1058 // try renderToken(ais, tree, colon, Space.None); // :
1059 // try renderExpression(allocator, ais, tree, sentinel, Space.None);
1060 // }
1061 // return renderToken(ais, tree, suffix_op.rtoken, space); // ]
1062 //},
1063
1064 //.Deref => {
1065 // const suffix_op = base.castTag(.Deref).?;
1066
1067 // try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None);
1068 // return renderToken(ais, tree, suffix_op.rtoken, space); // .*
1069 //},
1070 //.UnwrapOptional => {
1071 // const suffix_op = base.castTag(.UnwrapOptional).?;
1072
1073 // try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None);
1074 // try renderToken(ais, tree, tree.prevToken(suffix_op.rtoken), Space.None); // .
1075 // return renderToken(ais, tree, suffix_op.rtoken, space); // ?
1076 //},
1077
1078 //.Break => {
1079 // const flow_expr = base.castTag(.Break).?;
1080 // const maybe_rhs = flow_expr.getRHS();
1081 // const maybe_label = flow_expr.getLabel();
1082
1083 // if (maybe_label == null and maybe_rhs == null) {
1084 // return renderToken(ais, tree, flow_expr.ltoken, space); // break
1085 // }
1086
1087 // try renderToken(ais, tree, flow_expr.ltoken, Space.Space); // break
1088 // if (maybe_label) |label| {
1089 // const colon = tree.nextToken(flow_expr.ltoken);
1090 // try renderToken(ais, tree, colon, Space.None); // :
1091
1092 // if (maybe_rhs == null) {
1093 // return renderToken(ais, tree, label, space); // label
1094 // }
1095 // try renderToken(ais, tree, label, Space.Space); // label
1096 // }
1097 // return renderExpression(allocator, ais, tree, maybe_rhs.?, space);
1098 //},
1099
1100 //.Continue => {
1101 // const flow_expr = base.castTag(.Continue).?;
1102 // if (flow_expr.getLabel()) |label| {
1103 // try renderToken(ais, tree, flow_expr.ltoken, Space.Space); // continue
1104 // const colon = tree.nextToken(flow_expr.ltoken);
1105 // try renderToken(ais, tree, colon, Space.None); // :
1106 // return renderToken(ais, tree, label, space); // label
1107 // } else {
1108 // return renderToken(ais, tree, flow_expr.ltoken, space); // continue
1109 // }
1110 //},
1111
1112 //.Return => {
1113 // const flow_expr = base.castTag(.Return).?;
1114 // if (flow_expr.getRHS()) |rhs| {
1115 // try renderToken(ais, tree, flow_expr.ltoken, Space.Space);
1116 // return renderExpression(allocator, ais, tree, rhs, space);
1117 // } else {
1118 // return renderToken(ais, tree, flow_expr.ltoken, space);
1119 // }
1120 //},
1121
1122 //.Payload => {
1123 // const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
1124
1125 // try renderToken(ais, tree, payload.lpipe, Space.None);
1126 // try renderExpression(allocator, ais, tree, payload.error_symbol, Space.None);
1127 // return renderToken(ais, tree, payload.rpipe, space);
1128 //},
1129
1130 //.PointerPayload => {
1131 // const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
1132
1133 // try renderToken(ais, tree, payload.lpipe, Space.None);
1134 // if (payload.ptr_token) |ptr_token| {
1135 // try renderToken(ais, tree, ptr_token, Space.None);
1136 // }
1137 // try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None);
1138 // return renderToken(ais, tree, payload.rpipe, space);
1139 //},
1140
1141 //.PointerIndexPayload => {
1142 // const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
1143
1144 // try renderToken(ais, tree, payload.lpipe, Space.None);
1145 // if (payload.ptr_token) |ptr_token| {
1146 // try renderToken(ais, tree, ptr_token, Space.None);
1147 // }
1148 // try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None);
1149
1150 // if (payload.index_symbol) |index_symbol| {
1151 // const comma = tree.nextToken(payload.value_symbol.lastToken());
1152
1153 // try renderToken(ais, tree, comma, Space.Space);
1154 // try renderExpression(allocator, ais, tree, index_symbol, Space.None);
1155 // }
1156
1157 // return renderToken(ais, tree, payload.rpipe, space);
1158 //},
1159
1160 //.GroupedExpression => {
1161 // const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
1162
1163 // try renderToken(ais, tree, grouped_expr.lparen, Space.None);
1164 // {
1165 // ais.pushIndentOneShot();
1166 // try renderExpression(allocator, ais, tree, grouped_expr.expr, Space.None);
1167 // }
1168 // return renderToken(ais, tree, grouped_expr.rparen, space);
1169 //},
1170
1171 //.FieldInitializer => {
1172 // const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
1173
1174 // try renderToken(ais, tree, field_init.period_token, Space.None); // .
1175 // try renderToken(ais, tree, field_init.name_token, Space.Space); // name
1176 // try renderToken(ais, tree, tree.nextToken(field_init.name_token), Space.Space); // =
1177 // return renderExpression(allocator, ais, tree, field_init.expr, space);
1178 //},
1179
1180 //.ContainerDecl => {
1181 // const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
1182
1183 // if (container_decl.layout_token) |layout_token| {
1184 // try renderToken(ais, tree, layout_token, Space.Space);
1185 // }
1186
1187 // switch (container_decl.init_arg_expr) {
1188 // .None => {
1189 // try renderToken(ais, tree, container_decl.kind_token, Space.Space); // union
1190 // },
1191 // .Enum => |enum_tag_type| {
1192 // try renderToken(ais, tree, container_decl.kind_token, Space.None); // union
1193
1194 // const lparen = tree.nextToken(container_decl.kind_token);
1195 // const enum_token = tree.nextToken(lparen);
1196
1197 // try renderToken(ais, tree, lparen, Space.None); // (
1198 // try renderToken(ais, tree, enum_token, Space.None); // enum
1199
1200 // if (enum_tag_type) |expr| {
1201 // try renderToken(ais, tree, tree.nextToken(enum_token), Space.None); // (
1202 // try renderExpression(allocator, ais, tree, expr, Space.None);
1203
1204 // const rparen = tree.nextToken(expr.lastToken());
1205 // try renderToken(ais, tree, rparen, Space.None); // )
1206 // try renderToken(ais, tree, tree.nextToken(rparen), Space.Space); // )
1207 // } else {
1208 // try renderToken(ais, tree, tree.nextToken(enum_token), Space.Space); // )
1209 // }
1210 // },
1211 // .Type => |type_expr| {
1212 // try renderToken(ais, tree, container_decl.kind_token, Space.None); // union
1213
1214 // const lparen = tree.nextToken(container_decl.kind_token);
1215 // const rparen = tree.nextToken(type_expr.lastToken());
1216
1217 // try renderToken(ais, tree, lparen, Space.None); // (
1218 // try renderExpression(allocator, ais, tree, type_expr, Space.None);
1219 // try renderToken(ais, tree, rparen, Space.Space); // )
1220 // },
1221 // }
1222
1223 // if (container_decl.fields_and_decls_len == 0) {
1224 // {
1225 // ais.pushIndentNextLine();
1226 // defer ais.popIndent();
1227 // try renderToken(ais, tree, container_decl.lbrace_token, Space.None); // {
1228 // }
1229 // return renderToken(ais, tree, container_decl.rbrace_token, space); // }
1230 // }
1231
1232 // const src_has_trailing_comma = blk: {
1233 // var maybe_comma = tree.prevToken(container_decl.lastToken());
1234 // // Doc comments for a field may also appear after the comma, eg.
1235 // // field_name: T, // comment attached to field_name
1236 // if (tree.token_tags[maybe_comma] == .DocComment)
1237 // maybe_comma = tree.prevToken(maybe_comma);
1238 // break :blk tree.token_tags[maybe_comma] == .Comma;
1239 // };
1240
1241 // const fields_and_decls = container_decl.fieldsAndDecls();
1242
1243 // // Check if the first declaration and the { are on the same line
1244 // const src_has_newline = !tree.tokensOnSameLine(
1245 // container_decl.lbrace_token,
1246 // fields_and_decls[0].firstToken(),
1247 // );
1248
1249 // // We can only print all the elements in-line if all the
1250 // // declarations inside are fields
1251 // const src_has_only_fields = blk: {
1252 // for (fields_and_decls) |decl| {
1253 // if (decl.tag != .ContainerField) break :blk false;
1254 // }
1255 // break :blk true;
1256 // };
1257
1258 // if (src_has_trailing_comma or !src_has_only_fields) {
1259 // // One declaration per line
1260 // ais.pushIndentNextLine();
1261 // defer ais.popIndent();
1262 // try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // {
1263
1264 // for (fields_and_decls) |decl, i| {
1265 // try renderContainerDecl(allocator, ais, tree, decl, .Newline);
1266
1267 // if (i + 1 < fields_and_decls.len) {
1268 // try renderExtraNewline(tree, ais, fields_and_decls[i + 1]);
1269 // }
1270 // }
1271 // } else if (src_has_newline) {
1272 // // All the declarations on the same line, but place the items on
1273 // // their own line
1274 // try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // {
1275
1276 // ais.pushIndent();
1277 // defer ais.popIndent();
1278
1279 // for (fields_and_decls) |decl, i| {
1280 // const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space;
1281 // try renderContainerDecl(allocator, ais, tree, decl, space_after_decl);
1282 // }
1283 // } else {
1284 // // All the declarations on the same line
1285 // try renderToken(ais, tree, container_decl.lbrace_token, .Space); // {
1286
1287 // for (fields_and_decls) |decl| {
1288 // try renderContainerDecl(allocator, ais, tree, decl, .Space);
1289 // }
1290 // }
1291
1292 // return renderToken(ais, tree, container_decl.rbrace_token, space); // }
1293 //},
1294
1295 //.ErrorSetDecl => {
1296 // const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
1297
1298 // const lbrace = tree.nextToken(err_set_decl.error_token);
1299
1300 // if (err_set_decl.decls_len == 0) {
1301 // try renderToken(ais, tree, err_set_decl.error_token, Space.None);
1302 // try renderToken(ais, tree, lbrace, Space.None);
1303 // return renderToken(ais, tree, err_set_decl.rbrace_token, space);
1304 // }
1305
1306 // if (err_set_decl.decls_len == 1) blk: {
1307 // const node = err_set_decl.decls()[0];
1308
1309 // // if there are any doc comments or same line comments
1310 // // don't try to put it all on one line
1311 // if (node.cast(ast.Node.ErrorTag)) |tag| {
1312 // if (tag.doc_comments != null) break :blk;
1313 // } else {
1314 // break :blk;
1315 // }
1316
1317 // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error
1318 // try renderToken(ais, tree, lbrace, Space.None); // {
1319 // try renderExpression(allocator, ais, tree, node, Space.None);
1320 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }
1321 // }
1322
1323 // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error
1324
1325 // const src_has_trailing_comma = blk: {
1326 // const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
1327 // break :blk tree.token_tags[maybe_comma] == .Comma;
1328 // };
1329
1330 // if (src_has_trailing_comma) {
1331 // {
1332 // ais.pushIndent();
1333 // defer ais.popIndent();
1334
1335 // try renderToken(ais, tree, lbrace, Space.Newline); // {
1336 // const decls = err_set_decl.decls();
1337 // for (decls) |node, i| {
1338 // if (i + 1 < decls.len) {
1339 // try renderExpression(allocator, ais, tree, node, Space.None);
1340 // try renderToken(ais, tree, tree.nextToken(node.lastToken()), Space.Newline); // ,
1341
1342 // try renderExtraNewline(tree, ais, decls[i + 1]);
1343 // } else {
1344 // try renderExpression(allocator, ais, tree, node, Space.Comma);
1345 // }
1346 // }
1347 // }
1348
1349 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }
1350 // } else {
1351 // try renderToken(ais, tree, lbrace, Space.Space); // {
1352
1353 // const decls = err_set_decl.decls();
1354 // for (decls) |node, i| {
1355 // if (i + 1 < decls.len) {
1356 // try renderExpression(allocator, ais, tree, node, Space.None);
1357
1358 // const comma_token = tree.nextToken(node.lastToken());
1359 // assert(tree.token_tags[comma_token] == .Comma);
1360 // try renderToken(ais, tree, comma_token, Space.Space); // ,
1361 // try renderExtraNewline(tree, ais, decls[i + 1]);
1362 // } else {
1363 // try renderExpression(allocator, ais, tree, node, Space.Space);
1364 // }
1365 // }
1366
1367 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }
1368 // }
1369 //},
1370
1371 //.ErrorTag => {
1372 // const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
1373
1374 // try renderDocComments(tree, ais, tag, tag.doc_comments);
1375 // return renderToken(ais, tree, tag.name_token, space); // name
1376 //},
1377
1378 //.MultilineStringLiteral => {
1379 // const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
1380
1381 // {
1382 // const locked_indents = ais.lockOneShotIndent();
1383 // defer {
1384 // var i: u8 = 0;
1385 // while (i < locked_indents) : (i += 1) ais.popIndent();
1386 // }
1387 // try ais.maybeInsertNewline();
1388
1389 // for (multiline_str_literal.lines()) |t| try renderToken(ais, tree, t, Space.None);
1390 // }
1391 //},
1392
1393 //.BuiltinCall => {
1394 // const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
1395
1396 // // TODO remove after 0.7.0 release
1397 // if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))
1398 // return ais.writer().writeAll("opaque {}");
1399
1400 // // TODO remove after 0.7.0 release
1401 // {
1402 // const params = builtin_call.paramsConst();
1403 // if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and
1404 // params.len == 1)
1405 // {
1406 // if (params[0].castTag(.EnumLiteral)) |enum_literal|
1407 // if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque"))
1408 // return ais.writer().writeAll("opaque {}");
1409 // }
1410 // }
1411
1412 // try renderToken(ais, tree, builtin_call.builtin_token, Space.None); // @name
1413
1414 // const src_params_trailing_comma = blk: {
1415 // if (builtin_call.params_len == 0) break :blk false;
1416 // const last_node = builtin_call.params()[builtin_call.params_len - 1];
1417 // const maybe_comma = tree.nextToken(last_node.lastToken());
1418 // break :blk tree.token_tags[maybe_comma] == .Comma;
1419 // };
1420
1421 // const lparen = tree.nextToken(builtin_call.builtin_token);
1422
1423 // if (!src_params_trailing_comma) {
1424 // try renderToken(ais, tree, lparen, Space.None); // (
1425
1426 // // render all on one line, no trailing comma
1427 // const params = builtin_call.params();
1428 // for (params) |param_node, i| {
1429 // const maybe_comment = param_node.firstToken() - 1;
1430 // if (param_node.*.tag == .MultilineStringLiteral or tree.token_tags[maybe_comment] == .LineComment) {
1431 // ais.pushIndentOneShot();
1432 // }
1433 // try renderExpression(allocator, ais, tree, param_node, Space.None);
1434
1435 // if (i + 1 < params.len) {
1436 // const comma_token = tree.nextToken(param_node.lastToken());
1437 // try renderToken(ais, tree, comma_token, Space.Space); // ,
1438 // }
1439 // }
1440 // } else {
1441 // // one param per line
1442 // ais.pushIndent();
1443 // defer ais.popIndent();
1444 // try renderToken(ais, tree, lparen, Space.Newline); // (
1445
1446 // for (builtin_call.params()) |param_node| {
1447 // try renderExpression(allocator, ais, tree, param_node, Space.Comma);
1448 // }
1449 // }
1450
1451 // return renderToken(ais, tree, builtin_call.rparen_token, space); // )
1452 //},
1453
1454 //.FnProto => {
1455 // const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
1456
1457 // if (fn_proto.getVisibToken()) |visib_token_index| {
1458 // const visib_token = tree.token_tags[visib_token_index];
1459 // assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
1460
1461 // try renderToken(ais, tree, visib_token_index, Space.Space); // pub
1462 // }
1463
1464 // if (fn_proto.getExternExportInlineToken()) |extern_export_inline_token| {
1465 // if (fn_proto.getIsExternPrototype() == null)
1466 // try renderToken(ais, tree, extern_export_inline_token, Space.Space); // extern/export/inline
1467 // }
1468
1469 // if (fn_proto.getLibName()) |lib_name| {
1470 // try renderExpression(allocator, ais, tree, lib_name, Space.Space);
1471 // }
1472
1473 // const lparen = if (fn_proto.getNameToken()) |name_token| blk: {
1474 // try renderToken(ais, tree, fn_proto.fn_token, Space.Space); // fn
1475 // try renderToken(ais, tree, name_token, Space.None); // name
1476 // break :blk tree.nextToken(name_token);
1477 // } else blk: {
1478 // try renderToken(ais, tree, fn_proto.fn_token, Space.Space); // fn
1479 // break :blk tree.nextToken(fn_proto.fn_token);
1480 // };
1481 // assert(tree.token_tags[lparen] == .LParen);
1482
1483 // const rparen = tree.prevToken(
1484 // // the first token for the annotation expressions is the left
1485 // // parenthesis, hence the need for two prevToken
1486 // if (fn_proto.getAlignExpr()) |align_expr|
1487 // tree.prevToken(tree.prevToken(align_expr.firstToken()))
1488 // else if (fn_proto.getSectionExpr()) |section_expr|
1489 // tree.prevToken(tree.prevToken(section_expr.firstToken()))
1490 // else if (fn_proto.getCallconvExpr()) |callconv_expr|
1491 // tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
1492 // else switch (fn_proto.return_type) {
1493 // .Explicit => |node| node.firstToken(),
1494 // .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1495 // .Invalid => unreachable,
1496 // },
1497 // );
1498 // assert(tree.token_tags[rparen] == .RParen);
1499
1500 // const src_params_trailing_comma = blk: {
1501 // const maybe_comma = tree.token_tags[rparen - 1];
1502 // break :blk maybe_comma == .Comma or maybe_comma == .LineComment;
1503 // };
1504
1505 // if (!src_params_trailing_comma) {
1506 // try renderToken(ais, tree, lparen, Space.None); // (
1507
1508 // // render all on one line, no trailing comma
1509 // for (fn_proto.params()) |param_decl, i| {
1510 // try renderParamDecl(allocator, ais, tree, param_decl, Space.None);
1511
1512 // if (i + 1 < fn_proto.params_len or fn_proto.getVarArgsToken() != null) {
1513 // const comma = tree.nextToken(param_decl.lastToken());
1514 // try renderToken(ais, tree, comma, Space.Space); // ,
1515 // }
1516 // }
1517 // if (fn_proto.getVarArgsToken()) |var_args_token| {
1518 // try renderToken(ais, tree, var_args_token, Space.None);
1519 // }
1520 // } else {
1521 // // one param per line
1522 // ais.pushIndent();
1523 // defer ais.popIndent();
1524 // try renderToken(ais, tree, lparen, Space.Newline); // (
1525
1526 // for (fn_proto.params()) |param_decl| {
1527 // try renderParamDecl(allocator, ais, tree, param_decl, Space.Comma);
1528 // }
1529 // if (fn_proto.getVarArgsToken()) |var_args_token| {
1530 // try renderToken(ais, tree, var_args_token, Space.Comma);
1531 // }
1532 // }
1533
1534 // try renderToken(ais, tree, rparen, Space.Space); // )
1535
1536 // if (fn_proto.getAlignExpr()) |align_expr| {
1537 // const align_rparen = tree.nextToken(align_expr.lastToken());
1538 // const align_lparen = tree.prevToken(align_expr.firstToken());
1539 // const align_kw = tree.prevToken(align_lparen);
1540
1541 // try renderToken(ais, tree, align_kw, Space.None); // align
1542 // try renderToken(ais, tree, align_lparen, Space.None); // (
1543 // try renderExpression(allocator, ais, tree, align_expr, Space.None);
1544 // try renderToken(ais, tree, align_rparen, Space.Space); // )
1545 // }
1546
1547 // if (fn_proto.getSectionExpr()) |section_expr| {
1548 // const section_rparen = tree.nextToken(section_expr.lastToken());
1549 // const section_lparen = tree.prevToken(section_expr.firstToken());
1550 // const section_kw = tree.prevToken(section_lparen);
1551
1552 // try renderToken(ais, tree, section_kw, Space.None); // section
1553 // try renderToken(ais, tree, section_lparen, Space.None); // (
1554 // try renderExpression(allocator, ais, tree, section_expr, Space.None);
1555 // try renderToken(ais, tree, section_rparen, Space.Space); // )
1556 // }
1557
1558 // if (fn_proto.getCallconvExpr()) |callconv_expr| {
1559 // const callconv_rparen = tree.nextToken(callconv_expr.lastToken());
1560 // const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
1561 // const callconv_kw = tree.prevToken(callconv_lparen);
1562
1563 // try renderToken(ais, tree, callconv_kw, Space.None); // callconv
1564 // try renderToken(ais, tree, callconv_lparen, Space.None); // (
1565 // try renderExpression(allocator, ais, tree, callconv_expr, Space.None);
1566 // try renderToken(ais, tree, callconv_rparen, Space.Space); // )
1567 // } else if (fn_proto.getIsExternPrototype() != null) {
1568 // try ais.writer().writeAll("callconv(.C) ");
1569 // } else if (fn_proto.getIsAsync() != null) {
1570 // try ais.writer().writeAll("callconv(.Async) ");
1571 // }
1572
1573 // switch (fn_proto.return_type) {
1574 // .Explicit => |node| {
1575 // return renderExpression(allocator, ais, tree, node, space);
1576 // },
1577 // .InferErrorSet => |node| {
1578 // try renderToken(ais, tree, tree.prevToken(node.firstToken()), Space.None); // !
1579 // return renderExpression(allocator, ais, tree, node, space);
1580 // },
1581 // .Invalid => unreachable,
1582 // }
1583 //},
1584
1585 //.AnyFrameType => {
1586 // const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
1587
1588 // if (anyframe_type.result) |result| {
1589 // try renderToken(ais, tree, anyframe_type.anyframe_token, Space.None); // anyframe
1590 // try renderToken(ais, tree, result.arrow_token, Space.None); // ->
1591 // return renderExpression(allocator, ais, tree, result.return_type, space);
1592 // } else {
1593 // return renderToken(ais, tree, anyframe_type.anyframe_token, space); // anyframe
1594 // }
1595 //},
1596
1597 //.DocComment => unreachable, // doc comments are attached to nodes
1598
1599 //.Switch => {
1600 // const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
1601
1602 // try renderToken(ais, tree, switch_node.switch_token, Space.Space); // switch
1603 // try renderToken(ais, tree, tree.nextToken(switch_node.switch_token), Space.None); // (
1604
1605 // const rparen = tree.nextToken(switch_node.expr.lastToken());
1606 // const lbrace = tree.nextToken(rparen);
1607
1608 // if (switch_node.cases_len == 0) {
1609 // try renderExpression(allocator, ais, tree, switch_node.expr, Space.None);
1610 // try renderToken(ais, tree, rparen, Space.Space); // )
1611 // try renderToken(ais, tree, lbrace, Space.None); // {
1612 // return renderToken(ais, tree, switch_node.rbrace, space); // }
1613 // }
1614
1615 // try renderExpression(allocator, ais, tree, switch_node.expr, Space.None);
1616 // try renderToken(ais, tree, rparen, Space.Space); // )
1617
1618 // {
1619 // ais.pushIndentNextLine();
1620 // defer ais.popIndent();
1621 // try renderToken(ais, tree, lbrace, Space.Newline); // {
1622
1623 // const cases = switch_node.cases();
1624 // for (cases) |node, i| {
1625 // try renderExpression(allocator, ais, tree, node, Space.Comma);
1626
1627 // if (i + 1 < cases.len) {
1628 // try renderExtraNewline(tree, ais, cases[i + 1]);
1629 // }
1630 // }
1631 // }
1632
1633 // return renderToken(ais, tree, switch_node.rbrace, space); // }
1634 //},
1635
1636 //.SwitchCase => {
1637 // const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
1638
1639 // assert(switch_case.items_len != 0);
1640 // const src_has_trailing_comma = blk: {
1641 // const last_node = switch_case.items()[switch_case.items_len - 1];
1642 // const maybe_comma = tree.nextToken(last_node.lastToken());
1643 // break :blk tree.token_tags[maybe_comma] == .Comma;
1644 // };
1645
1646 // if (switch_case.items_len == 1 or !src_has_trailing_comma) {
1647 // const items = switch_case.items();
1648 // for (items) |node, i| {
1649 // if (i + 1 < items.len) {
1650 // try renderExpression(allocator, ais, tree, node, Space.None);
1651
1652 // const comma_token = tree.nextToken(node.lastToken());
1653 // try renderToken(ais, tree, comma_token, Space.Space); // ,
1654 // try renderExtraNewline(tree, ais, items[i + 1]);
1655 // } else {
1656 // try renderExpression(allocator, ais, tree, node, Space.Space);
1657 // }
1658 // }
1659 // } else {
1660 // const items = switch_case.items();
1661 // for (items) |node, i| {
1662 // if (i + 1 < items.len) {
1663 // try renderExpression(allocator, ais, tree, node, Space.None);
1664
1665 // const comma_token = tree.nextToken(node.lastToken());
1666 // try renderToken(ais, tree, comma_token, Space.Newline); // ,
1667 // try renderExtraNewline(tree, ais, items[i + 1]);
1668 // } else {
1669 // try renderExpression(allocator, ais, tree, node, Space.Comma);
1670 // }
1671 // }
1672 // }
1673
1674 // try renderToken(ais, tree, switch_case.arrow_token, Space.Space); // =>
1675
1676 // if (switch_case.payload) |payload| {
1677 // try renderExpression(allocator, ais, tree, payload, Space.Space);
1678 // }
1679
1680 // return renderExpression(allocator, ais, tree, switch_case.expr, space);
1681 //},
1682 //.SwitchElse => {
1683 // const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
1684 // return renderToken(ais, tree, switch_else.token, space);
1685 //},
1686 //.Else => {
1687 // const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
1688
1689 // const body_is_block = nodeIsBlock(else_node.body);
1690 // const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken());
1691
1692 // const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline;
1693 // try renderToken(ais, tree, else_node.else_token, after_else_space);
1694
1695 // if (else_node.payload) |payload| {
1696 // const payload_space = if (same_line) Space.Space else Space.Newline;
1697 // try renderExpression(allocator, ais, tree, payload, payload_space);
1698 // }
1699
1700 // if (same_line) {
1701 // return renderExpression(allocator, ais, tree, else_node.body, space);
1702 // } else {
1703 // ais.pushIndent();
1704 // defer ais.popIndent();
1705 // return renderExpression(allocator, ais, tree, else_node.body, space);
1706 // }
1707 //},
1708
1709 //.While => {
1710 // const while_node = @fieldParentPtr(ast.Node.While, "base", base);
1711
1712 // if (while_node.label) |label| {
1713 // try renderToken(ais, tree, label, Space.None); // label
1714 // try renderToken(ais, tree, tree.nextToken(label), Space.Space); // :
1715 // }
1716
1717 // if (while_node.inline_token) |inline_token| {
1718 // try renderToken(ais, tree, inline_token, Space.Space); // inline
1719 // }
1720
1721 // try renderToken(ais, tree, while_node.while_token, Space.Space); // while
1722 // try renderToken(ais, tree, tree.nextToken(while_node.while_token), Space.None); // (
1723 // try renderExpression(allocator, ais, tree, while_node.condition, Space.None);
1724
1725 // const cond_rparen = tree.nextToken(while_node.condition.lastToken());
1726
1727 // const body_is_block = nodeIsBlock(while_node.body);
1728
1729 // var block_start_space: Space = undefined;
1730 // var after_body_space: Space = undefined;
1731
1732 // if (body_is_block) {
1733 // block_start_space = Space.BlockStart;
1734 // after_body_space = if (while_node.@"else" == null) space else Space.SpaceOrOutdent;
1735 // } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) {
1736 // block_start_space = Space.Space;
1737 // after_body_space = if (while_node.@"else" == null) space else Space.Space;
1738 // } else {
1739 // block_start_space = Space.Newline;
1740 // after_body_space = if (while_node.@"else" == null) space else Space.Newline;
1741 // }
1742
1743 // {
1744 // const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;
1745 // try renderToken(ais, tree, cond_rparen, rparen_space); // )
1746 // }
1747
1748 // if (while_node.payload) |payload| {
1749 // const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
1750 // try renderExpression(allocator, ais, tree, payload, payload_space);
1751 // }
1752
1753 // if (while_node.continue_expr) |continue_expr| {
1754 // const rparen = tree.nextToken(continue_expr.lastToken());
1755 // const lparen = tree.prevToken(continue_expr.firstToken());
1756 // const colon = tree.prevToken(lparen);
1757
1758 // try renderToken(ais, tree, colon, Space.Space); // :
1759 // try renderToken(ais, tree, lparen, Space.None); // (
1760
1761 // try renderExpression(allocator, ais, tree, continue_expr, Space.None);
1762
1763 // try renderToken(ais, tree, rparen, block_start_space); // )
1764 // }
1765
1766 // {
1767 // if (!body_is_block) ais.pushIndent();
1768 // defer if (!body_is_block) ais.popIndent();
1769 // try renderExpression(allocator, ais, tree, while_node.body, after_body_space);
1770 // }
1771
1772 // if (while_node.@"else") |@"else"| {
1773 // return renderExpression(allocator, ais, tree, &@"else".base, space);
1774 // }
1775 //},
1776
1777 //.For => {
1778 // const for_node = @fieldParentPtr(ast.Node.For, "base", base);
1779
1780 // if (for_node.label) |label| {
1781 // try renderToken(ais, tree, label, Space.None); // label
1782 // try renderToken(ais, tree, tree.nextToken(label), Space.Space); // :
1783 // }
1784
1785 // if (for_node.inline_token) |inline_token| {
1786 // try renderToken(ais, tree, inline_token, Space.Space); // inline
1787 // }
1788
1789 // try renderToken(ais, tree, for_node.for_token, Space.Space); // for
1790 // try renderToken(ais, tree, tree.nextToken(for_node.for_token), Space.None); // (
1791 // try renderExpression(allocator, ais, tree, for_node.array_expr, Space.None);
1792
1793 // const rparen = tree.nextToken(for_node.array_expr.lastToken());
1794
1795 // const body_is_block = for_node.body.tag.isBlock();
1796 // const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
1797 // const body_on_same_line = body_is_block or src_one_line_to_body;
1798
1799 // try renderToken(ais, tree, rparen, Space.Space); // )
1800
1801 // const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline;
1802 // try renderExpression(allocator, ais, tree, for_node.payload, space_after_payload); // |x|
1803
1804 // const space_after_body = blk: {
1805 // if (for_node.@"else") |@"else"| {
1806 // const src_one_line_to_else = tree.tokensOnSameLine(rparen, @"else".firstToken());
1807 // if (body_is_block or src_one_line_to_else) {
1808 // break :blk Space.Space;
1809 // } else {
1810 // break :blk Space.Newline;
1811 // }
1812 // } else {
1813 // break :blk space;
1814 // }
1815 // };
1816
1817 // {
1818 // if (!body_on_same_line) ais.pushIndent();
1819 // defer if (!body_on_same_line) ais.popIndent();
1820 // try renderExpression(allocator, ais, tree, for_node.body, space_after_body); // { body }
1821 // }
1822
1823 // if (for_node.@"else") |@"else"| {
1824 // return renderExpression(allocator, ais, tree, &@"else".base, space); // else
1825 // }
1826 //},
1827
1828 //.If => {
1829 // const if_node = @fieldParentPtr(ast.Node.If, "base", base);
1830
1831 // const lparen = tree.nextToken(if_node.if_token);
1832 // const rparen = tree.nextToken(if_node.condition.lastToken());
1833
1834 // try renderToken(ais, tree, if_node.if_token, Space.Space); // if
1835 // try renderToken(ais, tree, lparen, Space.None); // (
1836
1837 // try renderExpression(allocator, ais, tree, if_node.condition, Space.None); // condition
1838
1839 // const body_is_if_block = if_node.body.tag == .If;
1840 // const body_is_block = nodeIsBlock(if_node.body);
1841
1842 // if (body_is_if_block) {
1843 // try renderExtraNewline(tree, ais, if_node.body);
1844 // } else if (body_is_block) {
1845 // const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;
1846 // try renderToken(ais, tree, rparen, after_rparen_space); // )
1847
1848 // if (if_node.payload) |payload| {
1849 // try renderExpression(allocator, ais, tree, payload, Space.BlockStart); // |x|
1850 // }
1851
1852 // if (if_node.@"else") |@"else"| {
1853 // try renderExpression(allocator, ais, tree, if_node.body, Space.SpaceOrOutdent);
1854 // return renderExpression(allocator, ais, tree, &@"else".base, space);
1855 // } else {
1856 // return renderExpression(allocator, ais, tree, if_node.body, space);
1857 // }
1858 // }
1859
1860 // const src_has_newline = !tree.tokensOnSameLine(rparen, if_node.body.lastToken());
1861
1862 // if (src_has_newline) {
1863 // const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
1864
1865 // {
1866 // ais.pushIndent();
1867 // defer ais.popIndent();
1868 // try renderToken(ais, tree, rparen, after_rparen_space); // )
1869 // }
1870
1871 // if (if_node.payload) |payload| {
1872 // try renderExpression(allocator, ais, tree, payload, Space.Newline);
1873 // }
1874
1875 // if (if_node.@"else") |@"else"| {
1876 // const else_is_block = nodeIsBlock(@"else".body);
1877
1878 // {
1879 // ais.pushIndent();
1880 // defer ais.popIndent();
1881 // try renderExpression(allocator, ais, tree, if_node.body, Space.Newline);
1882 // }
1883
1884 // if (else_is_block) {
1885 // try renderToken(ais, tree, @"else".else_token, Space.Space); // else
1886
1887 // if (@"else".payload) |payload| {
1888 // try renderExpression(allocator, ais, tree, payload, Space.Space);
1889 // }
1890
1891 // return renderExpression(allocator, ais, tree, @"else".body, space);
1892 // } else {
1893 // const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space;
1894 // try renderToken(ais, tree, @"else".else_token, after_else_space); // else
1895
1896 // if (@"else".payload) |payload| {
1897 // try renderExpression(allocator, ais, tree, payload, Space.Newline);
1898 // }
1899
1900 // ais.pushIndent();
1901 // defer ais.popIndent();
1902 // return renderExpression(allocator, ais, tree, @"else".body, space);
1903 // }
1904 // } else {
1905 // ais.pushIndent();
1906 // defer ais.popIndent();
1907 // return renderExpression(allocator, ais, tree, if_node.body, space);
1908 // }
1909 // }
1910
1911 // // Single line if statement
1912
1913 // try renderToken(ais, tree, rparen, Space.Space); // )
1914
1915 // if (if_node.payload) |payload| {
1916 // try renderExpression(allocator, ais, tree, payload, Space.Space);
1917 // }
1918
1919 // if (if_node.@"else") |@"else"| {
1920 // try renderExpression(allocator, ais, tree, if_node.body, Space.Space);
1921 // try renderToken(ais, tree, @"else".else_token, Space.Space);
1922
1923 // if (@"else".payload) |payload| {
1924 // try renderExpression(allocator, ais, tree, payload, Space.Space);
1925 // }
1926
1927 // return renderExpression(allocator, ais, tree, @"else".body, space);
1928 // } else {
1929 // return renderExpression(allocator, ais, tree, if_node.body, space);
1930 // }
1931 //},
1932
1933 //.Asm => {
1934 // const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1935
1936 // try renderToken(ais, tree, asm_node.asm_token, Space.Space); // asm
1937
1938 // if (asm_node.volatile_token) |volatile_token| {
1939 // try renderToken(ais, tree, volatile_token, Space.Space); // volatile
1940 // try renderToken(ais, tree, tree.nextToken(volatile_token), Space.None); // (
1941 // } else {
1942 // try renderToken(ais, tree, tree.nextToken(asm_node.asm_token), Space.None); // (
1943 // }
1944
1945 // asmblk: {
1946 // ais.pushIndent();
1947 // defer ais.popIndent();
1948
1949 // if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1950 // try renderExpression(allocator, ais, tree, asm_node.template, Space.None);
1951 // break :asmblk;
1952 // }
1953
1954 // try renderExpression(allocator, ais, tree, asm_node.template, Space.Newline);
1955
1956 // ais.setIndentDelta(asm_indent_delta);
1957 // defer ais.setIndentDelta(indent_delta);
1958
1959 // const colon1 = tree.nextToken(asm_node.template.lastToken());
1960
1961 // const colon2 = if (asm_node.outputs.len == 0) blk: {
1962 // try renderToken(ais, tree, colon1, Space.Newline); // :
1963
1964 // break :blk tree.nextToken(colon1);
1965 // } else blk: {
1966 // try renderToken(ais, tree, colon1, Space.Space); // :
1967
1968 // ais.pushIndent();
1969 // defer ais.popIndent();
1970
1971 // for (asm_node.outputs) |*asm_output, i| {
1972 // if (i + 1 < asm_node.outputs.len) {
1973 // const next_asm_output = asm_node.outputs[i + 1];
1974 // try renderAsmOutput(allocator, ais, tree, asm_output, Space.None);
1975
1976 // const comma = tree.prevToken(next_asm_output.firstToken());
1977 // try renderToken(ais, tree, comma, Space.Newline); // ,
1978 // try renderExtraNewlineToken(tree, ais, next_asm_output.firstToken());
1979 // } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1980 // try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline);
1981 // break :asmblk;
1982 // } else {
1983 // try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline);
1984 // const comma_or_colon = tree.nextToken(asm_output.lastToken());
1985 // break :blk switch (tree.token_tags[comma_or_colon]) {
1986 // .Comma => tree.nextToken(comma_or_colon),
1987 // else => comma_or_colon,
1988 // };
1989 // }
1990 // }
1991 // unreachable;
1992 // };
1993
1994 // const colon3 = if (asm_node.inputs.len == 0) blk: {
1995 // try renderToken(ais, tree, colon2, Space.Newline); // :
1996 // break :blk tree.nextToken(colon2);
1997 // } else blk: {
1998 // try renderToken(ais, tree, colon2, Space.Space); // :
1999 // ais.pushIndent();
2000 // defer ais.popIndent();
2001 // for (asm_node.inputs) |*asm_input, i| {
2002 // if (i + 1 < asm_node.inputs.len) {
2003 // const next_asm_input = &asm_node.inputs[i + 1];
2004 // try renderAsmInput(allocator, ais, tree, asm_input, Space.None);
2005
2006 // const comma = tree.prevToken(next_asm_input.firstToken());
2007 // try renderToken(ais, tree, comma, Space.Newline); // ,
2008 // try renderExtraNewlineToken(tree, ais, next_asm_input.firstToken());
2009 // } else if (asm_node.clobbers.len == 0) {
2010 // try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline);
2011 // break :asmblk;
2012 // } else {
2013 // try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline);
2014 // const comma_or_colon = tree.nextToken(asm_input.lastToken());
2015 // break :blk switch (tree.token_tags[comma_or_colon]) {
2016 // .Comma => tree.nextToken(comma_or_colon),
2017 // else => comma_or_colon,
2018 // };
2019 // }
2020 // }
2021 // unreachable;
2022 // };
2023
2024 // try renderToken(ais, tree, colon3, Space.Space); // :
2025 // ais.pushIndent();
2026 // defer ais.popIndent();
2027 // for (asm_node.clobbers) |clobber_node, i| {
2028 // if (i + 1 >= asm_node.clobbers.len) {
2029 // try renderExpression(allocator, ais, tree, clobber_node, Space.Newline);
2030 // break :asmblk;
2031 // } else {
2032 // try renderExpression(allocator, ais, tree, clobber_node, Space.None);
2033 // const comma = tree.nextToken(clobber_node.lastToken());
2034 // try renderToken(ais, tree, comma, Space.Space); // ,
2035 // }
2036 // }
2037 // }
2038
2039 // return renderToken(ais, tree, asm_node.rparen, space);
2040 //},
2041
2042 //.EnumLiteral => {
2043 // const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
2044
2045 // try renderToken(ais, tree, enum_literal.dot, Space.None); // .
2046 // return renderToken(ais, tree, enum_literal.name, space); // name
2047 //},
2048
2049 //.ContainerField,
2050 //.Root,
2051 //.VarDecl,
2052 //.Use,
2053 //.TestDecl,
2054 //=> unreachable,
2055 else => @panic("TODO implement more renderExpression"),
21512056 }
21522057}
21532058
21542059fn renderArrayType(
21552060 allocator: *mem.Allocator,
2156 ais: anytype,
2157 tree: *ast.Tree,
2061 ais: *Ais,
2062 tree: ast.Tree,
21582063 lbracket: ast.TokenIndex,
2159 rhs: *ast.Node,
2160 len_expr: *ast.Node,
2161 opt_sentinel: ?*ast.Node,
2064 rhs: ast.Node.Index,
2065 len_expr: ast.Node.Index,
2066 opt_sentinel: ?ast.Node.Index,
21622067 space: Space,
2163) (@TypeOf(ais.*).Error || Error)!void {
2068) Error!void {
21642069 const rbracket = tree.nextToken(if (opt_sentinel) |sentinel|
21652070 sentinel.lastToken()
21662071 else
21672072 len_expr.lastToken());
21682073
2169 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
2170 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
2074 const starts_with_comment = tree.token_tags[lbracket + 1] == .LineComment;
2075 const ends_with_comment = tree.token_tags[rbracket - 1] == .LineComment;
21712076 const new_space = if (ends_with_comment) Space.Newline else Space.None;
21722077 {
21732078 const do_indent = (starts_with_comment or ends_with_comment);
21742079 if (do_indent) ais.pushIndent();
21752080 defer if (do_indent) ais.popIndent();
21762081
2177 try renderToken(tree, ais, lbracket, Space.None); // [
2082 try renderToken(ais, tree, lbracket, Space.None); // [
21782083 try renderExpression(allocator, ais, tree, len_expr, new_space);
21792084
21802085 if (starts_with_comment) {
......@@ -2182,25 +2087,25 @@ fn renderArrayType(
21822087 }
21832088 if (opt_sentinel) |sentinel| {
21842089 const colon_token = tree.prevToken(sentinel.firstToken());
2185 try renderToken(tree, ais, colon_token, Space.None); // :
2090 try renderToken(ais, tree, colon_token, Space.None); // :
21862091 try renderExpression(allocator, ais, tree, sentinel, Space.None);
21872092 }
21882093 if (starts_with_comment) {
21892094 try ais.maybeInsertNewline();
21902095 }
21912096 }
2192 try renderToken(tree, ais, rbracket, Space.None); // ]
2097 try renderToken(ais, tree, rbracket, Space.None); // ]
21932098
21942099 return renderExpression(allocator, ais, tree, rhs, space);
21952100}
21962101
21972102fn renderAsmOutput(
21982103 allocator: *mem.Allocator,
2199 ais: anytype,
2200 tree: *ast.Tree,
2104 ais: *Ais,
2105 tree: ast.Tree,
22012106 asm_output: *const ast.Node.Asm.Output,
22022107 space: Space,
2203) (@TypeOf(ais.*).Error || Error)!void {
2108) Error!void {
22042109 try ais.writer().writeAll("[");
22052110 try renderExpression(allocator, ais, tree, asm_output.symbolic_name, Space.None);
22062111 try ais.writer().writeAll("] ");
......@@ -2217,37 +2122,37 @@ fn renderAsmOutput(
22172122 },
22182123 }
22192124
2220 return renderToken(tree, ais, asm_output.lastToken(), space); // )
2125 return renderToken(ais, tree, asm_output.lastToken(), space); // )
22212126}
22222127
22232128fn renderAsmInput(
22242129 allocator: *mem.Allocator,
2225 ais: anytype,
2226 tree: *ast.Tree,
2130 ais: *Ais,
2131 tree: ast.Tree,
22272132 asm_input: *const ast.Node.Asm.Input,
22282133 space: Space,
2229) (@TypeOf(ais.*).Error || Error)!void {
2134) Error!void {
22302135 try ais.writer().writeAll("[");
22312136 try renderExpression(allocator, ais, tree, asm_input.symbolic_name, Space.None);
22322137 try ais.writer().writeAll("] ");
22332138 try renderExpression(allocator, ais, tree, asm_input.constraint, Space.None);
22342139 try ais.writer().writeAll(" (");
22352140 try renderExpression(allocator, ais, tree, asm_input.expr, Space.None);
2236 return renderToken(tree, ais, asm_input.lastToken(), space); // )
2141 return renderToken(ais, tree, asm_input.lastToken(), space); // )
22372142}
22382143
22392144fn renderVarDecl(
22402145 allocator: *mem.Allocator,
2241 ais: anytype,
2242 tree: *ast.Tree,
2243 var_decl: *ast.Node.VarDecl,
2244) (@TypeOf(ais.*).Error || Error)!void {
2146 ais: *Ais,
2147 tree: ast.Tree,
2148 var_decl: ast.Node.Index.VarDecl,
2149) Error!void {
22452150 if (var_decl.getVisibToken()) |visib_token| {
2246 try renderToken(tree, ais, visib_token, Space.Space); // pub
2151 try renderToken(ais, tree, visib_token, Space.Space); // pub
22472152 }
22482153
22492154 if (var_decl.getExternExportToken()) |extern_export_token| {
2250 try renderToken(tree, ais, extern_export_token, Space.Space); // extern
2155 try renderToken(ais, tree, extern_export_token, Space.Space); // extern
22512156
22522157 if (var_decl.getLibName()) |lib_name| {
22532158 try renderExpression(allocator, ais, tree, lib_name, Space.Space); // "lib"
......@@ -2255,13 +2160,13 @@ fn renderVarDecl(
22552160 }
22562161
22572162 if (var_decl.getComptimeToken()) |comptime_token| {
2258 try renderToken(tree, ais, comptime_token, Space.Space); // comptime
2163 try renderToken(ais, tree, comptime_token, Space.Space); // comptime
22592164 }
22602165
22612166 if (var_decl.getThreadLocalToken()) |thread_local_token| {
2262 try renderToken(tree, ais, thread_local_token, Space.Space); // threadlocal
2167 try renderToken(ais, tree, thread_local_token, Space.Space); // threadlocal
22632168 }
2264 try renderToken(tree, ais, var_decl.mut_token, Space.Space); // var
2169 try renderToken(ais, tree, var_decl.mut_token, Space.Space); // var
22652170
22662171 const name_space = if (var_decl.getTypeNode() == null and
22672172 (var_decl.getAlignNode() != null or
......@@ -2270,10 +2175,10 @@ fn renderVarDecl(
22702175 Space.Space
22712176 else
22722177 Space.None;
2273 try renderToken(tree, ais, var_decl.name_token, name_space);
2178 try renderToken(ais, tree, var_decl.name_token, name_space);
22742179
22752180 if (var_decl.getTypeNode()) |type_node| {
2276 try renderToken(tree, ais, tree.nextToken(var_decl.name_token), Space.Space);
2181 try renderToken(ais, tree, tree.nextToken(var_decl.name_token), Space.Space);
22772182 const s = if (var_decl.getAlignNode() != null or
22782183 var_decl.getSectionNode() != null or
22792184 var_decl.getInitNode() != null) Space.Space else Space.None;
......@@ -2284,22 +2189,22 @@ fn renderVarDecl(
22842189 const lparen = tree.prevToken(align_node.firstToken());
22852190 const align_kw = tree.prevToken(lparen);
22862191 const rparen = tree.nextToken(align_node.lastToken());
2287 try renderToken(tree, ais, align_kw, Space.None); // align
2288 try renderToken(tree, ais, lparen, Space.None); // (
2192 try renderToken(ais, tree, align_kw, Space.None); // align
2193 try renderToken(ais, tree, lparen, Space.None); // (
22892194 try renderExpression(allocator, ais, tree, align_node, Space.None);
22902195 const s = if (var_decl.getSectionNode() != null or var_decl.getInitNode() != null) Space.Space else Space.None;
2291 try renderToken(tree, ais, rparen, s); // )
2196 try renderToken(ais, tree, rparen, s); // )
22922197 }
22932198
22942199 if (var_decl.getSectionNode()) |section_node| {
22952200 const lparen = tree.prevToken(section_node.firstToken());
22962201 const section_kw = tree.prevToken(lparen);
22972202 const rparen = tree.nextToken(section_node.lastToken());
2298 try renderToken(tree, ais, section_kw, Space.None); // linksection
2299 try renderToken(tree, ais, lparen, Space.None); // (
2203 try renderToken(ais, tree, section_kw, Space.None); // linksection
2204 try renderToken(ais, tree, lparen, Space.None); // (
23002205 try renderExpression(allocator, ais, tree, section_node, Space.None);
23012206 const s = if (var_decl.getInitNode() != null) Space.Space else Space.None;
2302 try renderToken(tree, ais, rparen, s); // )
2207 try renderToken(ais, tree, rparen, s); // )
23032208 }
23042209
23052210 if (var_decl.getInitNode()) |init_node| {
......@@ -2312,268 +2217,150 @@ fn renderVarDecl(
23122217 {
23132218 ais.pushIndent();
23142219 defer ais.popIndent();
2315 try renderToken(tree, ais, eq_token, eq_space); // =
2220 try renderToken(ais, tree, eq_token, eq_space); // =
23162221 }
23172222 ais.pushIndentOneShot();
23182223 try renderExpression(allocator, ais, tree, init_node, Space.None);
23192224 }
23202225
2321 try renderToken(tree, ais, var_decl.semicolon_token, Space.Newline);
2226 try renderToken(ais, tree, var_decl.semicolon_token, Space.Newline);
23222227}
23232228
23242229fn renderParamDecl(
23252230 allocator: *mem.Allocator,
2326 ais: anytype,
2327 tree: *ast.Tree,
2231 ais: *Ais,
2232 tree: ast.Tree,
23282233 param_decl: ast.Node.FnProto.ParamDecl,
23292234 space: Space,
2330) (@TypeOf(ais.*).Error || Error)!void {
2235) Error!void {
23312236 try renderDocComments(tree, ais, param_decl, param_decl.doc_comments);
23322237
23332238 if (param_decl.comptime_token) |comptime_token| {
2334 try renderToken(tree, ais, comptime_token, Space.Space);
2239 try renderToken(ais, tree, comptime_token, Space.Space);
23352240 }
23362241 if (param_decl.noalias_token) |noalias_token| {
2337 try renderToken(tree, ais, noalias_token, Space.Space);
2242 try renderToken(ais, tree, noalias_token, Space.Space);
23382243 }
23392244 if (param_decl.name_token) |name_token| {
2340 try renderToken(tree, ais, name_token, Space.None);
2341 try renderToken(tree, ais, tree.nextToken(name_token), Space.Space); // :
2245 try renderToken(ais, tree, name_token, Space.None);
2246 try renderToken(ais, tree, tree.nextToken(name_token), Space.Space); // :
23422247 }
23432248 switch (param_decl.param_type) {
23442249 .any_type, .type_expr => |node| try renderExpression(allocator, ais, tree, node, space),
23452250 }
23462251}
23472252
2348fn renderStatement(
2349 allocator: *mem.Allocator,
2350 ais: anytype,
2351 tree: *ast.Tree,
2352 base: *ast.Node,
2353) (@TypeOf(ais.*).Error || Error)!void {
2354 switch (base.tag) {
2355 .VarDecl => {
2356 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
2357 try renderVarDecl(allocator, ais, tree, var_decl);
2358 },
2359 else => {
2360 if (base.requireSemiColon()) {
2361 try renderExpression(allocator, ais, tree, base, Space.None);
2362
2363 const semicolon_index = tree.nextToken(base.lastToken());
2364 assert(tree.token_ids[semicolon_index] == .Semicolon);
2365 try renderToken(tree, ais, semicolon_index, Space.Newline);
2366 } else {
2367 try renderExpression(allocator, ais, tree, base, Space.Newline);
2368 }
2369 },
2370 }
2253fn renderStatement(ais: *Ais, tree: ast.Tree, base: ast.Node.Index) Error!void {
2254 @panic("TODO render statement");
2255 //switch (base.tag) {
2256 // .VarDecl => {
2257 // const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
2258 // try renderVarDecl(allocator, ais, tree, var_decl);
2259 // },
2260 // else => {
2261 // if (base.requireSemiColon()) {
2262 // try renderExpression(allocator, ais, tree, base, Space.None);
2263
2264 // const semicolon_index = tree.nextToken(base.lastToken());
2265 // assert(tree.token_tags[semicolon_index] == .Semicolon);
2266 // try renderToken(ais, tree, semicolon_index, Space.Newline);
2267 // } else {
2268 // try renderExpression(allocator, ais, tree, base, Space.Newline);
2269 // }
2270 // },
2271 //}
23712272}
23722273
23732274const Space = enum {
23742275 None,
23752276 Newline,
2277 /// `renderToken` will additionally consume the next token if it is a comma.
23762278 Comma,
23772279 Space,
23782280 SpaceOrOutdent,
23792281 NoNewline,
2282 /// Skips writing the possible line comment after the token.
23802283 NoComment,
23812284 BlockStart,
23822285};
23832286
2384fn renderTokenOffset(
2385 tree: *ast.Tree,
2386 ais: anytype,
2387 token_index: ast.TokenIndex,
2388 space: Space,
2389 token_skip_bytes: usize,
2390) (@TypeOf(ais.*).Error || Error)!void {
2287fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void {
23912288 if (space == Space.BlockStart) {
2392 // If placing the lbrace on the current line would cause an uggly gap then put the lbrace on the next line
2289 // If placing the lbrace on the current line would cause an ugly gap then put the lbrace on the next line.
23932290 const new_space = if (ais.isLineOverIndented()) Space.Newline else Space.Space;
2394 return renderToken(tree, ais, token_index, new_space);
2291 return renderToken(ais, tree, token_index, new_space);
23952292 }
23962293
2397 var token_loc = tree.token_locs[token_index];
2398 try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));
2294 const token_tags = tree.tokens.items(.tag);
2295 const token_starts = tree.tokens.items(.start);
23992296
2400 if (space == Space.NoComment)
2401 return;
2297 const token_start = token_starts[token_index];
2298 const token_tag = token_tags[token_index];
2299 const lexeme = token_tag.lexeme() orelse lexeme: {
2300 var tokenizer: std.zig.Tokenizer = .{
2301 .buffer = tree.source,
2302 .index = token_start,
2303 .pending_invalid_token = null,
2304 };
2305 const token = tokenizer.next();
2306 assert(token.tag == token_tag);
2307 break :lexeme tree.source[token.loc.start..token.loc.end];
2308 };
2309 try ais.writer().writeAll(lexeme);
24022310
2403 var next_token_id = tree.token_ids[token_index + 1];
2404 var next_token_loc = tree.token_locs[token_index + 1];
2311 switch (space) {
2312 .NoComment => {},
2313 .NoNewline => {},
2314 .None => {},
2315 .Comma => {
2316 const count = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ", ");
2317 if (count == 0 and token_tags[token_index + 1] == .Comma) {
2318 return renderToken(ais, tree, token_index + 1, Space.Newline);
2319 }
2320 try ais.writer().writeAll(",");
24052321
2406 if (space == Space.Comma) switch (next_token_id) {
2407 .Comma => return renderToken(tree, ais, token_index + 1, Space.Newline),
2408 .LineComment => {
2409 try ais.writer().writeAll(", ");
2410 return renderToken(tree, ais, token_index + 1, Space.Newline);
2411 },
2412 else => {
2413 if (token_index + 2 < tree.token_ids.len and
2414 tree.token_ids[token_index + 2] == .MultilineStringLiteralLine)
2415 {
2416 try ais.writer().writeAll(",");
2417 return;
2418 } else {
2419 try ais.writer().writeAll(",");
2322 if (token_tags[token_index + 2] != .MultilineStringLiteralLine) {
24202323 try ais.insertNewline();
2421 return;
24222324 }
24232325 },
2424 };
2425
2426 // Skip over same line doc comments
2427 var offset: usize = 1;
2428 if (next_token_id == .DocComment) {
2429 const loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2430 if (loc.line == 0) {
2431 offset += 1;
2432 next_token_id = tree.token_ids[token_index + offset];
2433 next_token_loc = tree.token_locs[token_index + offset];
2434 }
2435 }
2436
2437 if (next_token_id != .LineComment) {
2438 switch (space) {
2439 Space.None, Space.NoNewline => return,
2440 Space.Newline => {
2441 if (next_token_id == .MultilineStringLiteralLine) {
2442 return;
2443 } else {
2444 try ais.insertNewline();
2445 return;
2446 }
2447 },
2448 Space.Space, Space.SpaceOrOutdent => {
2449 if (next_token_id == .MultilineStringLiteralLine)
2450 return;
2451 try ais.writer().writeByte(' ');
2452 return;
2453 },
2454 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
2455 }
2456 }
2457
2458 while (true) {
2459 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ").len == 2;
2460 if (comment_is_empty) {
2461 switch (space) {
2462 Space.Newline => {
2463 offset += 1;
2464 token_loc = next_token_loc;
2465 next_token_id = tree.token_ids[token_index + offset];
2466 next_token_loc = tree.token_locs[token_index + offset];
2467 if (next_token_id != .LineComment) {
2468 try ais.insertNewline();
2469 return;
2470 }
2471 },
2472 else => break,
2473 }
2474 } else {
2475 break;
2476 }
2477 }
2478
2479 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2480 if (loc.line == 0) {
2481 if (tree.token_ids[token_index] != .MultilineStringLiteralLine) {
2326 .SpaceOrOutdent => @panic("what does this even do"),
2327 .Space => {
2328 _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], "");
24822329 try ais.writer().writeByte(' ');
2483 }
2484 try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
2485 offset = 2;
2486 token_loc = next_token_loc;
2487 next_token_loc = tree.token_locs[token_index + offset];
2488 next_token_id = tree.token_ids[token_index + offset];
2489 if (next_token_id != .LineComment) {
2490 switch (space) {
2491 .None, .Space, .SpaceOrOutdent => {
2492 try ais.insertNewline();
2493 },
2494 .Newline => {
2495 if (next_token_id == .MultilineStringLiteralLine) {
2496 return;
2497 } else {
2498 try ais.insertNewline();
2499 return;
2500 }
2501 },
2502 .NoNewline => {},
2503 .NoComment, .Comma, .BlockStart => unreachable,
2504 }
2505 return;
2506 }
2507 loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2508 }
2509
2510 while (true) {
2511 // translate-c doesn't generate correct newlines
2512 // in generated code (loc.line == 0) so treat that case
2513 // as though there was meant to be a newline between the tokens
2514 var newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);
2515 while (newline_count > 0) : (newline_count -= 1) try ais.insertNewline();
2516 try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
2517
2518 offset += 1;
2519 token_loc = next_token_loc;
2520 next_token_loc = tree.token_locs[token_index + offset];
2521 next_token_id = tree.token_ids[token_index + offset];
2522 if (next_token_id != .LineComment) {
2523 switch (space) {
2524 .Newline => {
2525 if (next_token_id == .MultilineStringLiteralLine) {
2526 return;
2527 } else {
2528 try ais.insertNewline();
2529 return;
2530 }
2531 },
2532 .None, .Space, .SpaceOrOutdent => {
2533 try ais.insertNewline();
2534 },
2535 .NoNewline => {},
2536 .NoComment, .Comma, .BlockStart => unreachable,
2330 },
2331 .Newline => {
2332 if (token_tags[token_index + 1] != .MultilineStringLiteralLine) {
2333 try ais.insertNewline();
25372334 }
2538 return;
2539 }
2540 loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
2335 },
2336 .BlockStart => unreachable,
25412337 }
25422338}
25432339
2544fn renderToken(
2545 tree: *ast.Tree,
2546 ais: anytype,
2547 token_index: ast.TokenIndex,
2548 space: Space,
2549) (@TypeOf(ais.*).Error || Error)!void {
2550 return renderTokenOffset(tree, ais, token_index, space, 0);
2551}
2552
25532340fn renderDocComments(
2554 tree: *ast.Tree,
2555 ais: anytype,
2341 tree: ast.Tree,
2342 ais: *Ais,
25562343 node: anytype,
2557 doc_comments: ?*ast.Node.DocComment,
2558) (@TypeOf(ais.*).Error || Error)!void {
2344 doc_comments: ?ast.Node.Index.DocComment,
2345) Error!void {
25592346 const comment = doc_comments orelse return;
25602347 return renderDocCommentsToken(tree, ais, comment, node.firstToken());
25612348}
25622349
25632350fn renderDocCommentsToken(
2564 tree: *ast.Tree,
2565 ais: anytype,
2566 comment: *ast.Node.DocComment,
2351 tree: ast.Tree,
2352 ais: *Ais,
2353 comment: ast.Node.Index.DocComment,
25672354 first_token: ast.TokenIndex,
2568) (@TypeOf(ais.*).Error || Error)!void {
2355) Error!void {
25692356 var tok_i = comment.first_line;
25702357 while (true) : (tok_i += 1) {
2571 switch (tree.token_ids[tok_i]) {
2358 switch (tree.token_tags[tok_i]) {
25722359 .DocComment, .ContainerDocComment => {
25732360 if (comment.first_line < first_token) {
2574 try renderToken(tree, ais, tok_i, Space.Newline);
2361 try renderToken(ais, tree, tok_i, Space.Newline);
25752362 } else {
2576 try renderToken(tree, ais, tok_i, Space.NoComment);
2363 try renderToken(ais, tree, tok_i, Space.NoComment);
25772364 try ais.insertNewline();
25782365 }
25792366 },
......@@ -2596,7 +2383,7 @@ fn nodeIsBlock(base: *const ast.Node) bool {
25962383 };
25972384}
25982385
2599fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
2386fn nodeCausesSliceOpSpace(base: ast.Node.Index) bool {
26002387 return switch (base.tag) {
26012388 .Catch,
26022389 .Add,
......@@ -2646,7 +2433,7 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
26462433 };
26472434}
26482435
2649fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!void {
2436fn copyFixingWhitespace(ais: *Ais, slice: []const u8) @TypeOf(ais.*).Error!void {
26502437 for (slice) |byte| switch (byte) {
26512438 '\t' => try ais.writer().writeAll(" "),
26522439 '\r' => {},
......@@ -2656,12 +2443,12 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo
26562443
26572444// Returns the number of nodes in `expr` that are on the same line as `rtoken`,
26582445// or null if they all are on the same line.
2659fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex) ?usize {
2446fn rowSize(tree: ast.Tree, exprs: []ast.Node.Index, rtoken: ast.TokenIndex) ?usize {
26602447 const first_token = exprs[0].firstToken();
26612448 const first_loc = tree.tokenLocation(tree.token_locs[first_token].start, rtoken);
26622449 if (first_loc.line == 0) {
26632450 const maybe_comma = tree.prevToken(rtoken);
2664 if (tree.token_ids[maybe_comma] == .Comma)
2451 if (tree.token_tags[maybe_comma] == .Comma)
26652452 return 1;
26662453 return null; // no newlines
26672454 }
lib/std/zig/tokenizer.zig+18-13
......@@ -195,22 +195,23 @@ pub const Token = struct {
195195 Keyword_volatile,
196196 Keyword_while,
197197
198 pub fn symbol(tag: Tag) []const u8 {
198 pub fn lexeme(tag: Tag) ?[]const u8 {
199199 return switch (tag) {
200 .Invalid => "Invalid",
200 .Invalid,
201 .Identifier,
202 .StringLiteral,
203 .MultilineStringLiteralLine,
204 .CharLiteral,
205 .Eof,
206 .Builtin,
207 .IntegerLiteral,
208 .FloatLiteral,
209 .DocComment,
210 .ContainerDocComment,
211 => null,
212
201213 .Invalid_ampersands => "&&",
202214 .Invalid_periodasterisks => ".**",
203 .Identifier => "Identifier",
204 .StringLiteral => "StringLiteral",
205 .MultilineStringLiteralLine => "MultilineStringLiteralLine",
206 .CharLiteral => "CharLiteral",
207 .Eof => "Eof",
208 .Builtin => "Builtin",
209 .IntegerLiteral => "IntegerLiteral",
210 .FloatLiteral => "FloatLiteral",
211 .DocComment => "DocComment",
212 .ContainerDocComment => "ContainerDocComment",
213
214215 .Bang => "!",
215216 .Pipe => "|",
216217 .PipePipe => "||",
......@@ -319,6 +320,10 @@ pub const Token = struct {
319320 .Keyword_while => "while",
320321 };
321322 }
323
324 pub fn symbol(tag: Tag) []const u8 {
325 return tag.lexeme() orelse @tagName(tag);
326 }
322327 };
323328};
324329