Commit 33915cb1ed
Changed files (4)
lib
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,
- bit_range_start: Index,
- bit_range_end: Index,
};
- pub const SliceType = struct {
+ pub const PtrTypeBitRange = struct {
sentinel: Index,
align_node: Index,
+ bit_range_start: Index,
+ bit_range_end: Index,
};
+
pub const SubRange = struct {
/// Index into sub_list.
start: Index,
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,
}),
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 = .{
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,