Commit 290dc5d95b

Andrew Kelley <andrew@ziglang.org>
2019-12-21 19:44:00
zig fmt support for slice sentinel syntax
1 parent ce44477
Changed files (5)
lib/std/zig/ast.zig
@@ -1701,6 +1701,7 @@ pub const Node = struct {
             pub const Slice = struct {
                 start: *Node,
                 end: ?*Node,
+                sentinel: ?*Node,
             };
         };
 
@@ -1732,6 +1733,10 @@ pub const Node = struct {
                         if (i < 1) return end;
                         i -= 1;
                     }
+                    if (range.sentinel) |sentinel| {
+                        if (i < 1) return sentinel;
+                        i -= 1;
+                    }
                 },
                 .ArrayInitializer => |*exprs| {
                     if (i < exprs.len) return exprs.at(i).*;
lib/std/zig/parse.zig
@@ -2331,7 +2331,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
 }
 
 /// SuffixOp
-///     <- LBRACKET Expr (DOT2 Expr?)? RBRACKET
+///     <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET
 ///      / DOT IDENTIFIER
 ///      / DOTASTERISK
 ///      / DOTQUESTIONMARK
@@ -2349,11 +2349,16 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
 
             if (eatToken(it, .Ellipsis2) != null) {
                 const end_expr = try parseExpr(arena, it, tree);
+                const sentinel: ?*ast.Node = if (eatToken(it, .Colon) != null)
+                    try parseExpr(arena, it, tree)
+                else
+                    null;
                 break :blk OpAndToken{
                     .op = Op{
                         .Slice = Op.Slice{
                             .start = index_expr,
                             .end = end_expr,
+                            .sentinel = sentinel,
                         },
                     },
                     .token = try expectToken(it, tree, .RBracket),
lib/std/zig/parser_test.zig
@@ -419,10 +419,13 @@ test "zig fmt: pointer of unknown length" {
 test "zig fmt: spaces around slice operator" {
     try testCanonical(
         \\var a = b[c..d];
+        \\var a = b[c..d :0];
         \\var a = b[c + 1 .. d];
         \\var a = b[c + 1 ..];
         \\var a = b[c .. d + 1];
+        \\var a = b[c .. d + 1 :0];
         \\var a = b[c.a..d.e];
+        \\var a = b[c.a..d.e :0];
         \\
     );
 }
lib/std/zig/render.zig
@@ -689,7 +689,13 @@ fn renderExpression(
                     try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space);
                     try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
                     if (range.end) |end| {
-                        try renderExpression(allocator, stream, tree, indent, start_col, end, Space.None);
+                        const after_end_space = if (range.sentinel != null) Space.Space else Space.None;
+                        try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);
+                    }
+                    if (range.sentinel) |sentinel| {
+                        const colon = tree.prevToken(sentinel.firstToken());
+                        try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
+                        try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
                     }
                     return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
                 },
test/stage1/behavior/slice.zig
@@ -78,3 +78,22 @@ test "access len index of sentinel-terminated slice" {
     S.doTheTest();
     comptime S.doTheTest();
 }
+
+test "obtaining a null terminated slice" {
+    // here we have a normal array
+    var buf: [50]u8 = undefined;
+
+    buf[0] = 'a';
+    buf[1] = 'b';
+    buf[2] = 'c';
+    buf[3] = 0;
+
+    // now we obtain a null terminated slice:
+    const ptr = buf[0..3 :0];
+
+    var runtime_len: usize = 3;
+    const ptr2 = buf[0..runtime_len :0];
+    // ptr2 is a null-terminated slice
+    comptime expect(@TypeOf(ptr2) == [:0]u8);
+    comptime expect(@TypeOf(ptr2[0..2]) == []u8);
+}