zig fmt: implement pointer types

rename PtrType => PtrTypeBitRange, SliceType => PtrType

This rename was done as the current SliceType is used for non-bitrange
pointers as well as slices and because PtrTypeSentinel/PtrTypeAligned
are also used for slices. Therefore using the same Ptr prefix for all
these pointer/slice nodes is an improvement.
This commit is contained in:
Isaac Freund 2021-02-06 22:55:29 +01:00 committed by Andrew Kelley
parent d898945786
commit 33915cb1ed
4 changed files with 308 additions and 140 deletions

View File

@ -387,10 +387,22 @@ pub const Tree = struct {
}
},
.PtrTypeAligned => unreachable, // TODO
.PtrTypeSentinel => unreachable, // TODO
.PtrType => unreachable, // TODO
.SliceType => unreachable, // TODO
.PtrTypeAligned,
.PtrTypeSentinel,
.PtrType,
.PtrTypeBitRange,
=> {
const main_token = main_tokens[n];
return switch (token_tags[main_token]) {
.Asterisk => switch (token_tags[main_token - 1]) {
.LBrace => main_token - 1,
else => main_token,
},
.LBrace => main_token,
else => unreachable,
};
},
.SwitchCaseMulti => unreachable, // TODO
.WhileSimple => unreachable, // TODO
.WhileCont => unreachable, // TODO
@ -477,6 +489,10 @@ pub const Tree = struct {
.IfSimple,
.WhileSimple,
.FnDecl,
.PtrTypeAligned,
.PtrTypeSentinel,
.PtrType,
.PtrTypeBitRange,
=> n = datas[n].rhs,
.FieldAccess,
@ -698,10 +714,6 @@ pub const Tree = struct {
.SwitchRange => unreachable, // TODO
.ArrayType => unreachable, // TODO
.ArrayTypeSentinel => unreachable, // TODO
.PtrTypeAligned => unreachable, // TODO
.PtrTypeSentinel => unreachable, // TODO
.PtrType => unreachable, // TODO
.SliceType => unreachable, // TODO
.SwitchCaseMulti => unreachable, // TODO
.WhileCont => unreachable, // TODO
.While => unreachable, // TODO
@ -1028,6 +1040,60 @@ pub const Tree = struct {
};
}
pub fn ptrTypeAligned(tree: Tree, node: Node.Index) Full.PtrType {
assert(tree.nodes.items(.tag)[node] == .PtrTypeAligned);
const data = tree.nodes.items(.data)[node];
return tree.fullPtrType(.{
.main_token = tree.nodes.items(.main_token)[node],
.align_node = data.lhs,
.sentinel = 0,
.bit_range_start = 0,
.bit_range_end = 0,
.child_type = data.rhs,
});
}
pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) Full.PtrType {
assert(tree.nodes.items(.tag)[node] == .PtrTypeSentinel);
const data = tree.nodes.items(.data)[node];
return tree.fullPtrType(.{
.main_token = tree.nodes.items(.main_token)[node],
.align_node = 0,
.sentinel = data.lhs,
.bit_range_start = 0,
.bit_range_end = 0,
.child_type = data.rhs,
});
}
pub fn ptrType(tree: Tree, node: Node.Index) Full.PtrType {
assert(tree.nodes.items(.tag)[node] == .PtrType);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.PtrType);
return tree.fullPtrType(.{
.main_token = tree.nodes.items(.main_token)[node],
.align_node = extra.align_node,
.sentinel = extra.sentinel,
.bit_range_start = 0,
.bit_range_end = 0,
.child_type = data.rhs,
});
}
pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) Full.PtrType {
assert(tree.nodes.items(.tag)[node] == .PtrTypeBitRange);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.PtrTypeBitRange);
return tree.fullPtrType(.{
.main_token = tree.nodes.items(.main_token)[node],
.align_node = extra.align_node,
.sentinel = extra.sentinel,
.bit_range_start = extra.bit_range_start,
.bit_range_end = extra.bit_range_end,
.child_type = data.rhs,
});
}
pub fn containerDeclTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.ContainerDecl {
assert(tree.nodes.items(.tag)[node] == .ContainerDeclTwo or
tree.nodes.items(.tag)[node] == .ContainerDeclTwoComma);
@ -1195,6 +1261,64 @@ pub const Tree = struct {
return result;
}
fn fullPtrType(tree: Tree, info: Full.PtrType.Ast) Full.PtrType {
const token_tags = tree.tokens.items(.tag);
// TODO: looks like stage1 isn't quite smart enough to handle enum
// literals in some places here
const Kind = Full.PtrType.Kind;
const kind: Kind = switch (token_tags[info.main_token]) {
.Asterisk => switch (token_tags[info.main_token + 1]) {
.RBracket => .many,
.Colon => .sentinel,
.Identifier => if (token_tags[info.main_token - 1] == .LBracket) Kind.c else .one,
else => .one,
},
.LBracket => switch (token_tags[info.main_token + 1]) {
.RBracket => Kind.slice,
.Colon => .slice_sentinel,
else => unreachable,
},
else => unreachable,
};
var result: Full.PtrType = .{
.kind = kind,
.allowzero_token = null,
.const_token = null,
.volatile_token = null,
.ast = info,
};
// We need to be careful that we don't iterate over any sub-expressions
// here while looking for modifiers as that could result in false
// positives. Therefore, start after a sentinel if there is one and
// skip over any align node and bit range nodes.
var i = if (kind == .sentinel or kind == .slice_sentinel) blk: {
assert(info.sentinel != 0);
break :blk tree.lastToken(info.sentinel) + 1;
} else blk: {
assert(info.sentinel == 0);
break :blk info.main_token;
};
const end = tree.firstToken(info.child_type);
while (i < end) : (i += 1) {
switch (token_tags[i]) {
.Keyword_allowzero => result.allowzero_token = i,
.Keyword_const => result.const_token = i,
.Keyword_volatile => result.volatile_token = i,
.Keyword_align => {
assert(info.align_node != 0);
if (info.bit_range_end != 0) {
assert(info.bit_range_start != 0);
i = tree.lastToken(info.bit_range_end) + 1;
} else {
i = tree.lastToken(info.align_node) + 1;
}
},
else => {},
}
}
return result;
}
fn fullContainerDecl(tree: Tree, info: Full.ContainerDecl.Ast) Full.ContainerDecl {
const token_tags = tree.tokens.items(.tag);
var result: Full.ContainerDecl = .{
@ -1302,6 +1426,32 @@ pub const Full = struct {
};
};
pub const PtrType = struct {
kind: Kind,
allowzero_token: ?TokenIndex,
const_token: ?TokenIndex,
volatile_token: ?TokenIndex,
ast: Ast,
pub const Kind = enum {
one,
many,
sentinel,
c,
slice,
slice_sentinel,
};
pub const Ast = struct {
main_token: TokenIndex,
align_node: Node.Index,
sentinel: Node.Index,
bit_range_start: Node.Index,
bit_range_end: Node.Index,
child_type: Node.Index,
};
};
pub const ContainerDecl = struct {
layout_token: ?TokenIndex,
ast: Ast,
@ -1696,16 +1846,19 @@ pub const Node = struct {
/// `[*]align(lhs) rhs`. lhs can be omitted.
/// `*align(lhs) rhs`. lhs can be omitted.
/// `[]rhs`.
/// main_token is the asterisk if a pointer or the lbrace if a slice
PtrTypeAligned,
/// `[*:lhs]rhs`. lhs can be omitted.
/// `*rhs`.
/// `[:lhs]rhs`.
/// main_token is the asterisk if a pointer or the lbrace if a slice
PtrTypeSentinel,
/// lhs is index into PtrType. rhs is the element type expression.
/// main_token is the asterisk if a pointer or the lbrace if a slice
PtrType,
/// lhs is index into SliceType. rhs is the element type expression.
/// Can be pointer or slice, depending on main_token.
SliceType,
/// lhs is index into PtrTypeBitRange. rhs is the element type expression.
/// main_token is the asterisk if a pointer or the lbrace if a slice
PtrTypeBitRange,
/// `lhs[rhs..]`
/// main_token is the `[`.
SliceOpen,
@ -1954,14 +2107,15 @@ pub const Node = struct {
pub const PtrType = struct {
sentinel: Index,
align_node: Index,
};
pub const PtrTypeBitRange = struct {
sentinel: Index,
align_node: Index,
bit_range_start: Index,
bit_range_end: Index,
};
pub const SliceType = struct {
sentinel: Index,
align_node: Index,
};
pub const SubRange = struct {
/// Index into sub_list.
start: Index,

View File

@ -1618,10 +1618,10 @@ const Parser = struct {
});
} else {
return p.addNode(.{
.tag = .PtrType,
.tag = .PtrTypeBitRange,
.main_token = asterisk,
.data = .{
.lhs = try p.addExtra(Node.PtrType{
.lhs = try p.addExtra(Node.PtrTypeBitRange{
.sentinel = 0,
.align_node = mods.align_node,
.bit_range_start = mods.bit_range_start,
@ -1648,10 +1648,10 @@ const Parser = struct {
});
} else {
break :inner try p.addNode(.{
.tag = .PtrType,
.tag = .PtrTypeBitRange,
.main_token = asterisk,
.data = .{
.lhs = try p.addExtra(Node.PtrType{
.lhs = try p.addExtra(Node.PtrTypeBitRange{
.sentinel = 0,
.align_node = mods.align_node,
.bit_range_start = mods.bit_range_start,
@ -1713,10 +1713,10 @@ const Parser = struct {
});
} else {
return p.addNode(.{
.tag = .SliceType,
.tag = .PtrType,
.main_token = asterisk,
.data = .{
.lhs = try p.addExtra(.{
.lhs = try p.addExtra(Node.PtrType{
.sentinel = sentinel,
.align_node = mods.align_node,
}),
@ -1726,10 +1726,10 @@ const Parser = struct {
}
} else {
return p.addNode(.{
.tag = .PtrType,
.tag = .PtrTypeBitRange,
.main_token = asterisk,
.data = .{
.lhs = try p.addExtra(.{
.lhs = try p.addExtra(Node.PtrTypeBitRange{
.sentinel = sentinel,
.align_node = mods.align_node,
.bit_range_start = mods.bit_range_start,
@ -1777,10 +1777,10 @@ const Parser = struct {
});
} else {
return p.addNode(.{
.tag = .SliceType,
.tag = .PtrType,
.main_token = lbracket,
.data = .{
.lhs = try p.addExtra(.{
.lhs = try p.addExtra(Node.PtrType{
.sentinel = sentinel,
.align_node = mods.align_node,
}),

View File

@ -345,7 +345,59 @@ test "zig fmt: builtin call with trailing comma" {
// \\
// );
//}
//
test "zig fmt: pointer-to-one with modifiers" {
try testCanonical(
\\const x: *u32 = undefined;
\\const y: *allowzero align(8) const volatile u32 = undefined;
\\const z: *allowzero align(8:4:2) const volatile u32 = undefined;
\\
);
}
test "zig fmt: pointer-to-many with modifiers" {
try testCanonical(
\\const x: [*]u32 = undefined;
\\const y: [*]allowzero align(8) const volatile u32 = undefined;
\\const z: [*]allowzero align(8:4:2) const volatile u32 = undefined;
\\
);
}
test "zig fmt: sentinel pointer with modifiers" {
try testCanonical(
\\const x: [*:42]u32 = undefined;
\\const y: [*:42]allowzero align(8) const volatile u32 = undefined;
\\const y: [*:42]allowzero align(8:4:2) const volatile u32 = undefined;
\\
);
}
test "zig fmt: c pointer with modifiers" {
try testCanonical(
\\const x: [*c]u32 = undefined;
\\const y: [*c]allowzero align(8) const volatile u32 = undefined;
\\const z: [*c]allowzero align(8:4:2) const volatile u32 = undefined;
\\
);
}
test "zig fmt: slice with modifiers" {
try testCanonical(
\\const x: []u32 = undefined;
\\const y: []allowzero align(8) const volatile u32 = undefined;
\\
);
}
test "zig fmt: sentinel slice with modifiers" {
try testCanonical(
\\const x: [:42]u32 = undefined;
\\const y: [:42]allowzero align(8) const volatile u32 = undefined;
\\
);
}
//test "zig fmt: anon literal in array" {
// try testCanonical(
// \\var arr: [2]Foo = .{

View File

@ -370,120 +370,10 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
.ArrayType => return renderArrayType(ais, tree, tree.arrayType(node), space),
.ArrayTypeSentinel => return renderArrayType(ais, tree, tree.arrayTypeSentinel(node), space),
.PtrType => unreachable, // TODO
.PtrTypeAligned => unreachable, // TODO
.PtrTypeSentinel => unreachable, // TODO
//.PtrType => {
// const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
// const op_tok_id = tree.token_tags[ptr_type.op_token];
// switch (op_tok_id) {
// .Asterisk, .AsteriskAsterisk => try ais.writer().writeByte('*'),
// .LBracket => if (tree.token_tags[ptr_type.op_token + 2] == .Identifier)
// try ais.writer().writeAll("[*c")
// else
// try ais.writer().writeAll("[*"),
// else => unreachable,
// }
// if (ptr_type.ptr_info.sentinel) |sentinel| {
// const colon_token = tree.prevToken(sentinel.firstToken());
// try renderToken(ais, tree, colon_token, Space.None); // :
// const sentinel_space = switch (op_tok_id) {
// .LBracket => Space.None,
// else => Space.Space,
// };
// try renderExpression(ais, tree, sentinel, sentinel_space);
// }
// switch (op_tok_id) {
// .Asterisk, .AsteriskAsterisk => {},
// .LBracket => try ais.writer().writeByte(']'),
// else => unreachable,
// }
// if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {
// try renderToken(ais, tree, allowzero_token, Space.Space); // allowzero
// }
// if (ptr_type.ptr_info.align_info) |align_info| {
// const lparen_token = tree.prevToken(align_info.node.firstToken());
// const align_token = tree.prevToken(lparen_token);
// try renderToken(ais, tree, align_token, Space.None); // align
// try renderToken(ais, tree, lparen_token, Space.None); // (
// try renderExpression(ais, tree, align_info.node, Space.None);
// if (align_info.bit_range) |bit_range| {
// const colon1 = tree.prevToken(bit_range.start.firstToken());
// const colon2 = tree.prevToken(bit_range.end.firstToken());
// try renderToken(ais, tree, colon1, Space.None); // :
// try renderExpression(ais, tree, bit_range.start, Space.None);
// try renderToken(ais, tree, colon2, Space.None); // :
// try renderExpression(ais, tree, bit_range.end, Space.None);
// const rparen_token = tree.nextToken(bit_range.end.lastToken());
// try renderToken(ais, tree, rparen_token, Space.Space); // )
// } else {
// const rparen_token = tree.nextToken(align_info.node.lastToken());
// try renderToken(ais, tree, rparen_token, Space.Space); // )
// }
// }
// if (ptr_type.ptr_info.const_token) |const_token| {
// try renderToken(ais, tree, const_token, Space.Space); // const
// }
// if (ptr_type.ptr_info.volatile_token) |volatile_token| {
// try renderToken(ais, tree, volatile_token, Space.Space); // volatile
// }
// return renderExpression(ais, tree, ptr_type.rhs, space);
//},
.SliceType => unreachable, // TODO
//.SliceType => {
// const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
// try renderToken(ais, tree, slice_type.op_token, Space.None); // [
// if (slice_type.ptr_info.sentinel) |sentinel| {
// const colon_token = tree.prevToken(sentinel.firstToken());
// try renderToken(ais, tree, colon_token, Space.None); // :
// try renderExpression(ais, tree, sentinel, Space.None);
// try renderToken(ais, tree, tree.nextToken(sentinel.lastToken()), Space.None); // ]
// } else {
// try renderToken(ais, tree, tree.nextToken(slice_type.op_token), Space.None); // ]
// }
// if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
// try renderToken(ais, tree, allowzero_token, Space.Space); // allowzero
// }
// if (slice_type.ptr_info.align_info) |align_info| {
// const lparen_token = tree.prevToken(align_info.node.firstToken());
// const align_token = tree.prevToken(lparen_token);
// try renderToken(ais, tree, align_token, Space.None); // align
// try renderToken(ais, tree, lparen_token, Space.None); // (
// try renderExpression(ais, tree, align_info.node, Space.None);
// if (align_info.bit_range) |bit_range| {
// const colon1 = tree.prevToken(bit_range.start.firstToken());
// const colon2 = tree.prevToken(bit_range.end.firstToken());
// try renderToken(ais, tree, colon1, Space.None); // :
// try renderExpression(ais, tree, bit_range.start, Space.None);
// try renderToken(ais, tree, colon2, Space.None); // :
// try renderExpression(ais, tree, bit_range.end, Space.None);
// const rparen_token = tree.nextToken(bit_range.end.lastToken());
// try renderToken(ais, tree, rparen_token, Space.Space); // )
// } else {
// const rparen_token = tree.nextToken(align_info.node.lastToken());
// try renderToken(ais, tree, rparen_token, Space.Space); // )
// }
// }
// if (slice_type.ptr_info.const_token) |const_token| {
// try renderToken(ais, tree, const_token, Space.Space);
// }
// if (slice_type.ptr_info.volatile_token) |volatile_token| {
// try renderToken(ais, tree, volatile_token, Space.Space);
// }
// return renderExpression(ais, tree, slice_type.rhs, space);
//},
.PtrTypeAligned => return renderPtrType(ais, tree, tree.ptrTypeAligned(node), space),
.PtrTypeSentinel => return renderPtrType(ais, tree, tree.ptrTypeSentinel(node), space),
.PtrType => return renderPtrType(ais, tree, tree.ptrType(node), space),
.PtrTypeBitRange => return renderPtrType(ais, tree, tree.ptrTypeBitRange(node), space),
.ArrayInitOne => {
var elements: [1]ast.Node.Index = undefined;
@ -1180,6 +1070,78 @@ fn renderArrayType(
return renderExpression(ais, tree, array_type.ast.elem_type, space);
}
fn renderPtrType(
ais: *Ais,
tree: ast.Tree,
ptr_type: ast.Full.PtrType,
space: Space,
) Error!void {
switch (ptr_type.kind) {
.one => {
try renderToken(ais, tree, ptr_type.ast.main_token, .None); // asterisk
},
.many => {
try renderToken(ais, tree, ptr_type.ast.main_token - 1, .None); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token, .None); // asterisk
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // rbracket
},
.sentinel => {
try renderToken(ais, tree, ptr_type.ast.main_token - 1, .None); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token, .None); // asterisk
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // colon
try renderExpression(ais, tree, ptr_type.ast.sentinel, .None);
try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .None); // rbracket
},
.c => {
try renderToken(ais, tree, ptr_type.ast.main_token - 1, .None); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token, .None); // asterisk
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // c
try renderToken(ais, tree, ptr_type.ast.main_token + 2, .None); // rbracket
},
.slice => {
try renderToken(ais, tree, ptr_type.ast.main_token, .None); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // rbracket
},
.slice_sentinel => {
try renderToken(ais, tree, ptr_type.ast.main_token, .None); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // colon
try renderExpression(ais, tree, ptr_type.ast.sentinel, .None);
try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .None); // rbracket
},
}
if (ptr_type.allowzero_token) |allowzero_token| {
try renderToken(ais, tree, allowzero_token, .Space);
}
if (ptr_type.ast.align_node != 0) {
const align_first = tree.firstToken(ptr_type.ast.align_node);
try renderToken(ais, tree, align_first - 2, .None); // align
try renderToken(ais, tree, align_first - 1, .None); // lparen
try renderExpression(ais, tree, ptr_type.ast.align_node, .None);
if (ptr_type.ast.bit_range_start != 0) {
assert(ptr_type.ast.bit_range_end != 0);
try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_start) - 1, .None); // colon
try renderExpression(ais, tree, ptr_type.ast.bit_range_start, .None);
try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_end) - 1, .None); // colon
try renderExpression(ais, tree, ptr_type.ast.bit_range_end, .None);
try renderToken(ais, tree, tree.lastToken(ptr_type.ast.bit_range_end) + 1, .Space); // rparen
} else {
try renderToken(ais, tree, tree.lastToken(ptr_type.ast.align_node) + 1, .Space); // rparen
}
}
if (ptr_type.const_token) |const_token| {
try renderToken(ais, tree, const_token, .Space);
}
if (ptr_type.volatile_token) |volatile_token| {
try renderToken(ais, tree, volatile_token, .Space);
}
try renderExpression(ais, tree, ptr_type.ast.child_type, space);
}
fn renderAsmOutput(
allocator: *mem.Allocator,
ais: *Ais,