From 24798b84ad818a4c6d6a6ee3e215ccbc49293b81 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 13 Feb 2021 15:23:24 +0100 Subject: [PATCH] zig fmt: implement multiline string literals --- lib/std/zig/parser_test.zig | 154 ++++++++++++++++++------------------ lib/std/zig/render.zig | 43 +++++++++- 2 files changed, 116 insertions(+), 81 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index db8d028131..11bb4d8ceb 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -50,35 +50,35 @@ test "zig fmt: respect line breaks after var declarations" { ); } -//test "zig fmt: multiline string mixed with comments" { -// try testCanonical( -// \\const s1 = -// \\ //\\one -// \\ \\two) -// \\ \\three -// \\; -// \\const s2 = -// \\ \\one -// \\ \\two) -// \\ //\\three -// \\; -// \\const s3 = -// \\ \\one -// \\ //\\two) -// \\ \\three -// \\; -// \\const s4 = -// \\ \\one -// \\ //\\two -// \\ \\three -// \\ //\\four -// \\ \\five -// \\; -// \\const a = -// \\ 1; -// \\ -// ); -//} +test "zig fmt: multiline string mixed with comments" { + try testCanonical( + \\const s1 = + \\ //\\one + \\ \\two) + \\ \\three + \\; + \\const s2 = + \\ \\one + \\ \\two) + \\ //\\three + \\; + \\const s3 = + \\ \\one + \\ //\\two) + \\ \\three + \\; + \\const s4 = + \\ \\one + \\ //\\two + \\ \\three + \\ //\\four + \\ \\five + \\; + \\const a = + \\ 1; + \\ + ); +} test "zig fmt: empty file" { try testCanonical( @@ -974,25 +974,25 @@ test "zig fmt: character literal larger than u8" { ); } -//test "zig fmt: infix operator and then multiline string literal" { -// try testCanonical( -// \\const x = "" ++ -// \\ \\ hi -// \\; -// \\ -// ); -//} -// -//test "zig fmt: infix operator and then multiline string literal" { -// try testCanonical( -// \\const x = "" ++ -// \\ \\ hi0 -// \\ \\ hi1 -// \\ \\ hi2 -// \\; -// \\ -// ); -//} +test "zig fmt: infix operator and then multiline string literal" { + try testCanonical( + \\const x = "" ++ + \\ \\ hi + \\; + \\ + ); +} + +test "zig fmt: infix operator and then multiline string literal" { + try testCanonical( + \\const x = "" ++ + \\ \\ hi0 + \\ \\ hi1 + \\ \\ hi2 + \\; + \\ + ); +} test "zig fmt: C pointers" { try testCanonical( @@ -1725,35 +1725,35 @@ test "zig fmt: struct literal no trailing comma" { // \\ // ); //} -// -//test "zig fmt: multiline string with backslash at end of line" { -// try testCanonical( -// \\comptime { -// \\ err( -// \\ \\\ -// \\ ); -// \\} -// \\ -// ); -//} -// -//test "zig fmt: multiline string parameter in fn call with trailing comma" { -// try testCanonical( -// \\fn foo() void { -// \\ try stdout.print( -// \\ \\ZIG_CMAKE_BINARY_DIR {} -// \\ \\ZIG_C_HEADER_FILES {} -// \\ \\ZIG_DIA_GUIDS_LIB {} -// \\ \\ -// \\ , -// \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR), -// \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER), -// \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), -// \\ ); -// \\} -// \\ -// ); -//} + +test "zig fmt: multiline string with backslash at end of line" { + try testCanonical( + \\comptime { + \\ err( + \\ \\\ + \\ ); + \\} + \\ + ); +} + +test "zig fmt: multiline string parameter in fn call with trailing comma" { + try testCanonical( + \\fn foo() void { + \\ try stdout.print( + \\ \\ZIG_CMAKE_BINARY_DIR {} + \\ \\ZIG_C_HEADER_FILES {} + \\ \\ZIG_DIA_GUIDS_LIB {} + \\ \\ + \\ , + \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR), + \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER), + \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), + \\ ); + \\} + \\ + ); +} test "zig fmt: trailing comma on fn call" { try testCanonical( diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 42649779b7..33584fa2c0 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -146,7 +146,6 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac .identifier, .integer_literal, .float_literal, - .string_literal, .char_literal, .true_literal, .false_literal, @@ -156,6 +155,29 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac .anyframe_literal, => return renderToken(ais, tree, main_tokens[node], space), + .string_literal => switch (token_tags[main_tokens[node]]) { + .string_literal => try renderToken(ais, tree, main_tokens[node], space), + + .multiline_string_literal_line => { + var locked_indents = ais.lockOneShotIndent(); + try ais.maybeInsertNewline(); + + var i = datas[node].lhs; + while (i <= datas[node].rhs) : (i += 1) try renderToken(ais, tree, i, .newline); + + while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent(); + + switch (space) { + .none => {}, + .semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline), + .comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline), + .comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space), + else => unreachable, + } + }, + else => unreachable, + }, + .error_value => { try renderToken(ais, tree, main_tokens[node], .none); try renderToken(ais, tree, main_tokens[node] + 1, .none); @@ -1821,7 +1843,7 @@ fn renderCall( const last_param = params[params.len - 1]; const after_last_param_tok = tree.lastToken(last_param) + 1; if (token_tags[after_last_param_tok] == .comma) { - ais.pushIndent(); + ais.pushIndentNextLine(); try renderToken(ais, tree, lparen, Space.newline); // ( for (params) |param_node, i| { if (i + 1 < params.len) { @@ -1846,6 +1868,7 @@ fn renderCall( return renderToken(ais, tree, after_last_param_tok + 1, space); // ) } + ais.pushIndentNextLine(); try renderToken(ais, tree, lparen, Space.none); // ( for (params) |param_node, i| { @@ -1856,6 +1879,8 @@ fn renderCall( try renderToken(ais, tree, comma, Space.space); } } + + ais.popIndent(); return renderToken(ais, tree, after_last_param_tok, space); // ) } @@ -1907,7 +1932,8 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp const token_starts = tree.tokens.items(.start); const token_start = token_starts[token_index]; - const lexeme = tree.tokenSlice(token_index); + const lexeme = tokenSliceForRender(tree, token_index); + try ais.writer().writeAll(lexeme); if (space == .no_comment) return; @@ -1991,7 +2017,7 @@ fn renderExtraNewlineToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenInde const prev_token_end = if (token_index == 0) 0 else - token_starts[token_index - 1] + tree.tokenSlice(token_index - 1).len; + token_starts[token_index - 1] + tokenSliceForRender(tree, token_index - 1).len; // If there is a comment present, it will handle the empty line if (mem.indexOf(u8, tree.source[prev_token_end..token_start], "//") != null) return; @@ -2034,6 +2060,15 @@ fn renderDocComments(ais: *Ais, tree: ast.Tree, end_token: ast.TokenIndex) Error } } +fn tokenSliceForRender(tree: ast.Tree, token_index: ast.TokenIndex) []const u8 { + var ret = tree.tokenSlice(token_index); + if (tree.tokens.items(.tag)[token_index] == .multiline_string_literal_line) { + assert(ret[ret.len - 1] == '\n'); + ret.len -= 1; + } + return ret; +} + fn nodeIsBlock(tag: ast.Node.Tag) bool { return switch (tag) { .block,