mirror of
https://github.com/ziglang/zig.git
synced 2026-02-18 23:39:17 +00:00
std.zig.parser now parses labeled blocks.
* There is also some code for switch range parsing
This commit is contained in:
parent
f667744d44
commit
820de1716b
@ -20,6 +20,8 @@ pub const Node = struct {
|
||||
FnProto,
|
||||
ParamDecl,
|
||||
Block,
|
||||
Switch,
|
||||
SwitchCase,
|
||||
InfixOp,
|
||||
PrefixOp,
|
||||
SuffixOp,
|
||||
@ -55,6 +57,8 @@ pub const Node = struct {
|
||||
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
|
||||
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),
|
||||
Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
|
||||
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
|
||||
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index),
|
||||
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
|
||||
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
|
||||
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index),
|
||||
@ -91,6 +95,8 @@ pub const Node = struct {
|
||||
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),
|
||||
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),
|
||||
Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
|
||||
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
|
||||
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(),
|
||||
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
|
||||
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
|
||||
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(),
|
||||
@ -127,6 +133,8 @@ pub const Node = struct {
|
||||
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),
|
||||
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),
|
||||
Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
|
||||
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(),
|
||||
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(),
|
||||
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
|
||||
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
|
||||
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(),
|
||||
@ -506,9 +514,10 @@ pub const NodeParamDecl = struct {
|
||||
|
||||
pub const NodeBlock = struct {
|
||||
base: Node,
|
||||
begin_token: Token,
|
||||
end_token: Token,
|
||||
label: ?Token,
|
||||
lbrace: Token,
|
||||
statements: ArrayList(&Node),
|
||||
rbrace: Token,
|
||||
|
||||
pub fn iterate(self: &NodeBlock, index: usize) ?&Node {
|
||||
var i = index;
|
||||
@ -520,11 +529,80 @@ pub const NodeBlock = struct {
|
||||
}
|
||||
|
||||
pub fn firstToken(self: &NodeBlock) Token {
|
||||
return self.begin_token;
|
||||
if (self.label) |label| {
|
||||
return label;
|
||||
}
|
||||
|
||||
return self.lbrace;
|
||||
}
|
||||
|
||||
pub fn lastToken(self: &NodeBlock) Token {
|
||||
return self.end_token;
|
||||
return self.rbrace;
|
||||
}
|
||||
};
|
||||
|
||||
pub const NodeSwitch = struct {
|
||||
base: Node,
|
||||
switch_token: Token,
|
||||
expr: &Node,
|
||||
cases: ArrayList(&NodeSwitchCase),
|
||||
rbrace: Token,
|
||||
|
||||
pub fn iterate(self: &NodeSwitch, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return self.expr;
|
||||
i -= 1;
|
||||
|
||||
if (i < self.cases.len) return self.cases.at(i);
|
||||
i -= self.cases.len;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn firstToken(self: &NodeSwitch) Token {
|
||||
return self.switch_token;
|
||||
}
|
||||
|
||||
pub fn lastToken(self: &NodeSwitch) Token {
|
||||
return self.rbrace;
|
||||
}
|
||||
};
|
||||
|
||||
pub const NodeSwitchCase = struct {
|
||||
base: Node,
|
||||
items: ArrayList(&Node),
|
||||
capture: ?Capture,
|
||||
expr: &Node,
|
||||
|
||||
const Capture = struct {
|
||||
symbol: &NodeIdentifier,
|
||||
is_ptr: bool,
|
||||
};
|
||||
|
||||
pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
|
||||
var i = index;
|
||||
|
||||
if (i < self.items.len) return self.items.at(i);
|
||||
i -= self.items.len;
|
||||
|
||||
if (self.capture) |capture| {
|
||||
if (i < 1) return &capture.base;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
if (i < 1) return self.expr;
|
||||
i -= 1;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn firstToken(self: &NodeSwitchCase) Token {
|
||||
return self.items.at(0).firstToken();
|
||||
}
|
||||
|
||||
pub fn lastToken(self: &NodeSwitchCase) Token {
|
||||
return self.expr.lastToken();
|
||||
}
|
||||
};
|
||||
|
||||
@ -575,6 +653,7 @@ pub const NodeInfixOp = struct {
|
||||
Mult,
|
||||
MultWrap,
|
||||
Period,
|
||||
Range,
|
||||
Sub,
|
||||
SubWrap,
|
||||
UnwrapMaybe,
|
||||
@ -625,6 +704,7 @@ pub const NodeInfixOp = struct {
|
||||
InfixOp.Mult,
|
||||
InfixOp.MultWrap,
|
||||
InfixOp.Period,
|
||||
InfixOp.Range,
|
||||
InfixOp.Sub,
|
||||
InfixOp.SubWrap,
|
||||
InfixOp.UnwrapMaybe => {},
|
||||
|
||||
@ -146,6 +146,8 @@ pub const Parser = struct {
|
||||
Required,
|
||||
|
||||
Expression: DestPtr,
|
||||
RangeExpressionBegin: DestPtr,
|
||||
RangeExpressionEnd: DestPtr,
|
||||
AssignmentExpressionBegin: DestPtr,
|
||||
AssignmentExpressionEnd: DestPtr,
|
||||
UnwrapExpressionBegin: DestPtr,
|
||||
@ -256,7 +258,7 @@ pub const Parser = struct {
|
||||
}
|
||||
|
||||
const name = try self.createStringLiteral(arena, name_token);
|
||||
const block = try self.createBlock(arena, token);
|
||||
const block = try self.createBlock(arena, (?Token)(null), token);
|
||||
const test_decl = try self.createAttachTestDecl(arena, &root_node.decls, token, &name.base, block);
|
||||
stack.append(State { .Block = block }) catch unreachable;
|
||||
continue;
|
||||
@ -643,6 +645,27 @@ pub const Parser = struct {
|
||||
}
|
||||
},
|
||||
|
||||
State.RangeExpressionBegin => |dest_ptr| {
|
||||
stack.append(State { .RangeExpressionEnd = dest_ptr }) catch unreachable;
|
||||
try stack.append(State { .Expression = dest_ptr });
|
||||
continue;
|
||||
},
|
||||
|
||||
State.RangeExpressionEnd => |dest_ptr| {
|
||||
const token = self.getNextToken();
|
||||
if (token.id == Token.Id.Ellipsis3) {
|
||||
const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Range);
|
||||
node.lhs = dest_ptr.get();
|
||||
dest_ptr.store(&node.base);
|
||||
|
||||
stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
|
||||
continue;
|
||||
} else {
|
||||
self.putBackToken(token);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
|
||||
State.AssignmentExpressionBegin => |dest_ptr| {
|
||||
stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
|
||||
try stack.append(State { .UnwrapExpressionBegin = dest_ptr });
|
||||
@ -1205,10 +1228,6 @@ pub const Parser = struct {
|
||||
try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
|
||||
continue;
|
||||
},
|
||||
Token.Id.Identifier => {
|
||||
dest_ptr.store(&(try self.createIdentifier(arena, token)).base);
|
||||
continue;
|
||||
},
|
||||
Token.Id.Builtin => {
|
||||
const node = try arena.create(ast.NodeBuiltinCall);
|
||||
*node = ast.NodeBuiltinCall {
|
||||
@ -1348,8 +1367,32 @@ pub const Parser = struct {
|
||||
},
|
||||
}) catch unreachable;
|
||||
},
|
||||
Token.Id.Identifier => {
|
||||
const next = self.getNextToken();
|
||||
if (next.id != Token.Id.Colon) {
|
||||
self.putBackToken(next);
|
||||
dest_ptr.store(&(try self.createIdentifier(arena, token)).base);
|
||||
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,
|
||||
}
|
||||
});
|
||||
continue;
|
||||
},
|
||||
Token.Id.LBrace => {
|
||||
@panic("TODO: Block expr");
|
||||
const block = try self.createBlock(arena, (?Token)(null), token);
|
||||
dest_ptr.store(&block.base);
|
||||
|
||||
stack.append(State { .Block = block }) catch unreachable;
|
||||
continue;
|
||||
},
|
||||
Token.Id.Keyword_fn => {
|
||||
@panic("TODO: fn proto");
|
||||
@ -1618,7 +1661,7 @@ pub const Parser = struct {
|
||||
const token = self.getNextToken();
|
||||
switch(token.id) {
|
||||
Token.Id.LBrace => {
|
||||
const block = try self.createBlock(arena, token);
|
||||
const block = try self.createBlock(arena, (?Token)(null), token);
|
||||
fn_proto.body_node = &block.base;
|
||||
stack.append(State { .Block = block }) catch unreachable;
|
||||
continue;
|
||||
@ -1635,7 +1678,7 @@ pub const Parser = struct {
|
||||
const token = self.getNextToken();
|
||||
switch (token.id) {
|
||||
Token.Id.RBrace => {
|
||||
block.end_token = token;
|
||||
block.rbrace = token;
|
||||
continue;
|
||||
},
|
||||
else => {
|
||||
@ -1648,38 +1691,64 @@ pub const Parser = struct {
|
||||
},
|
||||
|
||||
State.Statement => |block| {
|
||||
{
|
||||
// Look for comptime var, comptime const
|
||||
const comptime_token = self.getNextToken();
|
||||
if (comptime_token.id == Token.Id.Keyword_comptime) {
|
||||
const next = self.getNextToken();
|
||||
switch (next.id) {
|
||||
Token.Id.Keyword_comptime => {
|
||||
const mut_token = self.getNextToken();
|
||||
if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
|
||||
// TODO shouldn't need these casts
|
||||
const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
|
||||
mut_token, (?Token)(comptime_token), (?Token)(null), null);
|
||||
mut_token, (?Token)(next), (?Token)(null), null);
|
||||
stack.append(State { .VarDecl = var_decl }) catch unreachable;
|
||||
continue;
|
||||
} else {
|
||||
self.putBackToken(mut_token);
|
||||
@panic("TODO: comptime block");
|
||||
}
|
||||
self.putBackToken(mut_token);
|
||||
}
|
||||
self.putBackToken(comptime_token);
|
||||
}
|
||||
{
|
||||
// Look for const, var
|
||||
const mut_token = self.getNextToken();
|
||||
if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
|
||||
// TODO shouldn't need these casts
|
||||
},
|
||||
Token.Id.Keyword_var, Token.Id.Keyword_const => {
|
||||
const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
|
||||
mut_token, (?Token)(null), (?Token)(null), null);
|
||||
next, (?Token)(null), (?Token)(null), null);
|
||||
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);
|
||||
|
||||
stack.append(State { .Block = inner_block }) 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() } });
|
||||
continue;
|
||||
}
|
||||
self.putBackToken(mut_token);
|
||||
}
|
||||
|
||||
stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
|
||||
try stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } });
|
||||
continue;
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1905,14 +1974,15 @@ pub const Parser = struct {
|
||||
return node;
|
||||
}
|
||||
|
||||
fn createBlock(self: &Parser, arena: &mem.Allocator, begin_token: &const Token) !&ast.NodeBlock {
|
||||
fn createBlock(self: &Parser, arena: &mem.Allocator, label: &const ?Token, lbrace: &const Token) !&ast.NodeBlock {
|
||||
const node = try arena.create(ast.NodeBlock);
|
||||
|
||||
*node = ast.NodeBlock {
|
||||
.base = self.initNode(ast.Node.Id.Block),
|
||||
.begin_token = *begin_token,
|
||||
.end_token = undefined,
|
||||
.label = *label,
|
||||
.lbrace = *lbrace,
|
||||
.statements = ArrayList(&ast.Node).init(arena),
|
||||
.rbrace = undefined,
|
||||
};
|
||||
return node;
|
||||
}
|
||||
@ -2340,6 +2410,10 @@ pub const Parser = struct {
|
||||
},
|
||||
ast.Node.Id.Block => {
|
||||
const block = @fieldParentPtr(ast.NodeBlock, "base", base);
|
||||
if (block.label) |label| {
|
||||
try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
|
||||
}
|
||||
|
||||
if (block.statements.len == 0) {
|
||||
try stream.write("{}");
|
||||
} else {
|
||||
@ -2747,6 +2821,8 @@ pub const Parser = struct {
|
||||
},
|
||||
ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"),
|
||||
ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
|
||||
ast.Node.Id.Switch => @panic("TODO switch"),
|
||||
ast.Node.Id.SwitchCase => @panic("TODO switch case"),
|
||||
|
||||
ast.Node.Id.StructField,
|
||||
ast.Node.Id.UnionTag,
|
||||
@ -2791,6 +2867,9 @@ pub const Parser = struct {
|
||||
const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", base);
|
||||
try stack.append(RenderState { .VarDecl = var_decl});
|
||||
},
|
||||
ast.Node.Id.Block => {
|
||||
try stack.append(RenderState { .Expression = base});
|
||||
},
|
||||
else => {
|
||||
try stack.append(RenderState { .Text = ";"});
|
||||
try stack.append(RenderState { .Expression = base});
|
||||
@ -3323,6 +3402,28 @@ test "zig fmt: catch" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: blocks" {
|
||||
try testCanonical(
|
||||
\\test "blocks" {
|
||||
\\ {
|
||||
\\ const a = 0;
|
||||
\\ const b = 0;
|
||||
\\ }
|
||||
\\
|
||||
\\ blk: {
|
||||
\\ const a = 0;
|
||||
\\ const b = 0;
|
||||
\\ }
|
||||
\\
|
||||
\\ const r = blk: {
|
||||
\\ const a = 0;
|
||||
\\ const b = 0;
|
||||
\\ };
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: switch" {
|
||||
try testCanonical(
|
||||
\\test "switch" {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user