Commit 0929fcbc34

Isaac Freund <ifreund@ifreund.xyz>
2021-02-07 12:43:53
zig fmt: implement slices
1 parent 33915cb
Changed files (3)
lib/std/zig/ast.zig
@@ -688,6 +688,20 @@ pub const Tree = struct {
                     return main_tokens[n] + end_offset;
                 }
             },
+            .SliceOpen => {
+                end_offset += 2; // ellipsis2 and rbracket
+                n = datas[n].rhs;
+            },
+            .Slice => {
+                const extra = tree.extraData(datas[n].rhs, Node.Slice);
+                if (extra.sentinel != 0) {
+                    n = extra.sentinel;
+                } else {
+                    assert(extra.end != 0); // should have used SliceOpen if end and sentinel are 0
+                    n = extra.end;
+                }
+                end_offset += 1; // rbracket
+            },
 
             // These are not supported by lastToken() because implementation would
             // require recursion due to the optional comma followed by rbrace.
@@ -708,8 +722,6 @@ pub const Tree = struct {
             .ErrorSetDecl => unreachable, // TODO
             .AsmSimple => unreachable, // TODO
             .Asm => unreachable, // TODO
-            .SliceOpen => unreachable, // TODO
-            .Slice => unreachable, // TODO
             .SwitchCaseOne => unreachable, // TODO
             .SwitchRange => unreachable, // TODO
             .ArrayType => unreachable, // TODO
@@ -1094,6 +1106,35 @@ pub const Tree = struct {
         });
     }
 
+    pub fn sliceOpen(tree: Tree, node: Node.Index) Full.Slice {
+        assert(tree.nodes.items(.tag)[node] == .SliceOpen);
+        const data = tree.nodes.items(.data)[node];
+        return .{
+            .ast = .{
+                .sliced = data.lhs,
+                .lbracket = tree.nodes.items(.main_token)[node],
+                .start = data.rhs,
+                .end = 0,
+                .sentinel = 0,
+            },
+        };
+    }
+
+    pub fn slice(tree: Tree, node: Node.Index) Full.Slice {
+        assert(tree.nodes.items(.tag)[node] == .Slice);
+        const data = tree.nodes.items(.data)[node];
+        const extra = tree.extraData(data.rhs, Node.Slice);
+        return .{
+            .ast = .{
+                .sliced = data.lhs,
+                .lbracket = tree.nodes.items(.main_token)[node],
+                .start = extra.start,
+                .end = extra.end,
+                .sentinel = extra.sentinel,
+            },
+        };
+    }
+
     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);
@@ -1452,6 +1493,18 @@ pub const Full = struct {
         };
     };
 
+    pub const Slice = struct {
+        ast: Ast,
+
+        pub const Ast = struct {
+            sliced: Node.Index,
+            lbracket: TokenIndex,
+            start: Node.Index,
+            end: Node.Index,
+            sentinel: Node.Index,
+        };
+    };
+
     pub const ContainerDecl = struct {
         layout_token: ?TokenIndex,
         ast: Ast,
@@ -1860,10 +1913,10 @@ pub const Node = struct {
         /// main_token is the asterisk if a pointer or the lbrace if a slice
         PtrTypeBitRange,
         /// `lhs[rhs..]`
-        /// main_token is the `[`.
+        /// main_token is the lbracket.
         SliceOpen,
-        /// `lhs[b..c :d]`. `slice_list[rhs]`.
-        /// main_token is the `[`.
+        /// `lhs[b..c :d]`. rhs is index into Slice
+        /// main_token is the lbracket.
         Slice,
         /// `lhs.*`. rhs is unused.
         Deref,
lib/std/zig/parser_test.zig
@@ -637,6 +637,24 @@ test "zig fmt: sentinel array literal 1 element" {
     );
 }
 
+test "zig fmt: slices" {
+    try testCanonical(
+        \\const a = b[0..];
+        \\const c = d[0..1];
+        \\const e = f[0..1 :0];
+        \\
+    );
+}
+
+test "zig fmt: slices with spaces in bounds" {
+    try testCanonical(
+        \\const a = b[0 + 0 ..];
+        \\const c = d[0 + 0 .. 1];
+        \\const e = f[0 .. 1 + 1 :0];
+        \\
+    );
+}
+
 //test "zig fmt: async function" {
 //    try testCanonical(
 //        \\pub const Server = struct {
lib/std/zig/render.zig
@@ -466,34 +466,8 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
             return renderToken(ais, tree, rbracket, space); // ]
         },
 
