authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-07 15:01:01+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 15:49:10+02:00
log64d5ee389912ea3e89eae18c0993a5728bc902dc
treef48cbd19e7851a18f01199a881446fbe65a6c63e
parentfe44dffa12470397146d079445ea4409961e734b
signaturelock-open Commit is signed but in an unrecognized format.

grammar: eliminate backtracking in "lists"

Currently these definitions do not result in an LL(k) generated parser. For in depth reasoning, see commit 296b39c32324 (grammar: fix ParamDeclList worst-case exponential time)

2 files changed, 56 insertions(+), 81 deletions(-)

doc/langref/grammar.peg+5-5
...@@ -441,13 +441,13 @@ ByteAlign <- KEYWORD_align LPAREN Expr RPAREN...@@ -441,13 +441,13 @@ ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
441BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN441BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
442442
443# Lists443# Lists
444IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?444IdentifierList <- (doc_comment? IDENTIFIER (COMMA IdentifierList)?)?
445445
446SwitchProngList <- (SwitchProng COMMA)* SwitchProng?446SwitchProngList <- (SwitchProng (COMMA SwitchProngList)?)?
447447
448AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?448AsmOutputList <- (AsmOutputItem (COMMA AsmOutputList)?)?
449449
450AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?450AsmInputList <- (AsmInputItem (COMMA AsmInputList)?)?
451451
452ParamDeclList <- LPAREN ParamDeclListRest452ParamDeclList <- LPAREN ParamDeclListRest
453ParamDeclListRest453ParamDeclListRest
...@@ -455,7 +455,7 @@ ParamDeclListRest...@@ -455,7 +455,7 @@ ParamDeclListRest
455 / DOT3 COMMA? RPAREN455 / DOT3 COMMA? RPAREN
456 / ParamDecl (COMMA ParamDeclListRest / RPAREN)456 / ParamDecl (COMMA ParamDeclListRest / RPAREN)
457457
458ExprList <- (Expr COMMA)* (Expr / !ExprPrefix)458ExprList <- Expr (COMMA ExprList)? / !ExprPrefix
459459
460ExprPrefix <- ASTERISK460ExprPrefix <- ASTERISK
461461
lib/std/zig/parser_generated_oracle.zig+51-76
...@@ -2913,21 +2913,14 @@ const Parser = struct {...@@ -2913,21 +2913,14 @@ const Parser = struct {
2913 defer p.depths[def_index] -= 1;2913 defer p.depths[def_index] -= 1;
2914 return blk_0: {2914 return blk_0: {
2915 const pos_0 = p.i;2915 const pos_0 = p.i;
2916 if (blk_1: {2916 if ((blk_3: {
2917 var i_1: usize = 0;
2918 while (blk_3: {
2919 const pos_3 = p.i;
2920 if ((try p.parsedoc_comment() or true) and try p.parseIDENTIFIER() and try p.parseCOMMA()) break :blk_3 true;
2921 p.i = pos_3;
2922 break :blk_3 false;
2923 }) {
2924 if (i_1 > max_depth) return error.MaxDepth;
2925 i_1 += 1;
2926 }
2927 break :blk_1 true;
2928 } and (blk_3: {
2929 const pos_3 = p.i;2917 const pos_3 = p.i;
2930 if ((try p.parsedoc_comment() or true) and try p.parseIDENTIFIER()) break :blk_3 true;2918 if ((try p.parsedoc_comment() or true) and try p.parseIDENTIFIER() and (blk_6: {
2919 const pos_6 = p.i;
2920 if (try p.parseCOMMA() and try p.parseIdentifierList()) break :blk_6 true;
2921 p.i = pos_6;
2922 break :blk_6 false;
2923 } or true)) break :blk_3 true;
2931 p.i = pos_3;2924 p.i = pos_3;
2932 break :blk_3 false;2925 break :blk_3 false;
2933 } or true)) break :blk_0 true;2926 } or true)) break :blk_0 true;
...@@ -2942,19 +2935,17 @@ const Parser = struct {...@@ -2942,19 +2935,17 @@ const Parser = struct {
2942 defer p.depths[def_index] -= 1;2935 defer p.depths[def_index] -= 1;
2943 return blk_0: {2936 return blk_0: {
2944 const pos_0 = p.i;2937 const pos_0 = p.i;
2945 if (blk_1: {2938 if ((blk_3: {
2946 var i_1: usize = 0;2939 const pos_3 = p.i;
2947 while (blk_3: {2940 if (try p.parseSwitchProng() and (blk_6: {
2948 const pos_3 = p.i;2941 const pos_6 = p.i;
2949 if (try p.parseSwitchProng() and try p.parseCOMMA()) break :blk_3 true;2942 if (try p.parseCOMMA() and try p.parseSwitchProngList()) break :blk_6 true;
2950 p.i = pos_3;2943 p.i = pos_6;
2951 break :blk_3 false;2944 break :blk_6 false;
2952 }) {2945 } or true)) break :blk_3 true;
2953 if (i_1 > max_depth) return error.MaxDepth;2946 p.i = pos_3;
2954 i_1 += 1;2947 break :blk_3 false;
2955 }2948 } or true)) break :blk_0 true;
2956 break :blk_1 true;
2957 } and (try p.parseSwitchProng() or true)) break :blk_0 true;
2958 p.i = pos_0;2949 p.i = pos_0;
2959 break :blk_0 false;2950 break :blk_0 false;
2960 };2951 };
...@@ -2966,19 +2957,17 @@ const Parser = struct {...@@ -2966,19 +2957,17 @@ const Parser = struct {
2966 defer p.depths[def_index] -= 1;2957 defer p.depths[def_index] -= 1;
2967 return blk_0: {2958 return blk_0: {
2968 const pos_0 = p.i;2959 const pos_0 = p.i;
2969 if (blk_1: {2960 if ((blk_3: {
2970 var i_1: usize = 0;2961 const pos_3 = p.i;
2971 while (blk_3: {2962 if (try p.parseAsmOutputItem() and (blk_6: {
2972 const pos_3 = p.i;2963 const pos_6 = p.i;
2973 if (try p.parseAsmOutputItem() and try p.parseCOMMA()) break :blk_3 true;2964 if (try p.parseCOMMA() and try p.parseAsmOutputList()) break :blk_6 true;
2974 p.i = pos_3;2965 p.i = pos_6;
2975 break :blk_3 false;2966 break :blk_6 false;
2976 }) {2967 } or true)) break :blk_3 true;
2977 if (i_1 > max_depth) return error.MaxDepth;2968 p.i = pos_3;
2978 i_1 += 1;2969 break :blk_3 false;
2979 }2970 } or true)) break :blk_0 true;
2980 break :blk_1 true;
2981 } and (try p.parseAsmOutputItem() or true)) break :blk_0 true;
2982 p.i = pos_0;2971 p.i = pos_0;
2983 break :blk_0 false;2972 break :blk_0 false;
2984 };2973 };
...@@ -2990,19 +2979,17 @@ const Parser = struct {...@@ -2990,19 +2979,17 @@ const Parser = struct {
2990 defer p.depths[def_index] -= 1;2979 defer p.depths[def_index] -= 1;
2991 return blk_0: {2980 return blk_0: {
2992 const pos_0 = p.i;2981 const pos_0 = p.i;
2993 if (blk_1: {2982 if ((blk_3: {
2994 var i_1: usize = 0;2983 const pos_3 = p.i;
2995 while (blk_3: {2984 if (try p.parseAsmInputItem() and (blk_6: {
2996 const pos_3 = p.i;2985 const pos_6 = p.i;
2997 if (try p.parseAsmInputItem() and try p.parseCOMMA()) break :blk_3 true;2986 if (try p.parseCOMMA() and try p.parseAsmInputList()) break :blk_6 true;
2998 p.i = pos_3;2987 p.i = pos_6;
2999 break :blk_3 false;2988 break :blk_6 false;
3000 }) {2989 } or true)) break :blk_3 true;
3001 if (i_1 > max_depth) return error.MaxDepth;2990 p.i = pos_3;
3002 i_1 += 1;2991 break :blk_3 false;
3003 }2992 } or true)) break :blk_0 true;
3004 break :blk_1 true;
3005 } and (try p.parseAsmInputItem() or true)) break :blk_0 true;
3006 p.i = pos_0;2993 p.i = pos_0;
3007 break :blk_0 false;2994 break :blk_0 false;
3008 };2995 };
...@@ -3049,30 +3036,18 @@ const Parser = struct {...@@ -3049,30 +3036,18 @@ const Parser = struct {
3049 defer p.depths[def_index] -= 1;3036 defer p.depths[def_index] -= 1;
3050 return blk_0: {3037 return blk_0: {
3051 const pos_0 = p.i;3038 const pos_0 = p.i;
3039 if (try p.parseExpr() and (blk_3: {
3040 const pos_3 = p.i;
3041 if (try p.parseCOMMA() and try p.parseExprList()) break :blk_3 true;
3042 p.i = pos_3;
3043 break :blk_3 false;
3044 } or true)) break :blk_0 true;
3045 p.i = pos_0;
3052 if (blk_1: {3046 if (blk_1: {
3053 var i_1: usize = 0;3047 const pos_1 = p.i;
3054 while (blk_3: {3048 const match_1 = try p.parseExprPrefix();
3055 const pos_3 = p.i;3049 p.i = pos_1;
3056 if (try p.parseExpr() and try p.parseCOMMA()) break :blk_3 true;3050 break :blk_1 !match_1;
3057 p.i = pos_3;
3058 break :blk_3 false;
3059 }) {
3060 if (i_1 > max_depth) return error.MaxDepth;
3061 i_1 += 1;
3062 }
3063 break :blk_1 true;
3064 } and blk_2: {
3065 const pos_2 = p.i;
3066 if (try p.parseExpr()) break :blk_2 true;
3067 p.i = pos_2;
3068 if (blk_3: {
3069 const pos_3 = p.i;
3070 const match_3 = try p.parseExprPrefix();
3071 p.i = pos_3;
3072 break :blk_3 !match_3;
3073 }) break :blk_2 true;
3074 p.i = pos_2;
3075 break :blk_2 false;
3076 }) break :blk_0 true;3051 }) break :blk_0 true;
3077 p.i = pos_0;3052 p.i = pos_0;
3078 break :blk_0 false;3053 break :blk_0 false;