authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-06-18 14:46:54+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 11:49:00+02:00
log04cb341cbfadcc9ed22202e0e48282e92bfd3f69
tree0d152118ad8faceb3da8940a8504ff3b91d9a647
parent78a196d04fb2c3a978fabec4c8c236f09add591e
signaturelock-open Commit is signed but in an unrecognized format.

grammar: fix tokenization of .?


4 files changed, 11 insertions(+), 22 deletions(-)

doc/langref/grammar.peg+3-4
......@@ -378,14 +378,14 @@ SuffixOp
378378 <- LBRACKET Expr (DOT2 (Expr / !ExprPrefix) (COLON Expr)?)? RBRACKET
379379 / DOT IDENTIFIER
380380 / DOTASTERISK
381 / DOTQUESTIONMARK
381 / DOT QUESTIONMARK
382382 / FnCallArguments
383383
384384SuffixOpPrefix
385385 <- LBRACKET
386386 / DOT IDENTIFIER
387387 / DOTASTERISK
388 / DOTQUESTIONMARK
388 / DOT QUESTIONMARK
389389 / LPAREN
390390
391391FnCallArguments <- LPAREN ExprList RPAREN
......@@ -554,11 +554,10 @@ CARET <- skip '^' ![=]
554554CARETEQUAL <- skip '^='
555555COLON <- skip ':'
556556COMMA <- skip ','
557DOT <- skip '.' ![*.?]
557DOT <- skip '.' ![*.]
558558DOT2 <- skip '..' ![.]
559559DOT3 <- skip '...'
560560DOTASTERISK <- skip '.*'
561DOTQUESTIONMARK <- skip '.?'
562561EQUAL <- skip '=' ![>=]
563562EQUALEQUAL <- skip '=='
564563EQUALRARROW <- skip '=>'
lib/std/zig/Parse.zig+1-1
......@@ -3069,7 +3069,7 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers {
30693069/// <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET
30703070/// / DOT IDENTIFIER
30713071/// / DOTASTERISK
3072/// / DOTQUESTIONMARK
3072/// / DOT QUESTIONMARK
30733073/// / FnCallArguments
30743074///
30753075/// FnCallArguments <- LPAREN ExprList RPAREN
lib/std/zig/parser_fuzz.zig+5
......@@ -93,6 +93,11 @@ test "string lit" {
9393 );
9494}
9595
96// Found using AFL++
97test "dot question" {
98 try checkAgainstOracle("0. ?");
99}
100
96101fn checkAgainstOracle(source: [:0]const u8) !void {
97102 var fba_buf: [1 << 18]u8 = undefined;
98103 var fba: std.heap.FixedBufferAllocator = .init(&fba_buf);
lib/std/zig/parser_generated_oracle.zig+2-17
......@@ -1805,7 +1805,7 @@ const Parser = struct {
18051805 p.i = pos_0;
18061806 if (p.parseDOTASTERISK()) break :blk_0 true;
18071807 p.i = pos_0;
1808 if (p.parseDOTQUESTIONMARK()) break :blk_0 true;
1808 if (p.parseDOT() and p.parseQUESTIONMARK()) break :blk_0 true;
18091809 p.i = pos_0;
18101810 if (p.parseFnCallArguments()) break :blk_0 true;
18111811 p.i = pos_0;
......@@ -1821,7 +1821,7 @@ const Parser = struct {
18211821 p.i = pos_0;
18221822 if (p.parseDOTASTERISK()) break :blk_0 true;
18231823 p.i = pos_0;
1824 if (p.parseDOTQUESTIONMARK()) break :blk_0 true;
1824 if (p.parseDOT() and p.parseQUESTIONMARK()) break :blk_0 true;
18251825 p.i = pos_0;
18261826 if (p.parseLPAREN()) break :blk_0 true;
18271827 p.i = pos_0;
......@@ -3211,7 +3211,6 @@ const Parser = struct {
32113211 const match_1 = (p.i < p.source.len and switch (p.source[p.i]) {
32123212 '*'...'*',
32133213 '.'...'.',
3214 '?'...'?',
32153214 => blk_2: {
32163215 p.i += 1;
32173216 break :blk_2 true;
......@@ -3279,20 +3278,6 @@ const Parser = struct {
32793278 break :blk_0 false;
32803279 };
32813280 }
3282 pub fn parseDOTQUESTIONMARK(p: *Parser) bool {
3283 return blk_0: {
3284 const pos_0 = p.i;
3285 if (p.parseskip() and blk_1: {
3286 if (std.mem.startsWith(u8, p.source[p.i..], ".?")) {
3287 p.i += 2;
3288 break :blk_1 true;
3289 }
3290 break :blk_1 false;
3291 }) break :blk_0 true;
3292 p.i = pos_0;
3293 break :blk_0 false;
3294 };
3295 }
32963281 pub fn parseEQUAL(p: *Parser) bool {
32973282 return blk_0: {
32983283 const pos_0 = p.i;