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:
Isaac Freund 2021-03-07 12:38:08 +01:00
parent d01bb21173
commit b988815bf0
5 changed files with 43 additions and 37 deletions

View File

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

View File

@ -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(.{

View File

@ -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];
\\
);

View File

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

View File

@ -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);
}