mirror of
https://github.com/ziglang/zig.git
synced 2026-02-03 21:23:36 +00:00
std.zig.parser now parses while loops and labeled break and continue
This commit is contained in:
parent
e4d0b46c0c
commit
e260c8ca63
@ -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,
|
||||
|
||||
@ -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;
|
||||
\\}
|
||||
\\
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user