authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-06-15 13:00:01+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 11:48:58+02:00
loge539f7bbebc8016ea05b9203c8be371db8b2e90d
treed98fcc99e470cd871d8f7b66ee4c44a475080b26
parent153fcc4e9c7dfea91472a9456d95ff5abb3b8649
signaturelock-open Commit is signed but in an unrecognized format.

grammar: forbid && as op without whitespace between

This matches the Parse.zig implementation, which has a special parse error for this case: > ambiguous use of '&&'; use 'and' for logical AND, or change whitespace > to ' & &' for bitwise AND

3 files changed, 20 insertions(+), 2 deletions(-)

doc/langref/grammar.peg+1-1
......@@ -272,7 +272,7 @@ CompareOpTok
272272BitwiseOp <- pre_op_white BitwiseOpTok post_op_white
273273 / !pre_op_white BitwiseOpTok !post_op_white
274274BitwiseOpTok
275 <- AMPERSAND
275 <- AMPERSAND ![&]
276276 / CARET
277277 / PIPE
278278 / KEYWORD_orelse
lib/std/zig/parser_fuzz.zig+6
......@@ -30,6 +30,12 @@ test "doc comment or division operator" {
3030 try checkAgainstOracle("0=0///\n0");
3131}
3232
33// Found using AFL++
34test "double ampersand" {
35 try checkAgainstOracle("0=0&&0"); // error
36 try checkAgainstOracle("test{&&0;}"); // ok
37}
38
3339fn checkAgainstOracle(source: [:0]const u8) !void {
3440 var fba_buf: [1 << 18]u8 = undefined;
3541 var fba: std.heap.FixedBufferAllocator = .init(&fba_buf);
lib/std/zig/parser_generated_oracle.zig+13-1
......@@ -1528,7 +1528,19 @@ const Parser = struct {
15281528 pub fn parseBitwiseOpTok(p: *Parser) bool {
15291529 return blk_0: {
15301530 const pos_0 = p.i;
1531 if (p.parseAMPERSAND()) break :blk_0 true;
1531 if (p.parseAMPERSAND() and blk_1: {
1532 const pos_1 = p.i;
1533 const match_1 = (p.i < p.source.len and switch (p.source[p.i]) {
1534 '&'...'&',
1535 => blk_2: {
1536 p.i += 1;
1537 break :blk_2 true;
1538 },
1539 else => false,
1540 });
1541 p.i = pos_1;
1542 break :blk_1 !match_1;
1543 }) break :blk_0 true;
15321544 p.i = pos_0;
15331545 if (p.parseCARET()) break :blk_0 true;
15341546 p.i = pos_0;