Commit 1c79eea125
Changed files (4)
lib
lib/std/zig/ast.zig
@@ -760,6 +760,13 @@ pub const Tree = struct {
n = extra.sentinel;
},
+ .Continue => {
+ if (datas[n].lhs != 0) {
+ return datas[n].lhs + end_offset;
+ } else {
+ return main_tokens[n] + end_offset;
+ }
+ },
.Break => {
if (datas[n].rhs != 0) {
n = datas[n].rhs;
@@ -837,6 +844,21 @@ pub const Tree = struct {
n = max_node;
end_offset += max_offset;
},
+ .WhileCont => {
+ const extra = tree.extraData(datas[n].rhs, Node.WhileCont);
+ assert(extra.then_expr != 0);
+ n = extra.then_expr;
+ },
+ .While => {
+ const extra = tree.extraData(datas[n].rhs, Node.While);
+ assert(extra.else_expr != 0);
+ n = extra.else_expr;
+ },
+ .If => {
+ const extra = tree.extraData(datas[n].rhs, Node.If);
+ assert(extra.else_expr != 0);
+ n = extra.else_expr;
+ },
// These are not supported by lastToken() because implementation would
// require recursion due to the optional comma followed by rbrace.
@@ -851,13 +873,9 @@ pub const Tree = struct {
.TaggedUnionEnumTag => unreachable, // TODO
.TaggedUnionEnumTagComma => unreachable, // TODO
- .If => unreachable, // TODO
- .Continue => unreachable, // TODO
.SwitchRange => unreachable, // TODO
.ArrayType => unreachable, // TODO
.ArrayTypeSentinel => unreachable, // TODO
- .WhileCont => unreachable, // TODO
- .While => unreachable, // TODO
.ForSimple => unreachable, // TODO
.For => unreachable, // TODO
.ErrorValue => unreachable, // TODO
@@ -1404,6 +1422,41 @@ pub const Tree = struct {
});
}
+ pub fn whileSimple(tree: Tree, node: Node.Index) full.While {
+ const data = tree.nodes.items(.data)[node];
+ return tree.fullWhile(.{
+ .while_token = tree.nodes.items(.main_token)[node],
+ .cond_expr = data.lhs,
+ .cont_expr = 0,
+ .then_expr = data.rhs,
+ .else_expr = 0,
+ });
+ }
+
+ pub fn whileCont(tree: Tree, node: Node.Index) full.While {
+ const data = tree.nodes.items(.data)[node];
+ const extra = tree.extraData(data.rhs, Node.WhileCont);
+ return tree.fullWhile(.{
+ .while_token = tree.nodes.items(.main_token)[node],
+ .cond_expr = data.lhs,
+ .cont_expr = extra.cont_expr,
+ .then_expr = extra.then_expr,
+ .else_expr = 0,
+ });
+ }
+
+ pub fn whileFull(tree: Tree, node: Node.Index) full.While {
+ const data = tree.nodes.items(.data)[node];
+ const extra = tree.extraData(data.rhs, Node.While);
+ return tree.fullWhile(.{
+ .while_token = tree.nodes.items(.main_token)[node],
+ .cond_expr = data.lhs,
+ .cont_expr = extra.cont_expr,
+ .then_expr = extra.then_expr,
+ .else_expr = extra.else_expr,
+ });
+ }
+
fn fullVarDecl(tree: Tree, info: full.VarDecl.Ast) full.VarDecl {
const token_tags = tree.tokens.items(.tag);
var result: full.VarDecl = .{
@@ -1623,6 +1676,41 @@ pub const Tree = struct {
return result;
}
+
+ fn fullWhile(tree: Tree, info: full.While.Ast) full.While {
+ const token_tags = tree.tokens.items(.tag);
+ var result: full.While = .{
+ .ast = info,
+ .inline_token = null,
+ .label_token = null,
+ .payload_token = null,
+ .else_token = undefined,
+ .error_token = null,
+ };
+ var tok_i = info.while_token - 1;
+ if (token_tags[tok_i] == .Keyword_inline) {
+ result.inline_token = tok_i;
+ tok_i -= 1;
+ }
+ if (token_tags[tok_i] == .Colon and
+ token_tags[tok_i - 1] == .Identifier)
+ {
+ result.label_token = tok_i - 1;
+ }
+ const last_cond_token = tree.lastToken(info.cond_expr);
+ if (token_tags[last_cond_token + 2] == .Pipe) {
+ result.payload_token = last_cond_token + 3;
+ }
+ if (info.else_expr != 0) {
+ // then_expr else |x|
+ // ^ ^
+ result.else_token = tree.lastToken(info.then_expr) + 1;
+ if (token_tags[result.else_token + 1] == .Pipe) {
+ result.error_token = result.else_token + 2;
+ }
+ }
+ return result;
+ }
};
/// Fully assembled AST node information.
@@ -1645,12 +1733,12 @@ pub const full = struct {
};
pub const If = struct {
- // Points to the first token after the `|`. Will either be an identifier or
- // a `*` (with an identifier immediately after it).
+ /// Points to the first token after the `|`. Will either be an identifier or
+ /// a `*` (with an identifier immediately after it).
payload_token: ?TokenIndex,
- // Points to the identifier after the `|`.
+ /// Points to the identifier after the `|`.
error_token: ?TokenIndex,
- // Populated only if else_expr != 0.
+ /// Populated only if else_expr != 0.
else_token: TokenIndex,
ast: Ast,
@@ -1662,6 +1750,24 @@ pub const full = struct {
};
};
+ pub const While = struct {
+ ast: Ast,
+ inline_token: ?TokenIndex,
+ label_token: ?TokenIndex,
+ payload_token: ?TokenIndex,
+ error_token: ?TokenIndex,
+ /// Populated only if else_expr != 0.
+ else_token: TokenIndex,
+
+ pub const Ast = struct {
+ while_token: TokenIndex,
+ cond_expr: Node.Index,
+ cont_expr: Node.Index,
+ then_expr: Node.Index,
+ else_expr: Node.Index,
+ };
+ };
+
pub const ContainerField = struct {
comptime_token: ?TokenIndex,
ast: Ast,
@@ -2270,9 +2376,9 @@ pub const Node = struct {
/// `if (lhs) rhs`.
/// `if (lhs) |a| rhs`.
IfSimple,
- /// `if (lhs) a else b`. `if_list[rhs]`.
- /// `if (lhs) |x| a else b`. `if_list[rhs]`.
- /// `if (lhs) |x| a else |y| b`. `if_list[rhs]`.
+ /// `if (lhs) a else b`. `If[rhs]`.
+ /// `if (lhs) |x| a else b`. `If[rhs]`.
+ /// `if (lhs) |x| a else |y| b`. `If[rhs]`.
If,
/// `suspend lhs`. lhs can be omitted. rhs is unused.
Suspend,
@@ -2497,13 +2603,13 @@ pub const Node = struct {
};
pub const While = struct {
- continue_expr: Index,
+ cont_expr: Index,
then_expr: Index,
else_expr: Index,
};
pub const WhileCont = struct {
- continue_expr: Index,
+ cont_expr: Index,
then_expr: Index,
};
lib/std/zig/parse.zig
@@ -1085,7 +1085,7 @@ const Parser = struct {
const condition = try p.expectExpr();
_ = try p.expectToken(.RParen);
const then_payload = try p.parsePtrPayload();
- const continue_expr = try p.parseWhileContinueExpr();
+ const cont_expr = try p.parseWhileContinueExpr();
// TODO propose to change the syntax so that semicolons are always required
// inside while statements, even if there is an `else`.
@@ -1098,7 +1098,7 @@ const Parser = struct {
return p.fail(.{ .ExpectedBlockOrAssignment = .{ .token = p.tok_i } });
}
if (p.eatToken(.Semicolon)) |_| {
- if (continue_expr == 0) {
+ if (cont_expr == 0) {
return p.addNode(.{
.tag = .WhileSimple,
.main_token = while_token,
@@ -1114,7 +1114,7 @@ const Parser = struct {
.data = .{
.lhs = condition,
.rhs = try p.addExtra(Node.WhileCont{
- .continue_expr = continue_expr,
+ .cont_expr = cont_expr,
.then_expr = assign_expr,
}),
},
@@ -1128,7 +1128,7 @@ const Parser = struct {
if (else_required) {
return p.fail(.{ .ExpectedSemiOrElse = .{ .token = p.tok_i } });
}
- if (continue_expr == 0) {
+ if (cont_expr == 0) {
return p.addNode(.{
.tag = .WhileSimple,
.main_token = while_token,
@@ -1144,7 +1144,7 @@ const Parser = struct {
.data = .{
.lhs = condition,
.rhs = try p.addExtra(Node.WhileCont{
- .continue_expr = continue_expr,
+ .cont_expr = cont_expr,
.then_expr = then_expr,
}),
},
@@ -1159,7 +1159,7 @@ const Parser = struct {
.data = .{
.lhs = condition,
.rhs = try p.addExtra(Node.While{
- .continue_expr = continue_expr,
+ .cont_expr = cont_expr,
.then_expr = then_expr,
.else_expr = else_expr,
}),
@@ -2073,11 +2073,11 @@ const Parser = struct {
const condition = try p.expectExpr();
_ = try p.expectToken(.RParen);
const then_payload = try p.parsePtrPayload();
- const continue_expr = try p.parseWhileContinueExpr();
+ const cont_expr = try p.parseWhileContinueExpr();
const then_expr = try p.expectExpr();
const else_token = p.eatToken(.Keyword_else) orelse {
- if (continue_expr == 0) {
+ if (cont_expr == 0) {
return p.addNode(.{
.tag = .WhileSimple,
.main_token = while_token,
@@ -2093,7 +2093,7 @@ const Parser = struct {
.data = .{
.lhs = condition,
.rhs = try p.addExtra(Node.WhileCont{
- .continue_expr = continue_expr,
+ .cont_expr = cont_expr,
.then_expr = then_expr,
}),
},
@@ -2108,7 +2108,7 @@ const Parser = struct {
.data = .{
.lhs = condition,
.rhs = try p.addExtra(Node.While{
- .continue_expr = continue_expr,
+ .cont_expr = cont_expr,
.then_expr = then_expr,
.else_expr = else_expr,
}),
@@ -2836,11 +2836,11 @@ const Parser = struct {
const condition = try p.expectExpr();
_ = try p.expectToken(.RParen);
const then_payload = try p.parsePtrPayload();
- const continue_expr = try p.parseWhileContinueExpr();
+ const cont_expr = try p.parseWhileContinueExpr();
const then_expr = try p.expectTypeExpr();
const else_token = p.eatToken(.Keyword_else) orelse {
- if (continue_expr == 0) {
+ if (cont_expr == 0) {
return p.addNode(.{
.tag = .WhileSimple,
.main_token = while_token,
@@ -2856,7 +2856,7 @@ const Parser = struct {
.data = .{
.lhs = condition,
.rhs = try p.addExtra(Node.WhileCont{
- .continue_expr = continue_expr,
+ .cont_expr = cont_expr,
.then_expr = then_expr,
}),
},
@@ -2871,7 +2871,7 @@ const Parser = struct {
.data = .{
.lhs = condition,
.rhs = try p.addExtra(Node.While{
- .continue_expr = continue_expr,
+ .cont_expr = cont_expr,
.then_expr = then_expr,
.else_expr = else_expr,
}),
lib/std/zig/parser_test.zig
@@ -714,19 +714,19 @@ test "zig fmt: async function" {
// \\
// );
//}
-//
-//test "zig fmt: while else err prong with no block" {
-// try testCanonical(
-// \\test "" {
-// \\ const result = while (returnError()) |value| {
-// \\ break value;
-// \\ } else |err| @as(i32, 2);
-// \\ expect(result == 2);
-// \\}
-// \\
-// );
-//}
-//
+
+test "zig fmt: while else err prong with no block" {
+ try testCanonical(
+ \\test "" {
+ \\ const result = while (returnError()) |value| {
+ \\ break value;
+ \\ } else |err| @as(i32, 2);
+ \\ expect(result == 2);
+ \\}
+ \\
+ );
+}
+
//test "zig fmt: tagged union with enum values" {
// try testCanonical(
// \\const MultipleChoice2 = union(enum(u32)) {
lib/std/zig/render.zig
@@ -567,13 +567,13 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
if (lbrace + 1 == rbrace) {
// There is nothing between the braces so render condensed: `error{}`
try renderToken(ais, tree, lbrace, .None);
- try renderToken(ais, tree, rbrace, space);
+ return renderToken(ais, tree, rbrace, space);
} else if (lbrace + 2 == rbrace and token_tags[lbrace + 1] == .Identifier) {
// There is exactly one member and no trailing comma or
// comments, so render without surrounding spaces: `error{Foo}`
try renderToken(ais, tree, lbrace, .None);
try renderToken(ais, tree, lbrace + 1, .None); // identifier
- try renderToken(ais, tree, rbrace, space);
+ return renderToken(ais, tree, rbrace, space);
} else if (token_tags[rbrace - 1] == .Comma) {
// There is a trailing comma so render each member on a new line.
try renderToken(ais, tree, lbrace, .Newline);
@@ -589,7 +589,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
}
}
ais.popIndent();
- try renderToken(ais, tree, rbrace, space);
+ return renderToken(ais, tree, rbrace, space);
} else {
// There is no trailing comma so render everything on one line.
try renderToken(ais, tree, lbrace, .Space);
@@ -602,7 +602,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
else => unreachable,
}
}
- try renderToken(ais, tree, rbrace, space);
+ return renderToken(ais, tree, rbrace, space);
}
},
@@ -663,7 +663,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
if (cases.len == 0) {
try renderToken(ais, tree, rparen + 1, .None); // lbrace
- try renderToken(ais, tree, rparen + 2, space); // rbrace
+ return renderToken(ais, tree, rparen + 2, space); // rbrace
} else {
try renderToken(ais, tree, rparen + 1, .Newline); // lbrace
ais.pushIndent();
@@ -673,83 +673,16 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
try renderExpression(ais, tree, case, .Comma);
}
ais.popIndent();
- try renderToken(ais, tree, tree.lastToken(node), space); // rbrace
+ return renderToken(ais, tree, tree.lastToken(node), space); // rbrace
}
},
- .SwitchCaseOne => try renderSwitchCase(ais, tree, tree.switchCaseOne(node), space),
- .SwitchCase => try renderSwitchCase(ais, tree, tree.switchCase(node), space),
+ .SwitchCaseOne => return renderSwitchCase(ais, tree, tree.switchCaseOne(node), space),
+ .SwitchCase => return renderSwitchCase(ais, tree, tree.switchCase(node), space),
- .WhileSimple => unreachable, // TODO
- .WhileCont => unreachable, // TODO
- .While => unreachable, // TODO
- //.While => {
- // const while_node = @fieldParentPtr(ast.Node.While, "base", base);
-
- // if (while_node.label) |label| {
- // try renderToken(ais, tree, label, Space.None); // label
- // try renderToken(ais, tree, tree.nextToken(label), Space.Space); // :
- // }
-
- // if (while_node.inline_token) |inline_token| {
- // try renderToken(ais, tree, inline_token, Space.Space); // inline
- // }
-
- // try renderToken(ais, tree, while_node.while_token, Space.Space); // while
- // try renderToken(ais, tree, tree.nextToken(while_node.while_token), Space.None); // (
- // try renderExpression(ais, tree, while_node.condition, Space.None);
-
- // const cond_rparen = tree.nextToken(while_node.condition.lastToken());
-
- // const body_is_block = nodeIsBlock(while_node.body);
-
- // var block_start_space: Space = undefined;
- // var after_body_space: Space = undefined;
-
- // if (body_is_block) {
- // block_start_space = Space.BlockStart;
- // after_body_space = if (while_node.@"else" == null) space else Space.Space;
- // } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) {
- // block_start_space = Space.Space;
- // after_body_space = if (while_node.@"else" == null) space else Space.Space;
- // } else {
- // block_start_space = Space.Newline;
- // after_body_space = if (while_node.@"else" == null) space else Space.Newline;
- // }
-
- // {
- // const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;
- // try renderToken(ais, tree, cond_rparen, rparen_space); // )
- // }
-
- // if (while_node.payload) |payload| {
- // const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
- // try renderExpression(ais, tree, payload, payload_space);
- // }
-
- // if (while_node.continue_expr) |continue_expr| {
- // const rparen = tree.nextToken(continue_expr.lastToken());
- // const lparen = tree.prevToken(continue_expr.firstToken());
- // const colon = tree.prevToken(lparen);
-
- // try renderToken(ais, tree, colon, Space.Space); // :
- // try renderToken(ais, tree, lparen, Space.None); // (
-
- // try renderExpression(ais, tree, continue_expr, Space.None);
-
- // try renderToken(ais, tree, rparen, block_start_space); // )
- // }
-
- // {
- // if (!body_is_block) ais.pushIndent();
- // defer if (!body_is_block) ais.popIndent();
- // try renderExpression(ais, tree, while_node.body, after_body_space);
- // }
-
- // if (while_node.@"else") |@"else"| {
- // return renderExpression(ais, tree, &@"else".base, space);
- // }
- //},
+ .WhileSimple => return renderWhile(ais, tree, tree.whileSimple(node), space),
+ .WhileCont => return renderWhile(ais, tree, tree.whileCont(node), space),
+ .While => return renderWhile(ais, tree, tree.whileFull(node), space),
.ForSimple => unreachable, // TODO
.For => unreachable, // TODO
@@ -1092,105 +1025,142 @@ fn renderVarDecl(ais: *Ais, tree: ast.Tree, var_decl: ast.full.VarDecl) Error!vo
}
fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.full.If, space: Space) Error!void {
+ return renderWhile(ais, tree, .{
+ .ast = .{
+ .while_token = if_node.ast.if_token,
+ .cond_expr = if_node.ast.cond_expr,
+ .cont_expr = 0,
+ .then_expr = if_node.ast.then_expr,
+ .else_expr = if_node.ast.else_expr,
+ },
+ .inline_token = null,
+ .label_token = null,
+ .payload_token = if_node.payload_token,
+ .else_token = if_node.else_token,
+ .error_token = if_node.error_token,
+ }, space);
+}
+
+/// Note that this function is additionally used to render if expressions, with
+/// respective values set to null.
+fn renderWhile(ais: *Ais, tree: ast.Tree, while_node: ast.full.While, space: Space) Error!void {
const node_tags = tree.nodes.items(.tag);
const token_tags = tree.tokens.items(.tag);
- try renderToken(ais, tree, if_node.ast.if_token, .Space); // if
+ if (while_node.label_token) |label| {
+ try renderToken(ais, tree, label, .None); // label
+ try renderToken(ais, tree, label + 1, .Space); // :
+ }
- const lparen = if_node.ast.if_token + 1;
+ if (while_node.inline_token) |inline_token| {
+ try renderToken(ais, tree, inline_token, .Space); // inline
+ }
- try renderToken(ais, tree, lparen, .None); // (
- try renderExpression(ais, tree, if_node.ast.cond_expr, .None); // condition
+ try renderToken(ais, tree, while_node.ast.while_token, .Space); // if
+ try renderToken(ais, tree, while_node.ast.while_token + 1, .None); // (
+ try renderExpression(ais, tree, while_node.ast.cond_expr, .None); // condition
- switch (node_tags[if_node.ast.then_expr]) {
- .If, .IfSimple => {
- try renderExtraNewline(ais, tree, if_node.ast.then_expr);
- },
- .Block, .For, .ForSimple, .While, .WhileSimple, .Switch => {
- if (if_node.payload_token) |payload_token| {
- try renderToken(ais, tree, payload_token - 2, .Space); // )
- try renderToken(ais, tree, payload_token - 1, .None); // |
- if (token_tags[payload_token] == .Asterisk) {
- try renderToken(ais, tree, payload_token, .None); // *
- try renderToken(ais, tree, payload_token + 1, .None); // identifier
- try renderToken(ais, tree, payload_token + 2, .BlockStart); // |
- } else {
- try renderToken(ais, tree, payload_token, .None); // identifier
- try renderToken(ais, tree, payload_token + 1, .BlockStart); // |
- }
+ if (nodeIsBlock(node_tags[while_node.ast.then_expr])) {
+ const payload_space: Space = if (while_node.ast.cont_expr != 0) .Space else .BlockStart;
+ if (while_node.payload_token) |payload_token| {
+ try renderToken(ais, tree, payload_token - 2, .Space); // )
+ try renderToken(ais, tree, payload_token - 1, .None); // |
+ if (token_tags[payload_token] == .Asterisk) {
+ try renderToken(ais, tree, payload_token, .None); // *
+ try renderToken(ais, tree, payload_token + 1, .None); // identifier
+ try renderToken(ais, tree, payload_token + 2, payload_space); // |
} else {
- const rparen = tree.lastToken(if_node.ast.cond_expr) + 1;
- try renderToken(ais, tree, rparen, .BlockStart); // )
+ try renderToken(ais, tree, payload_token, .None); // identifier
+ try renderToken(ais, tree, payload_token + 1, payload_space); // |
}
- if (if_node.ast.else_expr != 0) {
- try renderExpression(ais, tree, if_node.ast.then_expr, Space.Space);
- try renderToken(ais, tree, if_node.else_token, .Space); // else
- if (if_node.error_token) |error_token| {
- try renderToken(ais, tree, error_token - 1, .None); // |
- try renderToken(ais, tree, error_token, .None); // identifier
- try renderToken(ais, tree, error_token + 1, .Space); // |
- }
- return renderExpression(ais, tree, if_node.ast.else_expr, space);
- } else {
- return renderExpression(ais, tree, if_node.ast.then_expr, space);
+ } else {
+ const rparen = tree.lastToken(while_node.ast.cond_expr) + 1;
+ try renderToken(ais, tree, rparen, payload_space); // )
+ }
+ if (while_node.ast.cont_expr != 0) {
+ const rparen = tree.lastToken(while_node.ast.cont_expr) + 1;
+ const lparen = tree.firstToken(while_node.ast.cont_expr) - 1;
+ try renderToken(ais, tree, lparen - 1, .Space); // :
+ try renderToken(ais, tree, lparen, .None); // lparen
+ try renderExpression(ais, tree, while_node.ast.cont_expr, .None);
+ try renderToken(ais, tree, rparen, .BlockStart); // rparen
+ }
+ if (while_node.ast.else_expr != 0) {
+ try renderExpression(ais, tree, while_node.ast.then_expr, Space.Space);
+ try renderToken(ais, tree, while_node.else_token, .Space); // else
+ if (while_node.error_token) |error_token| {
+ try renderToken(ais, tree, error_token - 1, .None); // |
+ try renderToken(ais, tree, error_token, .None); // identifier
+ try renderToken(ais, tree, error_token + 1, .Space); // |
}
- },
- else => {},
+ return renderExpression(ais, tree, while_node.ast.else_expr, space);
+ } else {
+ return renderExpression(ais, tree, while_node.ast.then_expr, space);
+ }
}
- const rparen = tree.lastToken(if_node.ast.cond_expr) + 1;
- const last_then_token = tree.lastToken(if_node.ast.then_expr);
+ const rparen = tree.lastToken(while_node.ast.cond_expr) + 1;
+ const last_then_token = tree.lastToken(while_node.ast.then_expr);
const src_has_newline = !tree.tokensOnSameLine(rparen, last_then_token);
if (src_has_newline) {
- if (if_node.payload_token) |payload_token| {
+ const payload_space: Space = if (while_node.ast.cont_expr != 0) .Space else .Newline;
+ if (while_node.payload_token) |payload_token| {
try renderToken(ais, tree, payload_token - 2, .Space); // )
try renderToken(ais, tree, payload_token - 1, .None); // |
try renderToken(ais, tree, payload_token, .None); // identifier
- try renderToken(ais, tree, payload_token + 1, .Newline); // |
+ try renderToken(ais, tree, payload_token + 1, payload_space); // |
} else {
ais.pushIndent();
- try renderToken(ais, tree, rparen, .Newline); // )
+ try renderToken(ais, tree, rparen, payload_space); // )
ais.popIndent();
}
- if (if_node.ast.else_expr != 0) {
+ if (while_node.ast.cont_expr != 0) {
+ const cont_rparen = tree.lastToken(while_node.ast.cont_expr) + 1;
+ const cont_lparen = tree.firstToken(while_node.ast.cont_expr) - 1;
+ try renderToken(ais, tree, cont_lparen - 1, .Space); // :
+ try renderToken(ais, tree, cont_lparen, .None); // lparen
+ try renderExpression(ais, tree, while_node.ast.cont_expr, .None);
+ try renderToken(ais, tree, cont_rparen, .Newline); // rparen
+ }
+ if (while_node.ast.else_expr != 0) {
ais.pushIndent();
- try renderExpression(ais, tree, if_node.ast.then_expr, Space.Newline);
+ try renderExpression(ais, tree, while_node.ast.then_expr, Space.Newline);
ais.popIndent();
- const else_is_block = nodeIsBlock(node_tags[if_node.ast.else_expr]);
+ const else_is_block = nodeIsBlock(node_tags[while_node.ast.else_expr]);
if (else_is_block) {
- try renderToken(ais, tree, if_node.else_token, .Space); // else
- if (if_node.error_token) |error_token| {
+ try renderToken(ais, tree, while_node.else_token, .Space); // else
+ if (while_node.error_token) |error_token| {
try renderToken(ais, tree, error_token - 1, .None); // |
try renderToken(ais, tree, error_token, .None); // identifier
try renderToken(ais, tree, error_token + 1, .Space); // |
}
- return renderExpression(ais, tree, if_node.ast.else_expr, space);
+ return renderExpression(ais, tree, while_node.ast.else_expr, space);
} else {
- if (if_node.error_token) |error_token| {
- try renderToken(ais, tree, if_node.else_token, .Space); // else
+ if (while_node.error_token) |error_token| {
+ try renderToken(ais, tree, while_node.else_token, .Space); // else
try renderToken(ais, tree, error_token - 1, .None); // |
try renderToken(ais, tree, error_token, .None); // identifier
try renderToken(ais, tree, error_token + 1, .Space); // |
} else {
- try renderToken(ais, tree, if_node.else_token, .Newline); // else
+ try renderToken(ais, tree, while_node.else_token, .Newline); // else
}
ais.pushIndent();
- try renderExpression(ais, tree, if_node.ast.else_expr, space);
+ try renderExpression(ais, tree, while_node.ast.else_expr, space);
ais.popIndent();
return;
}
} else {
ais.pushIndent();
- try renderExpression(ais, tree, if_node.ast.then_expr, space);
+ try renderExpression(ais, tree, while_node.ast.then_expr, space);
ais.popIndent();
return;
}
}
- // Single line if statement.
+ // Render everything on a single line.
- if (if_node.payload_token) |payload_token| {
+ if (while_node.payload_token) |payload_token| {
assert(payload_token - 2 == rparen);
try renderToken(ais, tree, payload_token - 2, .Space); // )
try renderToken(ais, tree, payload_token - 1, .None); // |
@@ -1206,19 +1176,28 @@ fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.full.If, space: Space) Error
try renderToken(ais, tree, rparen, .Space); // )
}
- if (if_node.ast.else_expr != 0) {
- try renderExpression(ais, tree, if_node.ast.then_expr, .Space);
- try renderToken(ais, tree, if_node.else_token, .Space); // else
+ if (while_node.ast.cont_expr != 0) {
+ const cont_rparen = tree.lastToken(while_node.ast.cont_expr) + 1;
+ const cont_lparen = tree.firstToken(while_node.ast.cont_expr) - 1;
+ try renderToken(ais, tree, cont_lparen - 1, .Space); // :
+ try renderToken(ais, tree, cont_lparen, .None); // lparen
+ try renderExpression(ais, tree, while_node.ast.cont_expr, .None);
+ try renderToken(ais, tree, cont_rparen, .Space); // rparen
+ }
+
+ if (while_node.ast.else_expr != 0) {
+ try renderExpression(ais, tree, while_node.ast.then_expr, .Space);
+ try renderToken(ais, tree, while_node.else_token, .Space); // else
- if (if_node.error_token) |error_token| {
+ if (while_node.error_token) |error_token| {
try renderToken(ais, tree, error_token - 1, .None); // |
try renderToken(ais, tree, error_token, .None); // identifier
try renderToken(ais, tree, error_token + 1, .Space); // |
}
- return renderExpression(ais, tree, if_node.ast.else_expr, space);
+ return renderExpression(ais, tree, while_node.ast.else_expr, space);
} else {
- return renderExpression(ais, tree, if_node.ast.then_expr, space);
+ return renderExpression(ais, tree, while_node.ast.then_expr, space);
}
}
@@ -2079,12 +2058,16 @@ fn renderDocComments(ais: *Ais, tree: ast.Tree, end_token: ast.TokenIndex) Error
fn nodeIsBlock(tag: ast.Node.Tag) bool {
return switch (tag) {
.Block,
+ .BlockSemicolon,
+ .BlockTwo,
+ .BlockTwoSemicolon,
.If,
.IfSimple,
.For,
.ForSimple,
.While,
.WhileSimple,
+ .WhileCont,
.Switch,
=> true,
else => false,