diff options
| author | Jimmi Holst Christensen <jhc@liab.dk> | 2018-04-09 11:11:18 +0200 |
|---|---|---|
| committer | Jimmi Holst Christensen <jhc@liab.dk> | 2018-04-09 11:11:18 +0200 |
| commit | e260c8ca632fb2569f99d182dd6d1daea2b6df63 (patch) | |
| tree | 2879e9f2b319ad3321ddf911356bfe0e3b8cabfd /std | |
| parent | e4d0b46c0c07f3151b4959c5e2e0d4c304981ead (diff) | |
| download | zig-e260c8ca632fb2569f99d182dd6d1daea2b6df63.tar.gz zig-e260c8ca632fb2569f99d182dd6d1daea2b6df63.zip | |
std.zig.parser now parses while loops and labeled break and continue
Diffstat (limited to 'std')
| -rw-r--r-- | std/zig/ast.zig | 62 | ||||
| -rw-r--r-- | std/zig/parser.zig | 541 |
2 files changed, 468 insertions, 135 deletions
diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 0d060eb685..22b14fe363 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -21,6 +21,7 @@ pub const Node = struct { ParamDecl, Block, Payload, + Else, Switch, SwitchCase, SwitchElse, @@ -61,6 +62,7 @@ pub const Node = struct { Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index), Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index), Id.Payload => @fieldParentPtr(NodePayload, "base", base).iterate(index), + Id.Else => @fieldParentPtr(NodeSwitch, "base", base).iterate(index), Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index), Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index), Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index), @@ -102,6 +104,7 @@ pub const Node = struct { Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(), Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(), Id.Payload => @fieldParentPtr(NodePayload, "base", base).firstToken(), + Id.Else => @fieldParentPtr(NodeSwitch, "base", base).firstToken(), Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(), Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(), Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(), @@ -143,6 +146,7 @@ pub const Node = struct { Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(), Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(), Id.Payload => @fieldParentPtr(NodePayload, "base", base).lastToken(), + Id.Else => @fieldParentPtr(NodeElse, "base", base).lastToken(), Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(), Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(), Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).lastToken(), @@ -578,6 +582,35 @@ pub const NodePayload = struct { } }; +pub const NodeElse = struct { + base: Node, + else_token: Token, + payload: ?&NodePayload, + body: &Node, + + pub fn iterate(self: &NodeElse, index: usize) ?&Node { + var i = index; + + if (self.payload) |payload| { + if (i < 1) return &payload.base; + i -= 1; + } + + if (i < 1) return self.body; + i -= 1; + + return null; + } + + pub fn firstToken(self: &NodeElse) Token { + return self.else_token; + } + + pub fn lastToken(self: &NodeElse) Token { + return self.body.lastToken(); + } +}; + pub const NodeSwitch = struct { base: Node, switch_token: Token, @@ -609,7 +642,7 @@ pub const NodeSwitch = struct { pub const NodeSwitchCase = struct { base: Node, items: ArrayList(&Node), - payload: ?&Node, + payload: ?&NodePayload, expr: &Node, pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node { @@ -657,18 +690,14 @@ pub const NodeSwitchElse = struct { pub const NodeWhile = struct { base: Node, + label: ?Token, + inline_token: ?Token, while_token: Token, condition: &Node, payload: ?&NodePayload, continue_expr: ?&Node, body: &Node, - @"else": ?Else, - - const Else = struct { - capture: ?&NodeIdentifier, - body: &Node, - }; - + @"else": ?&NodeElse, pub fn iterate(self: &NodeWhile, index: usize) ?&Node { var i = index; @@ -690,12 +719,7 @@ pub const NodeWhile = struct { i -= 1; if (self.@"else") |@"else"| { - if (@"else".capture) |capture| { - if (i < 1) return &capture.base; - i -= 1; - } - - if (i < 1) return @"else".body; + if (i < 1) return &@"else".base; i -= 1; } @@ -703,6 +727,14 @@ pub const NodeWhile = struct { } pub fn firstToken(self: &NodeWhile) Token { + if (self.label) |label| { + return label; + } + + if (self.inline_token) |inline_token| { + return inline_token; + } + return self.while_token; } @@ -749,7 +781,7 @@ pub const NodeInfixOp = struct { BitXor, BoolAnd, BoolOr, - Catch: ?&Node, + Catch: ?&NodePayload, Div, EqualEqual, ErrorUnion, diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 0d8b8a3248..7c8fbb4e52 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -116,6 +116,24 @@ pub const Parser = struct { }; } + const LabelCtx = struct { + label: ?Token, + dest_ptr: DestPtr, + }; + + const InlineCtx = struct { + label: ?Token, + inline_token: ?Token, + dest_ptr: DestPtr, + }; + + const LoopCtx = struct { + label: ?Token, + inline_token: ?Token, + loop_token: Token, + dest_ptr: DestPtr, + }; + const State = union(enum) { TopLevel, TopLevelExtern: TopLevelDeclCtx, @@ -137,15 +155,22 @@ pub const Parser = struct { ParamDecl: &ast.NodeFnProto, ParamDeclComma, FnDef: &ast.NodeFnProto, + LabeledExpression: LabelCtx, + Inline: InlineCtx, + While: LoopCtx, + For: LoopCtx, Block: &ast.NodeBlock, + Else: &?&ast.NodeElse, + WhileContinueExpr: &?&ast.Node, Statement: &ast.NodeBlock, + Semicolon: &const &const ast.Node, ExprListItemOrEnd: ExprListCtx, ExprListCommaOrEnd: ExprListCtx, FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer), FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer), FieldListCommaOrEnd: &ast.NodeContainerDecl, SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase), - Payload: DestPtr, + Payload: &?&ast.NodePayload, SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase), SwitchCaseItem: &ArrayList(&ast.Node), SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node), @@ -157,9 +182,6 @@ pub const Parser = struct { /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes. Optional: RevertState, - /// Optional can be reverted by adding the Required state to the stack. - Required, - Expression: DestPtr, RangeExpressionBegin: DestPtr, RangeExpressionEnd: DestPtr, @@ -598,8 +620,7 @@ pub const Parser = struct { continue; }, - State.Optional, - State.Required => { }, + State.Optional => { }, State.Expression => |dest_ptr| { const token = self.getNextToken(); @@ -626,10 +647,51 @@ pub const Parser = struct { continue; }, Token.Id.Keyword_break => { - @panic("TODO: break"); + const label = blk: { + const colon = self.getNextToken(); + if (colon.id != Token.Id.Colon) { + self.putBackToken(colon); + break :blk null; + } + + break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; + }; + + const node = try self.createControlFlowExpr(arena, token, + ast.NodeControlFlowExpression.Kind { + .Break = label, + } + ); + dest_ptr.store(&node.base); + + stack.append(State { + .Optional = RevertState { + .parser = *self, + .tokenizer = *self.tokenizer, + .ptr = &node.rhs, + } + }) catch unreachable; + try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } }); + continue; }, Token.Id.Keyword_continue => { - @panic("TODO: break"); + const label = blk: { + const colon = self.getNextToken(); + if (colon.id != Token.Id.Colon) { + self.putBackToken(colon); + break :blk null; + } + + break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; + }; + + const node = try self.createControlFlowExpr(arena, token, + ast.NodeControlFlowExpression.Kind { + .Continue = label, + } + ); + dest_ptr.store(&node.base); + continue; }, Token.Id.Keyword_cancel => { @panic("TODO: cancel"); @@ -707,14 +769,7 @@ pub const Parser = struct { stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable; try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }); - try stack.append(State { - .Optional = RevertState { - .tokenizer = *self.tokenizer, - .parser = *self, - .ptr = &node.op.Catch, - } - }); - try stack.append(State { .Payload = DestPtr { .NullableField = &node.op.Catch } }); + try stack.append(State { .Payload = &node.op.Catch }); continue; }, Token.Id.QuestionMarkQuestionMark => { @@ -1370,16 +1425,12 @@ pub const Parser = struct { continue; } - const block = try self.createBlock(arena, (?Token)(token), Token(undefined)); - dest_ptr.store(&block.base); - - stack.append(State { .Block = block }) catch unreachable; - try stack.append(State { - .ExpectTokenSave = ExpectTokenSave { - .id = Token.Id.LBrace, - .ptr = &block.lbrace, + stack.append(State { + .LabeledExpression = LabelCtx { + .label = token, + .dest_ptr = dest_ptr } - }); + }) catch unreachable; continue; }, Token.Id.LBrace => { @@ -1398,26 +1449,31 @@ pub const Parser = struct { Token.Id.Keyword_if => { @panic("TODO: inline if"); }, + Token.Id.Keyword_inline => { + stack.append(State { + .Inline = InlineCtx { + .label = null, + .inline_token = token, + .dest_ptr = dest_ptr, + } + }) catch unreachable; + continue; + }, Token.Id.Keyword_while => { - const node = try arena.create(ast.NodeWhile); - *node = ast.NodeWhile { - .base = self.initNode(ast.Node.Id.While), - .while_token = token, - .condition = undefined, - .payload = null, - .continue_expr = null, - .body = undefined, - .@"else" = null, - }; - dest_ptr.store(&node.base); - - @panic("TODO: inline while"); + stack.append(State { + .While = LoopCtx { + .label = null, + .inline_token = null, + .loop_token = token, + .dest_ptr = dest_ptr, + } + }) catch unreachable; + continue; }, Token.Id.Keyword_for => { @panic("TODO: inline for"); }, Token.Id.Keyword_switch => { - @breakpoint(); const node = try arena.create(ast.NodeSwitch); *node = ast.NodeSwitch { .base = self.initNode(ast.Node.Id.Switch), @@ -1558,15 +1614,7 @@ pub const Parser = struct { try list_state.list.append(node); stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable; try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } }); - try stack.append(State { - .Optional = RevertState { - .tokenizer = *self.tokenizer, - .parser = *self, - .ptr = &node.payload, - } - }); - try stack.append(State { .Payload = DestPtr { .NullableField = &node.payload } }); - try stack.append(State.Required); + try stack.append(State { .Payload = &node.payload }); const maybe_else = self.getNextToken(); if (maybe_else.id == Token.Id.Keyword_else) { @@ -1585,32 +1633,6 @@ pub const Parser = struct { } }, - State.Payload => |dest_ptr| { - const lpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; - - const is_ptr = blk: { - const asterik = self.getNextToken(); - if (asterik.id == Token.Id.Asterisk) { - break :blk true; - } else { - self.putBackToken(asterik); - break :blk false; - } - }; - - const ident = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; - const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; - const node = try arena.create(ast.NodePayload); - *node = ast.NodePayload { - .base = self.initNode(ast.Node.Id.Payload), - .lpipe = lpipe, - .is_ptr = is_ptr, - .symbol = try self.createIdentifier(arena, ident), - .rpipe = rpipe - }; - dest_ptr.store(&node.base); - }, - State.SwitchCaseItem => |case_items| { stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable; try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } }); @@ -1642,6 +1664,68 @@ pub const Parser = struct { continue; }, + State.Else => |dest| { + const else_token = self.getNextToken(); + if (else_token.id != Token.Id.Keyword_else) { + self.putBackToken(else_token); + continue; + } + + const node = try arena.create(ast.NodeElse); + *node = ast.NodeElse { + .base = self.initNode(ast.Node.Id.Else), + .else_token = else_token, + .payload = null, + .body = undefined, + }; + *dest = node; + + stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable; + try stack.append(State { .Payload = &node.payload }); + }, + + State.WhileContinueExpr => |dest| { + const colon = self.getNextToken(); + if (colon.id != Token.Id.Colon) { + self.putBackToken(colon); + continue; + } + + _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue; + stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable; + try stack.append(State { .Expression = DestPtr { .NullableField = dest } }); + }, + + State.Payload => |dest| { + const lpipe = self.getNextToken(); + if (lpipe.id != Token.Id.Pipe) { + self.putBackToken(lpipe); + continue; + } + + const is_ptr = blk: { + const asterik = self.getNextToken(); + if (asterik.id == Token.Id.Asterisk) { + break :blk true; + } else { + self.putBackToken(asterik); + break :blk false; + } + }; + + const ident = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; + const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; + const node = try arena.create(ast.NodePayload); + *node = ast.NodePayload { + .base = self.initNode(ast.Node.Id.Payload), + .lpipe = lpipe, + .is_ptr = is_ptr, + .symbol = try self.createIdentifier(arena, ident), + .rpipe = rpipe + }; + *dest = node; + }, + State.AddrOfModifiers => |addr_of_info| { var token = self.getNextToken(); switch (token.id) { @@ -1803,6 +1887,114 @@ pub const Parser = struct { } }, + State.LabeledExpression => |ctx| { + const token = self.getNextToken(); + switch (token.id) { + Token.Id.LBrace => { + const block = try self.createBlock(arena, (?Token)(ctx.label), token); + ctx.dest_ptr.store(&block.base); + + stack.append(State { .Block = block }) catch unreachable; + continue; + }, + Token.Id.Keyword_while => { + stack.append(State { + .While = LoopCtx { + .label = ctx.label, + .inline_token = null, + .loop_token = token, + .dest_ptr = ctx.dest_ptr, + } + }) catch unreachable; + continue; + }, + Token.Id.Keyword_for => { + stack.append(State { + .For = LoopCtx { + .label = ctx.label, + .inline_token = null, + .loop_token = token, + .dest_ptr = ctx.dest_ptr, + } + }) catch unreachable; + continue; + }, + Token.Id.Keyword_inline => { + stack.append(State { + .Inline = InlineCtx { + .label = ctx.label, + .inline_token = token, + .dest_ptr = ctx.dest_ptr, + } + }) catch unreachable; + continue; + }, + else => { + try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id)); + continue; + }, + } + }, + + State.Inline => |ctx| { + const token = self.getNextToken(); + switch (token.id) { + Token.Id.Keyword_while => { + stack.append(State { + .While = LoopCtx { + .inline_token = ctx.inline_token, + .label = ctx.label, + .loop_token = token, + .dest_ptr = ctx.dest_ptr, + } + }) catch unreachable; + continue; + }, + Token.Id.Keyword_for => { + stack.append(State { + .For = LoopCtx { + .inline_token = ctx.inline_token, + .label = ctx.label, + .loop_token = token, + .dest_ptr = ctx.dest_ptr, + } + }) catch unreachable; + continue; + }, + else => { + try self.parseError(&stack, token, "expected 'while' or 'for', found {}", @tagName(token.id)); + continue; + }, + } + }, + + State.While => |ctx| { + const node = try arena.create(ast.NodeWhile); + *node = ast.NodeWhile { + .base = self.initNode(ast.Node.Id.While), + .label = ctx.label, + .inline_token = ctx.inline_token, + .while_token = ctx.loop_token, + .condition = undefined, + .payload = null, + .continue_expr = null, + .body = undefined, + .@"else" = null, + }; + ctx.dest_ptr.store(&node.base); + + stack.append(State { .Else = &node.@"else" }) catch unreachable; + try stack.append(State { .Expression = DestPtr { .Field = &node.body } }); + try stack.append(State { .WhileContinueExpr = &node.continue_expr }); + try stack.append(State { .Payload = &node.payload }); + try stack.append(State { .ExpectToken = Token.Id.RParen }); + try stack.append(State { .Expression = DestPtr { .Field = &node.condition } }); + try stack.append(State { .ExpectToken = Token.Id.LParen }); + }, + + State.For => |ctx| { + }, + State.Block => |block| { const token = self.getNextToken(); switch (token.id) { @@ -1841,28 +2033,6 @@ pub const Parser = struct { stack.append(State { .VarDecl = var_decl }) catch unreachable; continue; }, - Token.Id.Identifier => { - const maybe_colon = self.getNextToken(); - if (maybe_colon.id != Token.Id.Colon) { - self.putBackToken(maybe_colon); - self.putBackToken(next); - stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable; - try stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }); - continue; - } - - const inner_block = try self.createBlock(arena, (?Token)(next), Token(undefined)); - try block.statements.append(&inner_block.base); - - stack.append(State { .Block = inner_block }) catch unreachable; - try stack.append(State { - .ExpectTokenSave = ExpectTokenSave { - .id = Token.Id.LBrace, - .ptr = &inner_block.lbrace, - } - }); - continue; - }, Token.Id.LBrace => { const inner_block = try self.createBlock(arena, (?Token)(null), next); try block.statements.append(&inner_block.base); @@ -1870,22 +2040,53 @@ pub const Parser = struct { stack.append(State { .Block = inner_block }) catch unreachable; continue; }, - Token.Id.Keyword_suspend, Token.Id.Keyword_if, - Token.Id.Keyword_while, Token.Id.Keyword_for, - Token.Id.Keyword_switch => { - self.putBackToken(next); - stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }) catch unreachable; - continue; - }, else => { self.putBackToken(next); - stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable; - try stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }); + const statememt = try block.statements.addOne(); + stack.append(State { .Semicolon = statememt }) catch unreachable; + try stack.append(State { .Expression = DestPtr{.Field = statememt } }); continue; } } }, + + State.Semicolon => |node_ptr| { + const node = *node_ptr; + switch (node.id) { + ast.Node.Id.Root, + ast.Node.Id.StructField, + ast.Node.Id.UnionTag, + ast.Node.Id.EnumTag, + ast.Node.Id.ParamDecl, + ast.Node.Id.Block, + ast.Node.Id.Payload, + ast.Node.Id.Switch, + ast.Node.Id.SwitchCase, + ast.Node.Id.SwitchElse, + ast.Node.Id.FieldInitializer, + ast.Node.Id.LineComment, + ast.Node.Id.TestDecl => continue, + ast.Node.Id.While => { + const while_node = @fieldParentPtr(ast.NodeWhile, "base", node); + if (while_node.@"else") |@"else"| { + stack.append(State { .Semicolon = &@"else".base }) catch unreachable; + continue; + } + + stack.append(State { .Semicolon = &while_node.body }) catch unreachable; + continue; + }, + ast.Node.Id.Else => { + const else_node = @fieldParentPtr(ast.NodeElse, "base", node); + stack.append(State { .Semicolon = &else_node.body }) catch unreachable; + continue; + }, + else => { + _ = (try self.eatToken(&stack, Token.Id.Semicolon)) ?? continue; + } + } + } } } } @@ -2295,9 +2496,6 @@ pub const Parser = struct { *revert.ptr = null; return; }, - State.Required => { - return error.StateRequired; - }, else => { } } } @@ -2361,6 +2559,7 @@ pub const Parser = struct { Expression: &ast.Node, VarDecl: &ast.NodeVarDecl, Statement: &ast.Node, + Semicolon: &ast.Node, FieldInitializer: &ast.NodeFieldInitializer, PrintIndent, Indent: usize, @@ -2589,7 +2788,7 @@ pub const Parser = struct { if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) { if (prefix_op_node.op.Catch) |payload| { try stack.append(RenderState { .Text = " " }); - try stack.append(RenderState { .Expression = payload }); + try stack.append(RenderState { .Expression = &payload.base }); } try stack.append(RenderState { .Text = " catch " }); } else { @@ -3013,7 +3212,7 @@ pub const Parser = struct { try stack.append(RenderState { .Expression = switch_case.expr }); if (switch_case.payload) |payload| { try stack.append(RenderState { .Text = " " }); - try stack.append(RenderState { .Expression = payload }); + try stack.append(RenderState { .Expression = &payload.base }); } try stack.append(RenderState { .Text = " => "}); @@ -3032,7 +3231,74 @@ pub const Parser = struct { const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base); try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token)); }, - ast.Node.Id.While => @panic("TODO: Render while"), + ast.Node.Id.Else => { + const else_node = @fieldParentPtr(ast.NodeElse, "base", base); + try stream.print("{} ", self.tokenizer.getTokenSlice(else_node.else_token)); + + if (else_node.body.id == ast.Node.Id.Block) { + try stack.append(RenderState { .Expression = else_node.body }); + } else { + try stack.append(RenderState { .Indent = indent }); + try stack.append(RenderState { .Expression = else_node.body }); + try stack.append(RenderState.PrintIndent); + try stack.append(RenderState { .Indent = indent + indent_delta }); + try stack.append(RenderState { .Text = "\n" }); + } + + if (else_node.payload) |payload| { + try stack.append(RenderState { .Text = " " }); + try stack.append(RenderState { .Expression = &payload.base }); + } + }, + ast.Node.Id.While => { + const while_node = @fieldParentPtr(ast.NodeWhile, "base", base); + if (while_node.label) |label| { + try stream.print("{}: ", self.tokenizer.getTokenSlice(label)); + } + + if (while_node.inline_token) |inline_token| { + try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token)); + } + + try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token)); + + if (while_node.@"else") |@"else"| { + try stack.append(RenderState { .Expression = &@"else".base }); + + if (while_node.body.id == ast.Node.Id.Block) { + try stack.append(RenderState { .Text = " " }); + } else { + try stack.append(RenderState { .Text = "\n" }); + } + } + + if (while_node.body.id == ast.Node.Id.Block) { + try stack.append(RenderState { .Expression = while_node.body }); + try stack.append(RenderState { .Text = " " }); + } else { + try stack.append(RenderState { .Indent = indent }); + try stack.append(RenderState { .Expression = while_node.body }); + try stack.append(RenderState.PrintIndent); + try stack.append(RenderState { .Indent = indent + indent_delta }); + try stack.append(RenderState { .Text = "\n" }); + } + + if (while_node.continue_expr) |continue_expr| { + try stack.append(RenderState { .Text = ")" }); + try stack.append(RenderState { .Expression = continue_expr }); + try stack.append(RenderState { .Text = ": (" }); + try stack.append(RenderState { .Text = " " }); + } + + if (while_node.payload) |payload| { + try stack.append(RenderState { .Expression = &payload.base }); + try stack.append(RenderState { .Text = " " }); + } + + try stack.append(RenderState { .Text = ")" }); + try stack.append(RenderState { .Expression = while_node.condition }); + try stack.append(RenderState { .Text = "(" }); + }, ast.Node.Id.StructField, ast.Node.Id.UnionTag, @@ -3077,13 +3343,45 @@ pub const Parser = struct { const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", base); try stack.append(RenderState { .VarDecl = var_decl}); }, - ast.Node.Id.Block, ast.Node.Id.Switch => { - try stack.append(RenderState { .Expression = base}); - }, else => { - try stack.append(RenderState { .Text = ";"}); - try stack.append(RenderState { .Expression = base}); + try stack.append(RenderState { .Semicolon = base }); + try stack.append(RenderState { .Expression = base }); + }, + } + }, + RenderState.Semicolon => |base| { + switch (base.id) { + ast.Node.Id.Root, + ast.Node.Id.StructField, + ast.Node.Id.UnionTag, + ast.Node.Id.EnumTag, + ast.Node.Id.ParamDecl, + ast.Node.Id.Block, + ast.Node.Id.Payload, + ast.Node.Id.Switch, + ast.Node.Id.SwitchCase, + ast.Node.Id.SwitchElse, + ast.Node.Id.FieldInitializer, + ast.Node.Id.LineComment, + ast.Node.Id.TestDecl => {}, + ast.Node.Id.While => { + const while_node = @fieldParentPtr(ast.NodeWhile, "base", base); + if (while_node.@"else") |@"else"| { + stack.append(RenderState { .Semicolon = &@"else".base }) catch unreachable; + continue; + } + + stack.append(RenderState { .Semicolon = while_node.body }) catch unreachable; + continue; + }, + ast.Node.Id.Else => { + const else_node = @fieldParentPtr(ast.NodeElse, "base", base); + stack.append(RenderState { .Semicolon = else_node.body }) catch unreachable; + continue; }, + else => { + try stack.append(RenderState { .Text = ";" }); + } } }, RenderState.Indent => |new_indent| indent = new_indent, @@ -3690,8 +3988,11 @@ test "zig fmt: while" { \\ continue; \\ \\ i = 0; - \\ var j usize = 0; - \\ while (i < 10) : ({ i += 1; j += 1; }) { + \\ var j: usize = 0; + \\ while (i < 10) : ({ + \\ i += 1; + \\ j += 1; + \\ }) { \\ continue; \\ } \\ @@ -3711,7 +4012,7 @@ test "zig fmt: while" { \\ break 7; \\ } else { \\ unreachable; - \\ } + \\ }; \\ \\ var a: error!u8 = 0; \\ while (a) |v| { @@ -3721,7 +4022,7 @@ test "zig fmt: while" { \\ } \\ \\ comptime var k: usize = 0; - \\ inline while (i < 10) (i += 1) + \\ inline while (i < 10) : (i += 1) \\ j += 2; \\} \\ |