-        .Slice => unreachable, // TODO
-        .SliceOpen => unreachable, // TODO
-        //.Slice => {
-        //    const suffix_op = base.castTag(.Slice).?;
-        //    try renderExpression(ais, tree, suffix_op.lhs, Space.None);
-
-        //    const lbracket = tree.prevToken(suffix_op.start.firstToken());
-        //    const dotdot = tree.nextToken(suffix_op.start.lastToken());
-
-        //    const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or
-        //        (if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false);
-        //    const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
-        //    const after_op_space = if (suffix_op.end != null) after_start_space else Space.None;
-
-        //    try renderToken(ais, tree, lbracket, Space.None); // [
-        //    try renderExpression(ais, tree, suffix_op.start, after_start_space);
-        //    try renderToken(ais, tree, dotdot, after_op_space); // ..
-        //    if (suffix_op.end) |end| {
-        //        const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;
-        //        try renderExpression(ais, tree, end, after_end_space);
-        //    }
-        //    if (suffix_op.sentinel) |sentinel| {
-        //        const colon = tree.prevToken(sentinel.firstToken());
-        //        try renderToken(ais, tree, colon, Space.None); // :
-        //        try renderExpression(ais, tree, sentinel, Space.None);
-        //    }
-        //    return renderToken(ais, tree, suffix_op.rtoken, space); // ]
-        //},
+        .SliceOpen => try renderSlice(ais, tree, tree.sliceOpen(node), space),
+        .Slice => try renderSlice(ais, tree, tree.slice(node), space),
 
         .Deref => {
             try renderExpression(ais, tree, datas[node].lhs, .None);
@@ -1142,6 +1116,40 @@ fn renderPtrType(
     try renderExpression(ais, tree, ptr_type.ast.child_type, space);
 }
 
+fn renderSlice(
+    ais: *Ais,
+    tree: ast.Tree,
+    slice: ast.Full.Slice,
+    space: Space,
+) Error!void {
+    const node_tags = tree.nodes.items(.tag);
+    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;
+
+    try renderExpression(ais, tree, slice.ast.sliced, .None);
+    try renderToken(ais, tree, slice.ast.lbracket, .None); // lbracket
+
+    const start_last = tree.lastToken(slice.ast.start);
+    try renderExpression(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
+    }
+
+    const end_last = tree.lastToken(slice.ast.end);
+    const after_end_space = if (slice.ast.sentinel != 0) Space.Space else Space.None;
+    try renderExpression(ais, tree, slice.ast.end, after_end_space);
+    if (slice.ast.sentinel == 0) {
+        return renderToken(ais, tree, end_last + 1, space); // rbracket
+    }
+
+    try renderToken(ais, tree, end_last + 1, .None); // colon
+    try renderExpression(ais, tree, slice.ast.sentinel, .None);
+    try renderToken(ais, tree, tree.lastToken(slice.ast.sentinel) + 1, space); // rbracket
+}
+
 fn renderAsmOutput(
     allocator: *mem.Allocator,
     ais: *Ais,
@@ -2099,8 +2107,8 @@ fn nodeIsBlock(tag: ast.Node.Tag) bool {
     };
 }
 
-fn nodeCausesSliceOpSpace(base: ast.Node.Index) bool {
-    return switch (base.tag) {
+fn nodeCausesSliceOpSpace(tag: ast.Node.Tag) bool {
+    return switch (tag) {
         .Catch,
         .Add,
         .AddWrap,
@@ -2139,7 +2147,6 @@ fn nodeCausesSliceOpSpace(base: ast.Node.Index) bool {
         .Mod,
         .Mul,
         .MulWrap,
-        .Range,
         .Sub,
         .SubWrap,
         .OrElse,