authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-06-18 14:20:39+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 11:48:59+02:00
logec04ae6e0003a7fd35782dbc26c89f9905119aee
treedf7bc6096d797624c4bf17086f02763b75f8c4bd
parentd9c6669f72c6d6d12a6533282c07239deac0c9c7
signaturelock-open Commit is signed but in an unrecognized format.

grammar: fix tokenization of @"" strings


3 files changed, 24 insertions(+), 7 deletions(-)

doc/langref/grammar.peg+4-3
...@@ -527,13 +527,14 @@ NUMBERLITERAL...@@ -527,13 +527,14 @@ NUMBERLITERAL
527 / skip [0-9] digit_float*527 / skip [0-9] digit_float*
528528
529529
530STRINGLITERALSINGLE <- skip ["] string_char* ["]530string <- ["] string_char* ["]
531STRINGLITERALSINGLE <- skip string
531STRINGLITERAL532STRINGLITERAL
532 <- STRINGLITERALSINGLE533 <- skip string
533 / (skip line_string)+534 / (skip line_string)+
534IDENTIFIER535IDENTIFIER
535 <- skip !keyword [A-Za-z_] [A-Za-z0-9_]*536 <- skip !keyword [A-Za-z_] [A-Za-z0-9_]*
536 / skip '@' STRINGLITERALSINGLE537 / skip '@' string
537BUILTINIDENTIFIER <- skip '@'[A-Za-z_][A-Za-z0-9_]*538BUILTINIDENTIFIER <- skip '@'[A-Za-z_][A-Za-z0-9_]*
538539
539540
lib/std/zig/parser_fuzz.zig+8
...@@ -78,6 +78,14 @@ test "fn container field" {...@@ -78,6 +78,14 @@ test "fn container field" {
78 try checkAgainstOracle("fn()0");78 try checkAgainstOracle("fn()0");
79}79}
8080
81// Found using AFL++
82test "at newline string" {
83 try checkAgainstOracle(
84 \\@
85 \\""
86 );
87}
88
81fn checkAgainstOracle(source: [:0]const u8) !void {89fn checkAgainstOracle(source: [:0]const u8) !void {
82 var fba_buf: [1 << 18]u8 = undefined;90 var fba_buf: [1 << 18]u8 = undefined;
83 var fba: std.heap.FixedBufferAllocator = .init(&fba_buf);91 var fba: std.heap.FixedBufferAllocator = .init(&fba_buf);
lib/std/zig/parser_generated_oracle.zig+12-4
...@@ -2818,10 +2818,10 @@ const Parser = struct {...@@ -2818,10 +2818,10 @@ const Parser = struct {
2818 break :blk_0 false;2818 break :blk_0 false;
2819 };2819 };
2820 }2820 }
2821 pub fn parseSTRINGLITERALSINGLE(p: *Parser) bool {2821 pub fn parsestring(p: *Parser) bool {
2822 return blk_0: {2822 return blk_0: {
2823 const pos_0 = p.i;2823 const pos_0 = p.i;
2824 if (p.parseskip() and (p.i < p.source.len and switch (p.source[p.i]) {2824 if ((p.i < p.source.len and switch (p.source[p.i]) {
2825 '"'...'"',2825 '"'...'"',
2826 => blk_1: {2826 => blk_1: {
2827 p.i += 1;2827 p.i += 1;
...@@ -2843,10 +2843,18 @@ const Parser = struct {...@@ -2843,10 +2843,18 @@ const Parser = struct {
2843 break :blk_0 false;2843 break :blk_0 false;
2844 };2844 };
2845 }2845 }
2846 pub fn parseSTRINGLITERALSINGLE(p: *Parser) bool {
2847 return blk_0: {
2848 const pos_0 = p.i;
2849 if (p.parseskip() and p.parsestring()) break :blk_0 true;
2850 p.i = pos_0;
2851 break :blk_0 false;
2852 };
2853 }
2846 pub fn parseSTRINGLITERAL(p: *Parser) bool {2854 pub fn parseSTRINGLITERAL(p: *Parser) bool {
2847 return blk_0: {2855 return blk_0: {
2848 const pos_0 = p.i;2856 const pos_0 = p.i;
2849 if (p.parseSTRINGLITERALSINGLE()) break :blk_0 true;2857 if (p.parseskip() and p.parsestring()) break :blk_0 true;
2850 p.i = pos_0;2858 p.i = pos_0;
2851 if (blk_1: {2859 if (blk_1: {
2852 var match_1 = false;2860 var match_1 = false;
...@@ -2902,7 +2910,7 @@ const Parser = struct {...@@ -2902,7 +2910,7 @@ const Parser = struct {
2902 break :blk_1 true;2910 break :blk_1 true;
2903 }2911 }
2904 break :blk_1 false;2912 break :blk_1 false;
2905 } and p.parseSTRINGLITERALSINGLE()) break :blk_0 true;2913 } and p.parsestring()) break :blk_0 true;
2906 p.i = pos_0;2914 p.i = pos_0;
2907 break :blk_0 false;2915 break :blk_0 false;
2908 };2916 };