diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index d5857c9d53..2d27de575a 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -438,7 +438,6 @@ pub const Tree = struct { .OptionalType, .Suspend, .Resume, - .Break, .Nosuspend, .Comptime, => n = datas[n].lhs, @@ -715,6 +714,16 @@ pub const Tree = struct { n = extra.sentinel; }, + .Break => { + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else if (datas[n].lhs != 0) { + return datas[n].lhs + end_offset; + } else { + return main_tokens[n] + end_offset; + } + }, + // These are not supported by lastToken() because implementation would // require recursion due to the optional comma followed by rbrace. // TODO follow the pattern set by StructInitDotTwoComma which will allow @@ -2023,7 +2032,8 @@ pub const Node = struct { Resume, /// `continue`. lhs is token index of label if any. rhs is unused. Continue, - /// `break rhs`. rhs can be omitted. lhs is label token index, if any. + /// `break :lhs rhs` + /// both lhs and rhs may be omitted. Break, /// `return lhs`. lhs can be omitted. rhs is unused. Return, diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 5d95a2b12f..b38e4c6ea9 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -273,6 +273,24 @@ test "zig fmt: comptime struct field" { ); } +test "zig fmt: break from block" { + try testCanonical( + \\const a = blk: { + \\ break :blk 42; + \\}; + \\const b = blk: { + \\ break :blk; + \\}; + \\const c = { + \\ break 42; + \\}; + \\const d = { + \\ break; + \\}; + \\ + ); +} + //test "zig fmt: c pointer type" { // try testCanonical( // \\pub extern fn repro() [*c]const u8; diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index ce3ce7055a..7daf1b7a62 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -487,28 +487,26 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac return renderToken(ais, tree, datas[node].rhs, space); }, - .Break => unreachable, // TODO - //.Break => { - // const flow_expr = base.castTag(.Break).?; - // const maybe_rhs = flow_expr.getRHS(); - // const maybe_label = flow_expr.getLabel(); - - // if (maybe_label == null and maybe_rhs == null) { - // return renderToken(ais, tree, flow_expr.ltoken, space); // break - // } - - // try renderToken(ais, tree, flow_expr.ltoken, Space.Space); // break - // if (maybe_label) |label| { - // const colon = tree.nextToken(flow_expr.ltoken); - // try renderToken(ais, tree, colon, Space.None); // : - - // if (maybe_rhs == null) { - // return renderToken(ais, tree, label, space); // label - // } - // try renderToken(ais, tree, label, Space.Space); // label - // } - // return renderExpression(ais, tree, maybe_rhs.?, space); - //}, + .Break => { + const main_token = main_tokens[node]; + const label_token = datas[node].lhs; + const target = datas[node].rhs; + if (label_token == 0 and target == 0) { + try renderToken(ais, tree, main_token, space); // break keyword + } else if (label_token == 0 and target != 0) { + try renderToken(ais, tree, main_token, .Space); // break keyword + try renderExpression(ais, tree, target, space); + } else if (label_token != 0 and target == 0) { + try renderToken(ais, tree, main_token, .Space); // break keyword + try renderToken(ais, tree, label_token - 1, .None); // colon + try renderToken(ais, tree, label_token, space); // identifier + } else if (label_token != 0 and target != 0) { + try renderToken(ais, tree, main_token, .Space); // break keyword + try renderToken(ais, tree, label_token - 1, .None); // colon + try renderToken(ais, tree, label_token, .Space); // identifier + try renderExpression(ais, tree, target, space); + } + }, .Continue => unreachable, // TODO //.Continue => {