From 33915cb1ed88417d3495c160ffd15c93f9197e5b Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 6 Feb 2021 22:55:29 +0100 Subject: [PATCH] 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. --- lib/std/zig/ast.zig | 184 +++++++++++++++++++++++++++++++--- lib/std/zig/parse.zig | 20 ++-- lib/std/zig/parser_test.zig | 54 +++++++++- lib/std/zig/render.zig | 190 +++++++++++++++--------------------- 4 files changed, 308 insertions(+), 140 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 5d65fc5ae6..0fdcf0a4d6 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -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, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 1143c9f9c0..c6cec8a195 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -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, }), diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 65843f9b5f..95299b8d94 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -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 = .{ diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index d873676d53..ba2158ff4e 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -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,