diff options
| -rw-r--r-- | lib/std/zig/parser_test.zig | 17 | ||||
| -rw-r--r-- | lib/std/zig/render.zig | 148 |
2 files changed, 101 insertions, 64 deletions
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index a74a002385..0fe3e64a35 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1496,12 +1496,14 @@ test "zig fmt: if nested" { \\ GE_EQUAL \\ else \\ GE_GREATER + \\ // comment \\ else if (aInt > bInt) \\ GE_LESS \\ else if (aInt == bInt) \\ GE_EQUAL \\ else \\ GE_GREATER; + \\ // comment \\} \\ ); @@ -4189,6 +4191,21 @@ test "zig fmt: line comment after multiline single expr if statement with multil \\ \\ // bar \\ baz(); + \\ + \\ if (foo) + \\ x = + \\ \\hello + \\ \\hello + \\ \\ + \\ else + \\ y = + \\ \\hello + \\ \\hello + \\ \\ + \\ ; + \\ + \\ // bar + \\ baz(); \\} \\ ); diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index e93881edc0..673a05f8e6 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -44,7 +44,6 @@ pub fn renderTree(buffer: *std.ArrayList(u8), tree: ast.Tree) Error!void { /// Render all members in the given slice, keeping empty lines where appropriate fn renderMembers(gpa: *Allocator, ais: *Ais, tree: ast.Tree, members: []const ast.Node.Index) Error!void { if (members.len == 0) return; - //try renderExtraNewline(ais, tree, members[0]); try renderMember(gpa, ais, tree, members[0], .newline); for (members[1..]) |member| { try renderExtraNewline(ais, tree, member); @@ -202,10 +201,8 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent(); switch (space) { - .none, .space, .newline => {}, - .newline_pop => ais.popIndent(), + .none, .space, .newline, .skip => {}, .semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline), - .semicolon_pop => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline_pop), .comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline), .comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space), } @@ -1147,15 +1144,11 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full. } else { try renderToken(ais, tree, while_node.else_token, .newline); // else } - ais.pushIndent(); - try renderExpression(gpa, ais, tree, while_node.ast.else_expr, space); - ais.popIndent(); + try renderExpressionIndented(gpa, ais, tree, while_node.ast.else_expr, space); return; } } else { - ais.pushIndent(); - assert(space == .semicolon); - try renderExpression(gpa, ais, tree, while_node.ast.then_expr, .semicolon_pop); + try renderExpressionIndented(gpa, ais, tree, while_node.ast.then_expr, space); return; } } @@ -2168,6 +2161,64 @@ fn renderCall( return renderToken(ais, tree, after_last_param_tok, space); // ) } +/// Renders the given expression indented, popping the indent before rendering +/// any following line comments +fn renderExpressionIndented(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { + const token_starts = tree.tokens.items(.start); + const token_tags = tree.tokens.items(.tag); + + ais.pushIndent(); + + var last_token = tree.lastToken(node); + const punctuation = switch (space) { + .none, .space, .newline, .skip => false, + .comma => true, + .comma_space => token_tags[last_token + 1] == .comma, + .semicolon => token_tags[last_token + 1] == .semicolon, + }; + + try renderExpression(gpa, ais, tree, node, if (punctuation) .none else .skip); + + switch (space) { + .none, .space, .newline, .skip => {}, + .comma => { + if (token_tags[last_token + 1] == .comma) { + try renderToken(ais, tree, last_token + 1, .skip); + last_token += 1; + } else { + try ais.writer().writeByte(','); + } + }, + .comma_space => if (token_tags[last_token + 1] == .comma) { + try renderToken(ais, tree, last_token + 1, .skip); + last_token += 1; + }, + .semicolon => if (token_tags[last_token + 1] == .semicolon) { + try renderToken(ais, tree, last_token + 1, .skip); + last_token += 1; + }, + } + + ais.popIndent(); + + if (space == .skip) return; + + const comment_start = token_starts[last_token] + tokenSliceForRender(tree, last_token).len; + const comment = try renderComments(ais, tree, comment_start, token_starts[last_token + 1]); + + if (!comment) switch (space) { + .none => {}, + .space, + .comma_space, + => try ais.writer().writeByte(' '), + .newline, + .comma, + .semicolon, + => try ais.insertNewline(), + .skip => unreachable, + }; +} + /// Render an expression, and the comma that follows it, if it is present in the source. fn renderExpressionComma(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { const token_tags = tree.tokens.items(.tag); @@ -2198,9 +2249,6 @@ const Space = enum { space, /// Output the token lexeme followed by a newline. newline, - /// Same as newline, but pop an indent level before rendering the - /// following comments if any. - newline_pop, /// If the next token is a comma, render it as well. If not, insert one. /// In either case, a newline will be inserted afterwards. comma, @@ -2210,9 +2258,9 @@ const Space = enum { /// Additionally consume the next token if it is a semicolon. /// In either case, a newline will be inserted afterwards. semicolon, - /// Same as semicolon, but pop an indent level before rendering the - /// following comments if any. - semicolon_pop, + /// Skip rendering whitespace and comments. If this is used, the caller + /// *must* handle handle whitespace and comments manually. + skip, }; fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void { @@ -2224,65 +2272,37 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp try ais.writer().writeAll(lexeme); - const token_end = token_start + lexeme.len; - const next_token_start = token_starts[token_index + 1]; - switch (space) { - .none => _ = try renderComments(ais, tree, token_end, next_token_start), - - .space => if (!try renderComments(ais, tree, token_end, next_token_start)) { - try ais.writer().writeByte(' '); - }, + if (space == .skip) return; - .newline => if (!try renderComments(ais, tree, token_end, next_token_start)) { - try ais.insertNewline(); - }, + if (space == .comma and token_tags[token_index + 1] != .comma) { + try ais.writer().writeByte(','); + } - .newline_pop => { - ais.popIndent(); - if (!try renderComments(ais, tree, token_end, next_token_start)) { - try ais.insertNewline(); - } - }, + const comment = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1]); + switch (space) { + .none => {}, + .space => if (!comment) try ais.writer().writeByte(' '), + .newline => if (!comment) try ais.insertNewline(), .comma => if (token_tags[token_index + 1] == .comma) { - _ = try renderComments(ais, tree, token_end, next_token_start); try renderToken(ais, tree, token_index + 1, .newline); - } else { - try ais.writer().writeByte(','); - if (!try renderComments(ais, tree, token_end, next_token_start)) { - try ais.insertNewline(); - } + } else if (!comment) { + try ais.insertNewline(); }, - .comma_space => { - const comment = try renderComments(ais, tree, token_end, next_token_start); - if (token_tags[token_index + 1] == .comma) { - try renderToken(ais, tree, token_index + 1, .space); - } else if (!comment) { - try ais.writer().writeByte(' '); - } + .comma_space => if (token_tags[token_index + 1] == .comma) { + try renderToken(ais, tree, token_index + 1, .space); + } else if (!comment) { + try ais.writer().writeByte(' '); }, - .semicolon => { - const comment = try renderComments(ais, tree, token_end, next_token_start); - if (token_tags[token_index + 1] == .semicolon) { - try renderToken(ais, tree, token_index + 1, .newline); - } else if (!comment) { - try ais.insertNewline(); - } + .semicolon => if (token_tags[token_index + 1] == .semicolon) { + try renderToken(ais, tree, token_index + 1, .newline); + } else if (!comment) { + try ais.insertNewline(); }, - .semicolon_pop => { - if (token_tags[token_index + 1] == .semicolon) { - _ = try renderComments(ais, tree, token_end, next_token_start); - try renderToken(ais, tree, token_index + 1, .newline_pop); - } else { - ais.popIndent(); - if (!try renderComments(ais, tree, token_end, next_token_start)) { - try ais.insertNewline(); - } - } - }, + .skip => unreachable, } } |
