authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-21 13:44:00-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-21 14:03:36-05:00
log290dc5d95b986464a5be91bb3fd0ada2dd0840ae
tree1e004f521047ead2fb52855da7bc4fa819020548
parentce444771c5a4da1d6caab0959e5c8dd5f2df820e
signaturelock-open Commit is signed but in an unrecognized format.

zig fmt support for slice sentinel syntax


5 files changed, 40 insertions(+), 2 deletions(-)

lib/std/zig/ast.zig+5
...@@ -1701,6 +1701,7 @@ pub const Node = struct {...@@ -1701,6 +1701,7 @@ pub const Node = struct {
1701 pub const Slice = struct {1701 pub const Slice = struct {
1702 start: *Node,1702 start: *Node,
1703 end: ?*Node,1703 end: ?*Node,
1704 sentinel: ?*Node,
1704 };1705 };
1705 };1706 };
17061707
...@@ -1732,6 +1733,10 @@ pub const Node = struct {...@@ -1732,6 +1733,10 @@ pub const Node = struct {
1732 if (i < 1) return end;1733 if (i < 1) return end;
1733 i -= 1;1734 i -= 1;
1734 }1735 }
1736 if (range.sentinel) |sentinel| {
1737 if (i < 1) return sentinel;
1738 i -= 1;
1739 }
1735 },1740 },
1736 .ArrayInitializer => |*exprs| {1741 .ArrayInitializer => |*exprs| {
1737 if (i < exprs.len) return exprs.at(i).*;1742 if (i < exprs.len) return exprs.at(i).*;
lib/std/zig/parse.zig+6-1
...@@ -2331,7 +2331,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2331,7 +2331,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2331}2331}
23322332
2333/// SuffixOp2333/// SuffixOp
2334/// <- LBRACKET Expr (DOT2 Expr?)? RBRACKET2334/// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET
2335/// / DOT IDENTIFIER2335/// / DOT IDENTIFIER
2336/// / DOTASTERISK2336/// / DOTASTERISK
2337/// / DOTQUESTIONMARK2337/// / DOTQUESTIONMARK
...@@ -2349,11 +2349,16 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2349,11 +2349,16 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
23492349
2350 if (eatToken(it, .Ellipsis2) != null) {2350 if (eatToken(it, .Ellipsis2) != null) {
2351 const end_expr = try parseExpr(arena, it, tree);2351 const end_expr = try parseExpr(arena, it, tree);
2352 const sentinel: ?*ast.Node = if (eatToken(it, .Colon) != null)
2353 try parseExpr(arena, it, tree)
2354 else
2355 null;
2352 break :blk OpAndToken{2356 break :blk OpAndToken{
2353 .op = Op{2357 .op = Op{
2354 .Slice = Op.Slice{2358 .Slice = Op.Slice{
2355 .start = index_expr,2359 .start = index_expr,
2356 .end = end_expr,2360 .end = end_expr,
2361 .sentinel = sentinel,
2357 },2362 },
2358 },2363 },
2359 .token = try expectToken(it, tree, .RBracket),2364 .token = try expectToken(it, tree, .RBracket),
lib/std/zig/parser_test.zig+3
...@@ -419,10 +419,13 @@ test "zig fmt: pointer of unknown length" {...@@ -419,10 +419,13 @@ test "zig fmt: pointer of unknown length" {
419test "zig fmt: spaces around slice operator" {419test "zig fmt: spaces around slice operator" {
420 try testCanonical(420 try testCanonical(
421 \\var a = b[c..d];421 \\var a = b[c..d];
422 \\var a = b[c..d :0];
422 \\var a = b[c + 1 .. d];423 \\var a = b[c + 1 .. d];
423 \\var a = b[c + 1 ..];424 \\var a = b[c + 1 ..];
424 \\var a = b[c .. d + 1];425 \\var a = b[c .. d + 1];
426 \\var a = b[c .. d + 1 :0];
425 \\var a = b[c.a..d.e];427 \\var a = b[c.a..d.e];
428 \\var a = b[c.a..d.e :0];
426 \\429 \\
427 );430 );
428}431}
lib/std/zig/render.zig+7-1
...@@ -689,7 +689,13 @@ fn renderExpression(...@@ -689,7 +689,13 @@ fn renderExpression(
689 try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space);689 try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space);
690 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..690 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
691 if (range.end) |end| {691 if (range.end) |end| {
692 try renderExpression(allocator, stream, tree, indent, start_col, end, Space.None);692 const after_end_space = if (range.sentinel != null) Space.Space else Space.None;
693 try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);
694 }
695 if (range.sentinel) |sentinel| {
696 const colon = tree.prevToken(sentinel.firstToken());
697 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
698 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
693 }699 }
694 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]700 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
695 },701 },
test/stage1/behavior/slice.zig+19
...@@ -78,3 +78,22 @@ test "access len index of sentinel-terminated slice" {...@@ -78,3 +78,22 @@ test "access len index of sentinel-terminated slice" {
78 S.doTheTest();78 S.doTheTest();
79 comptime S.doTheTest();79 comptime S.doTheTest();
80}80}
81
82test "obtaining a null terminated slice" {
83 // here we have a normal array
84 var buf: [50]u8 = undefined;
85
86 buf[0] = 'a';
87 buf[1] = 'b';
88 buf[2] = 'c';
89 buf[3] = 0;
90
91 // now we obtain a null terminated slice:
92 const ptr = buf[0..3 :0];
93
94 var runtime_len: usize = 3;
95 const ptr2 = buf[0..runtime_len :0];
96 // ptr2 is a null-terminated slice
97 comptime expect(@TypeOf(ptr2) == [:0]u8);
98 comptime expect(@TypeOf(ptr2[0..2]) == []u8);
99}