| author | |
| committer | |
| log | 290dc5d95b986464a5be91bb3fd0ada2dd0840ae |
| tree | 1e004f521047ead2fb52855da7bc4fa819020548 |
| parent | ce444771c5a4da1d6caab0959e5c8dd5f2df820e |
| signature | Commit is signed but in an unrecognized format. |
5 files changed, 40 insertions(+), 2 deletions(-)
lib/std/zig/ast.zig+5| ... | ... | @@ -1701,6 +1701,7 @@ pub const Node = struct { |
| 1701 | 1701 | pub const Slice = struct { |
| 1702 | 1702 | start: *Node, |
| 1703 | 1703 | end: ?*Node, |
| 1704 | sentinel: ?*Node, | |
| 1704 | 1705 | }; |
| 1705 | 1706 | }; |
| 1706 | 1707 | |
| ... | ... | @@ -1732,6 +1733,10 @@ pub const Node = struct { |
| 1732 | 1733 | if (i < 1) return end; |
| 1733 | 1734 | i -= 1; |
| 1734 | 1735 | } |
| 1736 | if (range.sentinel) |sentinel| { | |
| 1737 | if (i < 1) return sentinel; | |
| 1738 | i -= 1; | |
| 1739 | } | |
| 1735 | 1740 | }, |
| 1736 | 1741 | .ArrayInitializer => |*exprs| { |
| 1737 | 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 | 2331 | } |
| 2332 | 2332 | |
| 2333 | 2333 | /// SuffixOp |
| 2334 | /// <- LBRACKET Expr (DOT2 Expr?)? RBRACKET | |
| 2334 | /// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET | |
| 2335 | 2335 | /// / DOT IDENTIFIER |
| 2336 | 2336 | /// / DOTASTERISK |
| 2337 | 2337 | /// / DOTQUESTIONMARK |
| ... | ... | @@ -2349,11 +2349,16 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2349 | 2349 | |
| 2350 | 2350 | if (eatToken(it, .Ellipsis2) != null) { |
| 2351 | 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 | 2356 | break :blk OpAndToken{ |
| 2353 | 2357 | .op = Op{ |
| 2354 | 2358 | .Slice = Op.Slice{ |
| 2355 | 2359 | .start = index_expr, |
| 2356 | 2360 | .end = end_expr, |
| 2361 | .sentinel = sentinel, | |
| 2357 | 2362 | }, |
| 2358 | 2363 | }, |
| 2359 | 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 | 419 | test "zig fmt: spaces around slice operator" { |
| 420 | 420 | try testCanonical( |
| 421 | 421 | \\var a = b[c..d]; |
| 422 | \\var a = b[c..d :0]; | |
| 422 | 423 | \\var a = b[c + 1 .. d]; |
| 423 | 424 | \\var a = b[c + 1 ..]; |
| 424 | 425 | \\var a = b[c .. d + 1]; |
| 426 | \\var a = b[c .. d + 1 :0]; | |
| 425 | 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 | 689 | try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space); |
| 690 | 690 | try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // .. |
| 691 | 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 | 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 | 78 | S.doTheTest(); |
| 79 | 79 | comptime S.doTheTest(); |
| 80 | 80 | } |
| 81 | ||
| 82 | test "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 | } |