authorgravatar for goon.pri.low@gmail.comKendall Condon <goon.pri.low@gmail.com> 2026-03-22 17:34:56-04:00
committergravatar for goon.pri.low@gmail.comKendall Condon <goon.pri.low@gmail.com> 2026-03-25 17:30:51-04:00
logab237855b8df3f91f232c7e63eba7d21f166f75f
tree9644c18f1ab5a729114d7695478ef671acd94230
parentc818a1e61f702e1990af3e0773b3954d0e29d0ca

zig fmt: render asm colons with trailing comments

Previously, the comments would be lost with the colons. This required a substantial rewrite of renderAsm to determine how many colons should be rendered.

2 files changed, 102 insertions(+), 69 deletions(-)

lib/std/zig/Ast/Render.zig+85-69
...@@ -2756,8 +2756,47 @@ fn renderAsm(...@@ -2756,8 +2756,47 @@ fn renderAsm(
2756 try renderToken(r, asm_node.ast.asm_token + 1, .none); // lparen2756 try renderToken(r, asm_node.ast.asm_token + 1, .none); // lparen
2757 }2757 }
27582758
2759 const render_colons: [3]?Ast.TokenIndex = colons: {
2760 var colons: [3]Ast.TokenIndex = undefined;
2761 var render: u2 = 0;
2762
2763 const rparen = asm_node.ast.rparen;
2764 filled: {
2765 colons[0] = tree.lastToken(asm_node.ast.template) + 1;
2766 if (colons[0] == rparen) break :filled;
2767
2768 if (asm_node.outputs.len != 0) {
2769 colons[1] = tree.lastToken(asm_node.outputs[asm_node.outputs.len - 1]) + 1;
2770 colons[1] += @intFromBool(tree.tokenTag(colons[1]) == .comma);
2771 render = 1;
2772 } else {
2773 colons[1] = colons[0] + 1;
2774 if (hasComment(tree, colons[0], colons[1])) render = 1;
2775 }
2776 if (colons[1] == rparen) break :filled;
2777
2778 // Next colon is not checked for here since it cannot present without clobbers
2779 if (asm_node.inputs.len != 0) {
2780 render = 2;
2781 } else {
2782 const colon_or_rparen = colons[1] + 1;
2783 if (hasComment(tree, colons[1], colon_or_rparen)) render = 2;
2784 }
2785
2786 if (asm_node.ast.clobbers.unwrap()) |clobbers| {
2787 colons[2] = tree.firstToken(clobbers) - 1;
2788 render = 3;
2789 }
2790 }
2791
2792 var opt_colons: [3]?Ast.TokenIndex = @splat(null);
2793 for (0..render) |i| opt_colons[i] = colons[i];
2794 break :colons opt_colons;
2795 };
2796
2797 try ais.forcePushIndent(.normal);
2798
2759 if (asm_node.ast.items.len == 0) {2799 if (asm_node.ast.items.len == 0) {
2760 try ais.forcePushIndent(.normal);
2761 if (asm_node.ast.clobbers.unwrap()) |clobbers| {2800 if (asm_node.ast.clobbers.unwrap()) |clobbers| {
2762 // asm ("foo" ::: clobbers)2801 // asm ("foo" ::: clobbers)
2763 try renderExpression(r, asm_node.ast.template, .space);2802 try renderExpression(r, asm_node.ast.template, .space);
...@@ -2771,13 +2810,14 @@ fn renderAsm(...@@ -2771,13 +2810,14 @@ fn renderAsm(
2771 return renderToken(r, asm_node.ast.rparen, space); // rparen2810 return renderToken(r, asm_node.ast.rparen, space); // rparen
2772 }2811 }
27732812
2774 // asm ("foo")2813 if (render_colons[0] == null) {
2775 try renderExpression(r, asm_node.ast.template, .none);2814 // asm ("foo")
2776 ais.popIndent();2815 try renderExpression(r, asm_node.ast.template, .none);
2777 return renderToken(r, asm_node.ast.rparen, space); // rparen2816 ais.popIndent();
2817 return renderToken(r, asm_node.ast.rparen, space); // rparen
2818 }
2778 }2819 }
27792820
2780 try ais.forcePushIndent(.normal);
2781 try renderExpression(r, asm_node.ast.template, .newline);2821 try renderExpression(r, asm_node.ast.template, .newline);
2782 ais.forceLastIndent(); // Might have been dedented by a multiline string literal2822 ais.forceLastIndent(); // Might have been dedented by a multiline string literal
2783 assert(ais.current_line_empty);2823 assert(ais.current_line_empty);
...@@ -2785,86 +2825,62 @@ fn renderAsm(...@@ -2785,86 +2825,62 @@ fn renderAsm(
2785 const prev_indent_delta = ais.indent_delta; // May be part of another asm expression2825 const prev_indent_delta = ais.indent_delta; // May be part of another asm expression
2786 // so indent_delta can't be unconditionally used2826 // so indent_delta can't be unconditionally used
2787 ais.setIndentDelta(asm_indent_delta);2827 ais.setIndentDelta(asm_indent_delta);
2788 const colon1 = tree.lastToken(asm_node.ast.template) + 1;
27892828
2790 const colon2 = if (asm_node.outputs.len == 0) colon2: {2829 rendered: {
2791 try renderToken(r, colon1, .newline); // :2830 if (render_colons[0]) |colon1| {
2792 break :colon2 colon1 + 1;2831 if (asm_node.outputs.len != 0) {
2793 } else colon2: {2832 try renderToken(r, colon1, .space);
2794 try renderToken(r, colon1, .space); // :2833 try ais.forcePushIndent(.normal);
27952834
2796 try ais.forcePushIndent(.normal);2835 const final = asm_node.outputs.len - 1;
2797 for (asm_node.outputs, 0..) |asm_output, i| {2836 for (asm_node.outputs[0..final], 0..) |asm_output, i| {
2798 if (i + 1 < asm_node.outputs.len) {2837 try renderAsmOutput(r, asm_output, .none);
2799 const next_asm_output = asm_node.outputs[i + 1];2838
2800 try renderAsmOutput(r, asm_output, .none);2839 const next_start = tree.firstToken(asm_node.outputs[i + 1]);
2840 try renderToken(r, next_start - 1, .newline); // ,
2841 try renderExtraNewlineToken(r, next_start);
2842 }
28012843
2802 const comma = tree.firstToken(next_asm_output) - 1;
2803 try renderToken(r, comma, .newline); // ,
2804 try renderExtraNewlineToken(r, tree.firstToken(next_asm_output));
2805 } else if (asm_node.inputs.len == 0 and asm_node.ast.clobbers == .none) {
2806 try ais.pushSpace(.comma);2844 try ais.pushSpace(.comma);
2807 try renderAsmOutput(r, asm_output, .comma);2845 try renderAsmOutput(r, asm_node.outputs[final], .comma);
2808 ais.popSpace();2846 ais.popSpace();
2809 ais.popIndent();2847 ais.popIndent();
2810 ais.setIndentDelta(indent_delta);
2811 ais.popIndent();
2812 return renderToken(r, asm_node.ast.rparen, space); // rparen
2813 } else {2848 } else {
2814 try ais.pushSpace(.comma);2849 try renderToken(r, colon1, .newline);
2815 try renderAsmOutput(r, asm_output, .comma);
2816 ais.popSpace();
2817 const comma_or_colon = tree.lastToken(asm_output) + 1;
2818 ais.popIndent();
2819 break :colon2 switch (tree.tokenTag(comma_or_colon)) {
2820 .comma => comma_or_colon + 1,
2821 else => comma_or_colon,
2822 };
2823 }2850 }
2824 } else unreachable;2851 } else unreachable;
2825 };
28262852
2827 const colon3 = if (asm_node.inputs.len == 0) colon3: {2853 if (render_colons[1]) |colon2| {
2828 try renderToken(r, colon2, .newline); // :2854 if (asm_node.inputs.len != 0) {
2829 break :colon3 colon2 + 1;2855 try renderToken(r, colon2, .space);
2830 } else colon3: {2856 try ais.forcePushIndent(.normal);
2831 try renderToken(r, colon2, .space); // :2857
2832 try ais.forcePushIndent(.normal);2858 const final = asm_node.inputs.len - 1;
2833 for (asm_node.inputs, 0..) |asm_input, i| {2859 for (asm_node.inputs[0..final], 0..) |asm_input, i| {
2834 if (i + 1 < asm_node.inputs.len) {2860 try renderAsmInput(r, asm_input, .none);
2835 const next_asm_input = asm_node.inputs[i + 1];2861
2836 try renderAsmInput(r, asm_input, .none);2862 const next_start = tree.firstToken(asm_node.inputs[i + 1]);
28372863 try renderToken(r, next_start - 1, .newline); // ,
2838 const first_token = tree.firstToken(next_asm_input);2864 try renderExtraNewlineToken(r, next_start);
2839 try renderToken(r, first_token - 1, .newline); // ,2865 }
2840 try renderExtraNewlineToken(r, first_token);2866
2841 } else if (asm_node.ast.clobbers == .none) {
2842 try ais.pushSpace(.comma);2867 try ais.pushSpace(.comma);
2843 try renderAsmInput(r, asm_input, .comma);2868 try renderAsmInput(r, asm_node.inputs[final], .comma);
2844 ais.popSpace();2869 ais.popSpace();
2845 ais.popIndent();2870 ais.popIndent();
2846 ais.setIndentDelta(indent_delta);
2847 ais.popIndent();
2848 return renderToken(r, asm_node.ast.rparen, space); // rparen
2849 } else {2871 } else {
2850 try ais.pushSpace(.comma);2872 try renderToken(r, colon2, .newline);
2851 try renderAsmInput(r, asm_input, .comma);
2852 ais.popSpace();
2853 const comma_or_colon = tree.lastToken(asm_input) + 1;
2854 ais.popIndent();
2855 break :colon3 switch (tree.tokenTag(comma_or_colon)) {
2856 .comma => comma_or_colon + 1,
2857 else => comma_or_colon,
2858 };
2859 }2873 }
2874 } else break :rendered;
2875
2876 if (render_colons[2]) |colon3| {
2877 const clobbers = asm_node.ast.clobbers.unwrap().?;
2878 try renderToken(r, colon3, .maybe_space);
2879 try renderExpression(r, clobbers, .none);
2880 ais.forceLastIndent(); // Might have been dedented by a multiline string literal
2860 }2881 }
2861 unreachable;2882 }
2862 };
28632883
2864 try renderToken(r, colon3, .maybe_space); // :
2865 const clobbers = asm_node.ast.clobbers.unwrap().?;
2866 try renderExpression(r, clobbers, .none);
2867 ais.forceLastIndent(); // Might have been dedented by a multiline string literal
2868 ais.setIndentDelta(prev_indent_delta);2884 ais.setIndentDelta(prev_indent_delta);
2869 ais.popIndent();2885 ais.popIndent();
2870 return renderToken(r, asm_node.ast.rparen, space); // rparen2886 return renderToken(r, asm_node.ast.rparen, space); // rparen
lib/std/zig/parser_test.zig+17
...@@ -6892,6 +6892,23 @@ test "zig fmt: array init with multiline string literal with fmt on/off" {...@@ -6892,6 +6892,23 @@ test "zig fmt: array init with multiline string literal with fmt on/off" {
6892 );6892 );
6893}6893}
68946894
6895test "zig fmt: render extra colons with comments" {
6896 try testCanonical(
6897 \\const a = asm (""
6898 \\ : // testing
6899 \\);
6900 \\const b = asm (""
6901 \\ : // testing
6902 \\ : // testing
6903 \\);
6904 \\const c = asm (""
6905 \\ :
6906 \\ : // testing
6907 \\);
6908 \\
6909 );
6910}
6911
6895test "recovery: top level" {6912test "recovery: top level" {
6896 try testError(6913 try testError(
6897 \\test "" {inline}6914 \\test "" {inline}