std.zig.parser now parses while loops and labeled break and continue

This commit is contained in:
Jimmi Holst Christensen 2018-04-09 11:11:18 +02:00
parent e4d0b46c0c
commit e260c8ca63
2 changed files with 468 additions and 135 deletions

View File

@ -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,

View File

@ -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 { .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 = ";"});
try stack.append(RenderState { .Expression = base});
},
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;
\\}
\\