authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-07 14:22:17+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 15:48:03+02:00
logfe44dffa12470397146d079445ea4409961e734b
treefbedb4bc32ee973e06e2261db9ff33b5c1345587
parent5bafdbf9d8d8006cb1e3a7f3e69b059c58443489
signaturelock-open Commit is signed but in an unrecognized format.

grammar: eliminate ContainerField backtracking

For in depth reasoning, see commit 296b39c32324 (grammar: fix ParamDeclList worst-case exponential time)

2 files changed, 28 insertions(+), 36 deletions(-)

doc/langref/grammar.peg+4-3
...@@ -39,9 +39,10 @@...@@ -39,9 +39,10 @@
39Root <- ContainerMembers skip eof39Root <- ContainerMembers skip eof
4040
41# *** Top level ***41# *** Top level ***
42ContainerMembers <- container_doc_comment? ContainerDecl* !ContainerDeclPrefix42ContainerMembers <- container_doc_comment? ContainerDecl* ContainerMembersRest
43 (!ContainerDeclPrefix ContainerField COMMA)*43ContainerMembersRest
44 (!ContainerDeclPrefix ContainerField / ContainerDecl*)44 <- !ContainerDeclPrefix ContainerField (COMMA ContainerMembersRest)?
45 / ContainerDecl*
4546
46ContainerDecl <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl47ContainerDecl <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl
4748
lib/std/zig/parser_generated_oracle.zig+24-33
...@@ -16,6 +16,7 @@ pub fn parse(source: []const u8) Error!bool {...@@ -16,6 +16,7 @@ pub fn parse(source: []const u8) Error!bool {
16const Def = enum {16const Def = enum {
17 defRoot,17 defRoot,
18 defContainerMembers,18 defContainerMembers,
19 defContainerMembersRest,
19 defContainerDecl,20 defContainerDecl,
20 defContainerDeclPrefix,21 defContainerDeclPrefix,
21 defTestDecl,22 defTestDecl,
...@@ -289,7 +290,7 @@ const Def = enum {...@@ -289,7 +290,7 @@ const Def = enum {
289const Parser = struct {290const Parser = struct {
290 source: []const u8,291 source: []const u8,
291 i: usize,292 i: usize,
292 depths: [271]u8,293 depths: [272]u8,
293 pub fn parseRoot(p: *Parser) Error!bool {294 pub fn parseRoot(p: *Parser) Error!bool {
294 const def_index = @intFromEnum(Def.defRoot);295 const def_index = @intFromEnum(Def.defRoot);
295 if (p.depths[def_index] > max_depth) return error.MaxDepth;296 if (p.depths[def_index] > max_depth) return error.MaxDepth;
...@@ -316,47 +317,37 @@ const Parser = struct {...@@ -316,47 +317,37 @@ const Parser = struct {
316 i_1 += 1;317 i_1 += 1;
317 }318 }
318 break :blk_1 true;319 break :blk_1 true;
319 } and blk_1: {320 } and try p.parseContainerMembersRest()) break :blk_0 true;
321 p.i = pos_0;
322 break :blk_0 false;
323 };
324 }
325 pub fn parseContainerMembersRest(p: *Parser) Error!bool {
326 const def_index = @intFromEnum(Def.defContainerMembersRest);
327 if (p.depths[def_index] > max_depth) return error.MaxDepth;
328 p.depths[def_index] += 1;
329 defer p.depths[def_index] -= 1;
330 return blk_0: {
331 const pos_0 = p.i;
332 if (blk_1: {
320 const pos_1 = p.i;333 const pos_1 = p.i;
321 const match_1 = try p.parseContainerDeclPrefix();334 const match_1 = try p.parseContainerDeclPrefix();
322 p.i = pos_1;335 p.i = pos_1;
323 break :blk_1 !match_1;336 break :blk_1 !match_1;
324 } and blk_1: {337 } and try p.parseContainerField() and (blk_3: {
338 const pos_3 = p.i;
339 if (try p.parseCOMMA() and try p.parseContainerMembersRest()) break :blk_3 true;
340 p.i = pos_3;
341 break :blk_3 false;
342 } or true)) break :blk_0 true;
343 p.i = pos_0;
344 if (blk_1: {
325 var i_1: usize = 0;345 var i_1: usize = 0;
326 while (blk_3: {346 while (try p.parseContainerDecl()) {
327 const pos_3 = p.i;
328 if (blk_4: {
329 const pos_4 = p.i;
330 const match_4 = try p.parseContainerDeclPrefix();
331 p.i = pos_4;
332 break :blk_4 !match_4;
333 } and try p.parseContainerField() and try p.parseCOMMA()) break :blk_3 true;
334 p.i = pos_3;
335 break :blk_3 false;
336 }) {
337 if (i_1 > max_depth) return error.MaxDepth;347 if (i_1 > max_depth) return error.MaxDepth;
338 i_1 += 1;348 i_1 += 1;
339 }349 }
340 break :blk_1 true;350 break :blk_1 true;
341 } and blk_2: {
342 const pos_2 = p.i;
343 if (blk_3: {
344 const pos_3 = p.i;
345 const match_3 = try p.parseContainerDeclPrefix();
346 p.i = pos_3;
347 break :blk_3 !match_3;
348 } and try p.parseContainerField()) break :blk_2 true;
349 p.i = pos_2;
350 if (blk_3: {
351 var i_3: usize = 0;
352 while (try p.parseContainerDecl()) {
353 if (i_3 > max_depth) return error.MaxDepth;
354 i_3 += 1;
355 }
356 break :blk_3 true;
357 }) break :blk_2 true;
358 p.i = pos_2;
359 break :blk_2 false;
360 }) break :blk_0 true;351 }) break :blk_0 true;
361 p.i = pos_0;352 p.i = pos_0;
362 break :blk_0 false;353 break :blk_0 false;