mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
parser: fix parsing/rendering of a[b.. :c] slicing
The modification to the grammar in the comment is in line with the
grammar in the zig-spec repo.
Note: checking if the previous token is a colon is insufficent to tell
if a block has a label, the identifier must be checked for as well. This
can be seen in sentinel terminated slicing: `foo[0..1:{}]`
This commit is contained in:
parent
d01bb21173
commit
b988815bf0
@ -525,7 +525,9 @@ pub const Tree = struct {
|
||||
=> {
|
||||
// Look for a label.
|
||||
const lbrace = main_tokens[n];
|
||||
if (token_tags[lbrace - 1] == .colon) {
|
||||
if (token_tags[lbrace - 1] == .colon and
|
||||
token_tags[lbrace - 2] == .identifier)
|
||||
{
|
||||
end_offset += 2;
|
||||
}
|
||||
return lbrace - end_offset;
|
||||
@ -989,13 +991,13 @@ pub const Tree = struct {
|
||||
},
|
||||
.slice => {
|
||||
const extra = tree.extraData(datas[n].rhs, Node.Slice);
|
||||
assert(extra.end != 0); // should have used SliceOpen
|
||||
assert(extra.end != 0); // should have used slice_open
|
||||
end_offset += 1; // rbracket
|
||||
n = extra.end;
|
||||
},
|
||||
.slice_sentinel => {
|
||||
const extra = tree.extraData(datas[n].rhs, Node.SliceSentinel);
|
||||
assert(extra.sentinel != 0); // should have used Slice
|
||||
assert(extra.sentinel != 0); // should have used slice
|
||||
end_offset += 1; // rbracket
|
||||
n = extra.sentinel;
|
||||
},
|
||||
@ -2925,6 +2927,7 @@ pub const Node = struct {
|
||||
|
||||
pub const SliceSentinel = struct {
|
||||
start: Index,
|
||||
/// May be 0 if the slice is "open"
|
||||
end: Index,
|
||||
sentinel: Index,
|
||||
};
|
||||
|
||||
@ -3441,7 +3441,7 @@ const Parser = struct {
|
||||
}
|
||||
|
||||
/// SuffixOp
|
||||
/// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET
|
||||
/// <- LBRACKET Expr (DOT2 (Expr? (COLON Expr)?)?)? RBRACKET
|
||||
/// / DOT IDENTIFIER
|
||||
/// / DOTASTERISK
|
||||
/// / DOTQUESTIONMARK
|
||||
@ -3453,17 +3453,6 @@ const Parser = struct {
|
||||
|
||||
if (p.eatToken(.ellipsis2)) |_| {
|
||||
const end_expr = try p.parseExpr();
|
||||
if (end_expr == 0) {
|
||||
_ = try p.expectToken(.r_bracket);
|
||||
return p.addNode(.{
|
||||
.tag = .slice_open,
|
||||
.main_token = lbracket,
|
||||
.data = .{
|
||||
.lhs = lhs,
|
||||
.rhs = index_expr,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (p.eatToken(.colon)) |_| {
|
||||
const sentinel = try p.parseExpr();
|
||||
_ = try p.expectToken(.r_bracket);
|
||||
@ -3479,20 +3468,29 @@ const Parser = struct {
|
||||
}),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
_ = try p.expectToken(.r_bracket);
|
||||
}
|
||||
_ = try p.expectToken(.r_bracket);
|
||||
if (end_expr == 0) {
|
||||
return p.addNode(.{
|
||||
.tag = .slice,
|
||||
.tag = .slice_open,
|
||||
.main_token = lbracket,
|
||||
.data = .{
|
||||
.lhs = lhs,
|
||||
.rhs = try p.addExtra(Node.Slice{
|
||||
.start = index_expr,
|
||||
.end = end_expr,
|
||||
}),
|
||||
.rhs = index_expr,
|
||||
},
|
||||
});
|
||||
}
|
||||
return p.addNode(.{
|
||||
.tag = .slice,
|
||||
.main_token = lbracket,
|
||||
.data = .{
|
||||
.lhs = lhs,
|
||||
.rhs = try p.addExtra(Node.Slice{
|
||||
.start = index_expr,
|
||||
.end = end_expr,
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
_ = try p.expectToken(.r_bracket);
|
||||
return p.addNode(.{
|
||||
|
||||
@ -852,6 +852,7 @@ test "zig fmt: slices" {
|
||||
try testCanonical(
|
||||
\\const a = b[0..];
|
||||
\\const c = d[0..1];
|
||||
\\const d = f[0.. :0];
|
||||
\\const e = f[0..1 :0];
|
||||
\\
|
||||
);
|
||||
@ -861,6 +862,7 @@ test "zig fmt: slices with spaces in bounds" {
|
||||
try testCanonical(
|
||||
\\const a = b[0 + 0 ..];
|
||||
\\const c = d[0 + 0 .. 1];
|
||||
\\const c = d[0 + 0 .. :0];
|
||||
\\const e = f[0 .. 1 + 1 :0];
|
||||
\\
|
||||
);
|
||||
|
||||
@ -470,9 +470,9 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I
|
||||
return renderToken(ais, tree, rbracket, space); // ]
|
||||
},
|
||||
|
||||
.slice_open => return renderSlice(gpa, ais, tree, tree.sliceOpen(node), space),
|
||||
.slice => return renderSlice(gpa, ais, tree, tree.slice(node), space),
|
||||
.slice_sentinel => return renderSlice(gpa, ais, tree, tree.sliceSentinel(node), space),
|
||||
.slice_open => return renderSlice(gpa, ais, tree, node, tree.sliceOpen(node), space),
|
||||
.slice => return renderSlice(gpa, ais, tree, node, tree.slice(node), space),
|
||||
.slice_sentinel => return renderSlice(gpa, ais, tree, node, tree.sliceSentinel(node), space),
|
||||
|
||||
.deref => {
|
||||
try renderExpression(gpa, ais, tree, datas[node].lhs, .none);
|
||||
@ -815,6 +815,7 @@ fn renderSlice(
|
||||
gpa: *Allocator,
|
||||
ais: *Ais,
|
||||
tree: ast.Tree,
|
||||
slice_node: ast.Node.Index,
|
||||
slice: ast.full.Slice,
|
||||
space: Space,
|
||||
) Error!void {
|
||||
@ -822,7 +823,9 @@ fn renderSlice(
|
||||
const after_start_space_bool = nodeCausesSliceOpSpace(node_tags[slice.ast.start]) or
|
||||
if (slice.ast.end != 0) nodeCausesSliceOpSpace(node_tags[slice.ast.end]) else false;
|
||||
const after_start_space = if (after_start_space_bool) Space.space else Space.none;
|
||||
const after_dots_space = if (slice.ast.end != 0) after_start_space else Space.none;
|
||||
const after_dots_space = if (slice.ast.end != 0)
|
||||
after_start_space
|
||||
else if (slice.ast.sentinel != 0) Space.space else Space.none;
|
||||
|
||||
try renderExpression(gpa, ais, tree, slice.ast.sliced, .none);
|
||||
try renderToken(ais, tree, slice.ast.lbracket, .none); // lbracket
|
||||
@ -830,20 +833,18 @@ fn renderSlice(
|
||||
const start_last = tree.lastToken(slice.ast.start);
|
||||
try renderExpression(gpa, ais, tree, slice.ast.start, after_start_space);
|
||||
try renderToken(ais, tree, start_last + 1, after_dots_space); // ellipsis2 ("..")
|
||||
if (slice.ast.end == 0) {
|
||||
return renderToken(ais, tree, start_last + 2, space); // rbracket
|
||||
|
||||
if (slice.ast.end != 0) {
|
||||
const after_end_space = if (slice.ast.sentinel != 0) Space.space else Space.none;
|
||||
try renderExpression(gpa, ais, tree, slice.ast.end, after_end_space);
|
||||
}
|
||||
|
||||
const end_last = tree.lastToken(slice.ast.end);
|
||||
const after_end_space = if (slice.ast.sentinel != 0) Space.space else Space.none;
|
||||
try renderExpression(gpa, ais, tree, slice.ast.end, after_end_space);
|
||||
if (slice.ast.sentinel == 0) {
|
||||
return renderToken(ais, tree, end_last + 1, space); // rbracket
|
||||
if (slice.ast.sentinel != 0) {
|
||||
try renderToken(ais, tree, tree.firstToken(slice.ast.sentinel) - 1, .none); // colon
|
||||
try renderExpression(gpa, ais, tree, slice.ast.sentinel, .none);
|
||||
}
|
||||
|
||||
try renderToken(ais, tree, end_last + 1, .none); // colon
|
||||
try renderExpression(gpa, ais, tree, slice.ast.sentinel, .none);
|
||||
try renderToken(ais, tree, tree.lastToken(slice.ast.sentinel) + 1, space); // rbracket
|
||||
try renderToken(ais, tree, tree.lastToken(slice_node), space); // rbracket
|
||||
}
|
||||
|
||||
fn renderAsmOutput(
|
||||
|
||||
@ -848,7 +848,9 @@ pub fn blockExpr(
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
|
||||
const lbrace = main_tokens[block_node];
|
||||
if (token_tags[lbrace - 1] == .colon) {
|
||||
if (token_tags[lbrace - 1] == .colon and
|
||||
token_tags[lbrace - 2] == .identifier)
|
||||
{
|
||||
return labeledBlockExpr(mod, scope, rl, block_node, statements, .block);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user