authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-06-18 12:14:58+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 11:48:59+02:00
log0c7688332d10b5ae460e756c2d5a3f58ead26367
tree5784e37e87bee15ccfa4140254ebcd3ba3e3553a
parentb4185600466bd14e39e68cd9f07017a8dc1fcf8e
signaturelock-open Commit is signed but in an unrecognized format.

grammar: expression-level consistency with Parse.zig

This is a first pass at consistency with Parse.zig at the expression level, adding constant lookaheads to the grammar in several places to match the behavior of Parse.zig. I also updated the comments in Parse.zig and refactored for clarity, adding assertions in a few places but not intending any change in behavior. This commit also adds comments to the grammar and Parse.zig explaining what needs to be done in practice to ensure that the grammar is LL(k) and that the parser has worst-case linear runtime.

3 files changed, 400 insertions(+), 195 deletions(-)

doc/langref/grammar.peg+70-19
......@@ -1,3 +1,41 @@
1# This grammar is intended to be LL(k) at the token level.
2# In other words, whenever the parser is required to make a choice it must be
3# able to choose "correctly" with constant token lookahead. This means that the
4# handwritten recursive descent parser for this grammar can be implemented with
5# worst-case linear run time rather than worst-case exponential runtime.
6#
7# To ensure this property is upheld, care must be taken to avoid requiring
8# unbounded token lookahead in the grammar. To illustrate this, consider the
9# following examples requiring unbounded lookahead:
10#
11# This is rather subtle as it looks fine at first glance:
12#
13# SingleAssignExpr <- Expr (AssignOp Expr)?
14#
15# Consider the case where the AssignOp token matches but Expr after it does
16# not match. The parser would attempt to parse the Expr after the AssignOp,
17# fail, then backtrack and succeed the SingleAssignExpr rule matching only
18# the first Expr. This is an example of unbounded lookahead. The rule must
19# be rewritten so that if the AssignOp token is not followed by an Expr the
20# whole SingleAssignExpr rule fails to match:
21#
22# SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp)
23#
24# The pattern is similar for e.g. the * operator. The following rule requires
25# unbounded lookahead:
26#
27# BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)*
28#
29# and can be fixed to require only bounded lookahead by adding a !OrOp:
30#
31# BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp
32#
33# Note also that the negative lookahead added with the ! operator must always be
34# for a constant maximum number of tokens.
35#
36# See this paper for analysis of how LL(k) grammars relate to PEGs:
37# https://arxiv.org/abs/1304.3177
38
139Root <- ContainerMembers skip eof
240
341# *** Top level ***
......@@ -66,27 +104,27 @@ VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL
66104# *** Expression Level ***
67105
68106# An assignment or a destructure whose LHS are all lvalue expressions.
69AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)?
107AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA)
70108
71SingleAssignExpr <- Expr (AssignOp Expr)?
109SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp)
72110
73111Expr <- BoolOrExpr
74112
75BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)*
113BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp
76114
77BoolAndExpr <- CompareExpr (AndOp CompareExpr)*
115BoolAndExpr <- CompareExpr (AndOp CompareExpr)* !AndOp
78116
79CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
117CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr / !CompareOp)
80118
81BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
119BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* !BitwiseOp
82120
83BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
121BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* !BitShiftOp
84122
85AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
123AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* !AdditionOp
86124
87MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
125MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* !MultiplyOp
88126
89PrefixExpr <- PrefixOp* PrimaryExpr
127PrefixExpr <- PrefixOp* !PrefixOp PrimaryExpr
90128
91129PrimaryExpr
92130 <- AsmExpr
......@@ -101,7 +139,7 @@ PrimaryExpr
101139 / Block
102140 / CurlySuffixExpr
103141
104IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
142IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else)
105143
106144Block <- LBRACE BlockStatement* RBRACE
107145
......@@ -111,19 +149,18 @@ ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else)
111149
112150WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
113151
114CurlySuffixExpr <- TypeExpr InitList?
152CurlySuffixExpr <- TypeExpr (InitList / !LBRACE)
115153
116154InitList
117155 <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
118156 / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
119157 / LBRACE RBRACE
120158
121TypeExpr <- PrefixTypeOp* ErrorUnionExpr
159TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr
122160
123ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
161ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK)
124162
125SuffixExpr
126 <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
163SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix
127164
128165PrimaryTypeExpr
129166 <- BUILTINIDENTIFIER FnCallArguments
......@@ -150,7 +187,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
150187
151188GroupedExpr <- LPAREN Expr RPAREN
152189
153IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
190IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
154191
155192LabeledTypeExpr
156193 <- BlockLabel Block
......@@ -161,7 +198,7 @@ LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
161198
162199ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else)
163200
164WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
201WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
165202
166203SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
167204
......@@ -319,11 +356,25 @@ PrefixTypeOp
319356 / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
320357 / ArrayTypeStart
321358
359PrefixTypeOpPrefix
360 <- QUESTIONMARK
361 / KEYWORD_anyframe MINUSRARROW
362 / LBRACKET
363 / ASTERISK
364
322365SuffixOp
323366 <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET
324367 / DOT IDENTIFIER
325368 / DOTASTERISK
326369 / DOTQUESTIONMARK
370 / FnCallArguments
371
372SuffixOpPrefix
373 <- LBRACKET
374 / DOT IDENTIFIER
375 / DOTASTERISK
376 / DOTQUESTIONMARK
377 / LPAREN
327378
328379FnCallArguments <- LPAREN ExprList RPAREN
329380
......@@ -334,7 +385,7 @@ SinglePtrTypeStart <- ASTERISK
334385
335386ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
336387
337ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET
388ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET
338389
339390# ContainerDecl specific
340391ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
lib/std/zig/Parse.zig+126-113
......@@ -1,5 +1,18 @@
11//! Represents in-progress parsing, will be converted to an Ast after completion.
22
3// This recursive descent parser must be "predictive," using only constant
4// token lookahead and never backtracking.
5//
6// This means that whenever the parser encounters a choice it is allowed to look
7// at the next k tokens in order to make that choice, where k is a fixed constant.
8//
9// Once the parser has made the choice, it must either succeed at parsing that sub
10// expression or fail entirely and present an error to the user. The parser is never
11// allowed to backtrack and make a different choice to see if that one succeeds.
12//
13// This ensures worst-case linear runtime rather than worst-case exponential runtime
14// and requires the Zig grammar to be LL(k).
15
316pub const Error = error{ParseError} || Allocator.Error;
417
518gpa: Allocator,
......@@ -1411,7 +1424,7 @@ fn parseBlockExpr(p: *Parse) Error!?Node.Index {
14111424 }
14121425}
14131426
1414/// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)?
1427/// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA)
14151428///
14161429/// AssignOp
14171430/// <- ASTERISKEQUAL
......@@ -1437,7 +1450,7 @@ fn parseAssignExpr(p: *Parse) !?Node.Index {
14371450 return try p.finishAssignExpr(expr);
14381451}
14391452
1440/// SingleAssignExpr <- Expr (AssignOp Expr)?
1453/// SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp)
14411454fn parseSingleAssignExpr(p: *Parse) !?Node.Index {
14421455 const lhs = try p.parseExpr() orelse return null;
14431456 const tag = assignOpNode(p.tokenTag(p.tok_i)) orelse return lhs;
......@@ -1643,7 +1656,7 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index {
16431656 return node;
16441657}
16451658
1646/// PrefixExpr <- PrefixOp* PrimaryExpr
1659/// PrefixExpr <- PrefixOp* PrimaryExpr / !PrefixOp
16471660///
16481661/// PrefixOp
16491662/// <- EXCLAMATIONMARK
......@@ -1673,23 +1686,28 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index {
16731686 return try p.parsePrefixExpr() orelse return p.fail(.expected_prefix_expr);
16741687}
16751688
1676/// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
1689/// TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr
16771690///
16781691/// PrefixTypeOp
16791692/// <- QUESTIONMARK
16801693/// / KEYWORD_anyframe MINUSRARROW
16811694/// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
16821695/// / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
1683/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
16841696/// / ArrayTypeStart
16851697///
1698/// PrefixTypeOpPrefix
1699/// <- QUESTIONMARK
1700/// / KEYWORD_anyframe MINUSRARROW
1701/// / LBRACKET
1702/// / ASTERISK
1703///
16861704/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
16871705///
16881706/// SinglePtrTypeStart <- ASTERISK
16891707///
16901708/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
16911709///
1692/// ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET
1710/// ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET
16931711///
16941712/// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
16951713fn parseTypeExpr(p: *Parse) Error!?Node.Index {
......@@ -1904,19 +1922,19 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index {
19041922/// PrimaryExpr
19051923/// <- AsmExpr
19061924/// / IfExpr
1907/// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
1908/// / KEYWORD_comptime Expr !ExprSuffix
1909/// / KEYWORD_nosuspend Expr !ExprSuffix
1910/// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
1911/// / KEYWORD_resume Expr !ExprSuffix
1912/// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart)
1925/// / KEYWORD_break BreakLabel? Expr?
1926/// / KEYWORD_comptime Expr
1927/// / KEYWORD_nosuspend Expr
1928/// / KEYWORD_continue BreakLabel? Expr?
1929/// / KEYWORD_resume Expr
1930/// / KEYWORD_return Expr?
19131931/// / BlockLabel? LoopExpr
19141932/// / Block
19151933/// / CurlySuffixExpr
19161934fn parsePrimaryExpr(p: *Parse) !?Node.Index {
19171935 switch (p.tokenTag(p.tok_i)) {
19181936 .keyword_asm => return try p.expectAsmExpr(),
1919 .keyword_if => return try p.parseIfExpr(),
1937 .keyword_if => return try p.expectIf(expectExpr),
19201938 .keyword_break => {
19211939 return try p.addNode(.{
19221940 .tag = .@"break",
......@@ -1971,18 +1989,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {
19711989 .keyword_inline => {
19721990 p.tok_i += 3;
19731991 switch (p.tokenTag(p.tok_i)) {
1974 .keyword_for => return try p.parseFor(expectExpr),
1975 .keyword_while => return try p.parseWhileExpr(),
1992 .keyword_for => return try p.expectFor(expectExpr),
1993 .keyword_while => return try p.expectWhileExpr(),
19761994 else => return p.fail(.expected_inlinable),
19771995 }
19781996 },
19791997 .keyword_for => {
19801998 p.tok_i += 2;
1981 return try p.parseFor(expectExpr);
1999 return try p.expectFor(expectExpr);
19822000 },
19832001 .keyword_while => {
19842002 p.tok_i += 2;
1985 return try p.parseWhileExpr();
2003 return try p.expectWhileExpr();
19862004 },
19872005 else => return try p.parseCurlySuffixExpr(),
19882006 }
......@@ -1993,23 +2011,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {
19932011 .keyword_inline => {
19942012 p.tok_i += 1;
19952013 switch (p.tokenTag(p.tok_i)) {
1996 .keyword_for => return try p.parseFor(expectExpr),
1997 .keyword_while => return try p.parseWhileExpr(),
2014 .keyword_for => return try p.expectFor(expectExpr),
2015 .keyword_while => return try p.expectWhileExpr(),
19982016 else => return p.fail(.expected_inlinable),
19992017 }
20002018 },
2001 .keyword_for => return try p.parseFor(expectExpr),
2002 .keyword_while => return try p.parseWhileExpr(),
2019 .keyword_for => return try p.expectFor(expectExpr),
2020 .keyword_while => return try p.expectWhileExpr(),
20032021 .l_brace => return try p.parseBlock(),
20042022 else => return try p.parseCurlySuffixExpr(),
20052023 }
20062024}
20072025
2008/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
2009fn parseIfExpr(p: *Parse) !?Node.Index {
2010 return try p.parseIf(expectExpr);
2011}
2012
20132026/// Block <- LBRACE BlockStatement* RBRACE
20142027fn parseBlock(p: *Parse) !?Node.Index {
20152028 const lbrace = p.eatToken(.l_brace) orelse return null;
......@@ -2104,8 +2117,8 @@ fn forPrefix(p: *Parse) Error!usize {
21042117/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
21052118///
21062119/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi
2107fn parseWhileExpr(p: *Parse) !?Node.Index {
2108 const while_token = p.eatToken(.keyword_while) orelse return null;
2120fn expectWhileExpr(p: *Parse) !Node.Index {
2121 const while_token = p.assertToken(.keyword_while);
21092122 _ = try p.expectToken(.l_paren);
21102123 const condition = try p.expectExpr();
21112124 _ = try p.expectToken(.r_paren);
......@@ -2153,7 +2166,7 @@ fn parseWhileExpr(p: *Parse) !?Node.Index {
21532166 });
21542167}
21552168
2156/// CurlySuffixExpr <- TypeExpr InitList?
2169/// CurlySuffixExpr <- TypeExpr (InitList / !LBRACE)
21572170///
21582171/// InitList
21592172/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
......@@ -2255,7 +2268,7 @@ fn parseCurlySuffixExpr(p: *Parse) !?Node.Index {
22552268 }
22562269}
22572270
2258/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
2271/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK)
22592272fn parseErrorUnionExpr(p: *Parse) !?Node.Index {
22602273 const suffix_expr = try p.parseSuffixExpr() orelse return null;
22612274 const bang = p.eatToken(.bang) orelse return suffix_expr;
......@@ -2269,59 +2282,13 @@ fn parseErrorUnionExpr(p: *Parse) !?Node.Index {
22692282 });
22702283}
22712284
2272/// SuffixExpr
2273/// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
2274///
2275/// FnCallArguments <- LPAREN ExprList RPAREN
2276///
2277/// ExprList <- (Expr COMMA)* Expr?
2285/// SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix
22782286fn parseSuffixExpr(p: *Parse) !?Node.Index {
22792287 var res = try p.parsePrimaryTypeExpr() orelse return null;
2280 while (true) {
2281 const opt_suffix_op = try p.parseSuffixOp(res);
2282 if (opt_suffix_op) |suffix_op| {
2283 res = suffix_op;
2284 continue;
2285 }
2286 const lparen = p.eatToken(.l_paren) orelse return res;
2287 const scratch_top = p.scratch.items.len;
2288 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2289 while (true) {
2290 if (p.eatToken(.r_paren)) |_| break;
2291 const param = try p.expectExpr();
2292 try p.scratch.append(p.gpa, param);
2293 switch (p.tokenTag(p.tok_i)) {
2294 .comma => p.tok_i += 1,
2295 .r_paren => {
2296 p.tok_i += 1;
2297 break;
2298 },
2299 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2300 // Likely just a missing comma; give error but continue parsing.
2301 else => try p.warn(.expected_comma_after_arg),
2302 }
2303 }
2304 const comma = (p.tokenTag(p.tok_i - 2)) == .comma;
2305 const params = p.scratch.items[scratch_top..];
2306 res = switch (params.len) {
2307 0, 1 => try p.addNode(.{
2308 .tag = if (comma) .call_one_comma else .call_one,
2309 .main_token = lparen,
2310 .data = .{ .node_and_opt_node = .{
2311 res,
2312 if (params.len >= 1) .fromOptional(params[0]) else .none,
2313 } },
2314 }),
2315 else => try p.addNode(.{
2316 .tag = if (comma) .call_comma else .call,
2317 .main_token = lparen,
2318 .data = .{ .node_and_extra = .{
2319 res,
2320 try p.addExtra(try p.listToSpan(params)),
2321 } },
2322 }),
2323 };
2288 while (try p.parseSuffixOp(res)) |suffix_op| {
2289 res = suffix_op;
23242290 }
2291 return res;
23252292}
23262293
23272294/// PrimaryTypeExpr
......@@ -2331,17 +2298,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index {
23312298/// / DOT IDENTIFIER
23322299/// / DOT InitList
23332300/// / ErrorSetDecl
2334/// / FLOAT
23352301/// / FnProto
23362302/// / GroupedExpr
23372303/// / LabeledTypeExpr
2338/// / IDENTIFIER !(COLON LabelableExpr)
2304/// / IDENTIFIER
23392305/// / IfTypeExpr
2340/// / INTEGER
2341/// / KEYWORD_comptime TypeExpr !ExprSuffix
2306/// / KEYWORD_comptime TypeExpr
23422307/// / KEYWORD_error DOT IDENTIFIER
23432308/// / KEYWORD_anyframe
23442309/// / KEYWORD_unreachable
2310/// / NUMBERLITERAL
23452311/// / STRINGLITERAL
23462312///
23472313/// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
......@@ -2396,23 +2362,23 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
23962362 });
23972363 },
23982364
2399 .builtin => return try p.parseBuiltinCall(),
2400 .keyword_fn => return try p.parseFnProto(),
2401 .keyword_if => return try p.parseIf(expectTypeExpr),
2365 .builtin => return try p.expectBuiltinCall(),
2366 .keyword_fn => return (try p.parseFnProto()).?,
2367 .keyword_if => return try p.expectIf(expectTypeExpr),
24022368 .keyword_switch => return try p.expectSwitchExpr(false),
24032369
24042370 .keyword_extern,
24052371 .keyword_packed,
24062372 => {
24072373 p.tok_i += 1;
2408 return try p.parseContainerDeclAuto();
2374 return try p.expectContainerDeclAuto();
24092375 },
24102376
24112377 .keyword_struct,
24122378 .keyword_opaque,
24132379 .keyword_enum,
24142380 .keyword_union,
2415 => return try p.parseContainerDeclAuto(),
2381 => return try p.expectContainerDeclAuto(),
24162382
24172383 .keyword_comptime => return try p.addNode(.{
24182384 .tag = .@"comptime",
......@@ -2438,18 +2404,18 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
24382404 .keyword_inline => {
24392405 p.tok_i += 3;
24402406 switch (p.tokenTag(p.tok_i)) {
2441 .keyword_for => return try p.parseFor(expectTypeExpr),
2442 .keyword_while => return try p.parseWhileTypeExpr(),
2407 .keyword_for => return try p.expectFor(expectTypeExpr),
2408 .keyword_while => return try p.expectWhileTypeExpr(),
24432409 else => return p.fail(.expected_inlinable),
24442410 }
24452411 },
24462412 .keyword_for => {
24472413 p.tok_i += 2;
2448 return try p.parseFor(expectTypeExpr);
2414 return try p.expectFor(expectTypeExpr);
24492415 },
24502416 .keyword_while => {
24512417 p.tok_i += 2;
2452 return try p.parseWhileTypeExpr();
2418 return try p.expectWhileTypeExpr();
24532419 },
24542420 .keyword_switch => {
24552421 p.tok_i += 2;
......@@ -2457,7 +2423,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
24572423 },
24582424 .l_brace => {
24592425 p.tok_i += 2;
2460 return try p.parseBlock();
2426 return (try p.parseBlock()).?;
24612427 },
24622428 else => return try p.addNode(.{
24632429 .tag = .identifier,
......@@ -2474,13 +2440,13 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
24742440 .keyword_inline => {
24752441 p.tok_i += 1;
24762442 switch (p.tokenTag(p.tok_i)) {
2477 .keyword_for => return try p.parseFor(expectTypeExpr),
2478 .keyword_while => return try p.parseWhileTypeExpr(),
2443 .keyword_for => return try p.expectFor(expectTypeExpr),
2444 .keyword_while => return try p.expectWhileTypeExpr(),
24792445 else => return p.fail(.expected_inlinable),
24802446 }
24812447 },
2482 .keyword_for => return try p.parseFor(expectTypeExpr),
2483 .keyword_while => return try p.parseWhileTypeExpr(),
2448 .keyword_for => return try p.expectFor(expectTypeExpr),
2449 .keyword_while => return try p.expectWhileTypeExpr(),
24842450 .period => switch (p.tokenTag(p.tok_i + 1)) {
24852451 .identifier => {
24862452 p.tok_i += 1;
......@@ -2608,10 +2574,8 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
26082574 },
26092575 else => {
26102576 const main_token = p.nextToken();
2611 const period = p.eatToken(.period);
2612 if (period == null) return p.failExpected(.period);
2613 const identifier = p.eatToken(.identifier);
2614 if (identifier == null) return p.failExpected(.identifier);
2577 _ = try p.expectToken(.period);
2578 _ = try p.expectToken(.identifier);
26152579 return try p.addNode(.{
26162580 .tag = .error_value,
26172581 .main_token = main_token,
......@@ -2637,9 +2601,9 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index {
26372601
26382602/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
26392603///
2640/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
2641fn parseWhileTypeExpr(p: *Parse) !?Node.Index {
2642 const while_token = p.eatToken(.keyword_while) orelse return null;
2604/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
2605fn expectWhileTypeExpr(p: *Parse) !Node.Index {
2606 const while_token = p.assertToken(.keyword_while);
26432607 _ = try p.expectToken(.l_paren);
26442608 const condition = try p.expectExpr();
26452609 _ = try p.expectToken(.r_paren);
......@@ -3106,6 +3070,11 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers {
31063070/// / DOT IDENTIFIER
31073071/// / DOTASTERISK
31083072/// / DOTQUESTIONMARK
3073/// / FnCallArguments
3074///
3075/// FnCallArguments <- LPAREN ExprList RPAREN
3076///
3077/// ExprList <- (Expr COMMA)* Expr?
31093078fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
31103079 switch (p.tokenTag(p.tok_i)) {
31113080 .l_bracket => {
......@@ -3195,6 +3164,46 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
31953164 return null;
31963165 },
31973166 },
3167 .l_paren => {
3168 const lparen = p.nextToken();
3169 const scratch_top = p.scratch.items.len;
3170 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3171 while (true) {
3172 if (p.eatToken(.r_paren)) |_| break;
3173 const param = try p.expectExpr();
3174 try p.scratch.append(p.gpa, param);
3175 switch (p.tokenTag(p.tok_i)) {
3176 .comma => p.tok_i += 1,
3177 .r_paren => {
3178 p.tok_i += 1;
3179 break;
3180 },
3181 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
3182 // Likely just a missing comma; give error but continue parsing.
3183 else => try p.warn(.expected_comma_after_arg),
3184 }
3185 }
3186 const comma = (p.tokenTag(p.tok_i - 2)) == .comma;
3187 const params = p.scratch.items[scratch_top..];
3188 switch (params.len) {
3189 0, 1 => return try p.addNode(.{
3190 .tag = if (comma) .call_one_comma else .call_one,
3191 .main_token = lparen,
3192 .data = .{ .node_and_opt_node = .{
3193 lhs,
3194 if (params.len >= 1) .fromOptional(params[0]) else .none,
3195 } },
3196 }),
3197 else => return try p.addNode(.{
3198 .tag = if (comma) .call_comma else .call,
3199 .main_token = lparen,
3200 .data = .{ .node_and_extra = .{
3201 lhs,
3202 try p.addExtra(try p.listToSpan(params)),
3203 } },
3204 }),
3205 }
3206 },
31983207 else => return null,
31993208 }
32003209}
......@@ -3208,7 +3217,7 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
32083217/// / KEYWORD_opaque
32093218/// / KEYWORD_enum (LPAREN Expr RPAREN)?
32103219/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
3211fn parseContainerDeclAuto(p: *Parse) !?Node.Index {
3220fn expectContainerDeclAuto(p: *Parse) !Node.Index {
32123221 const main_token = p.nextToken();
32133222 const arg_expr = switch (p.tokenTag(main_token)) {
32143223 .keyword_opaque => null,
......@@ -3431,7 +3440,7 @@ fn parseParamDeclList(p: *Parse) !SmallSpan {
34313440/// FnCallArguments <- LPAREN ExprList RPAREN
34323441///
34333442/// ExprList <- (Expr COMMA)* Expr?
3434fn parseBuiltinCall(p: *Parse) !Node.Index {
3443fn expectBuiltinCall(p: *Parse) !Node.Index {
34353444 const builtin_token = p.assertToken(.builtin);
34363445 _ = p.eatToken(.l_paren) orelse {
34373446 try p.warn(.expected_param_list);
......@@ -3479,9 +3488,13 @@ fn parseBuiltinCall(p: *Parse) !Node.Index {
34793488 }
34803489}
34813490
3491/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else)
3492///
3493/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
3494///
34823495/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
3483fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index {
3484 const if_token = p.eatToken(.keyword_if) orelse return null;
3496fn expectIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index {
3497 const if_token = p.assertToken(.keyword_if);
34853498 _ = try p.expectToken(.l_paren);
34863499 const condition = try p.expectExpr();
34873500 _ = try p.expectToken(.r_paren);
......@@ -3513,11 +3526,11 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N
35133526 });
35143527}
35153528
3516/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix
3529/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else)
35173530///
3518/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix
3519fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index {
3520 const for_token = p.eatToken(.keyword_for) orelse return null;
3531/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else)
3532fn expectFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index {
3533 const for_token = p.assertToken(.keyword_for);
35213534
35223535 const scratch_top = p.scratch.items.len;
35233536 defer p.scratch.shrinkRetainingCapacity(scratch_top);
lib/std/zig/parser_generated_oracle.zig+204-63
......@@ -429,25 +429,37 @@ const Parser = struct {
429429 pub fn parseAssignExpr(p: *Parser) bool {
430430 return blk_0: {
431431 const pos_0 = p.i;
432 if (p.parseExpr() and (blk_3: {
433 const pos_3 = p.i;
434 if (p.parseAssignOp() and p.parseExpr()) break :blk_3 true;
435 p.i = pos_3;
436 if (blk_4: {
437 var match_4 = false;
438 while (blk_6: {
439 const pos_6 = p.i;
440 if (p.parseCOMMA() and p.parseExpr()) break :blk_6 true;
441 p.i = pos_6;
442 break :blk_6 false;
432 if (p.parseExpr() and blk_2: {
433 const pos_2 = p.i;
434 if (p.parseAssignOp() and p.parseExpr()) break :blk_2 true;
435 p.i = pos_2;
436 if (blk_3: {
437 var match_3 = false;
438 while (blk_5: {
439 const pos_5 = p.i;
440 if (p.parseCOMMA() and p.parseExpr()) break :blk_5 true;
441 p.i = pos_5;
442 break :blk_5 false;
443443 }) {
444 match_4 = true;
444 match_3 = true;
445445 }
446 break :blk_4 match_4;
447 } and p.parseEQUAL() and p.parseExpr()) break :blk_3 true;
448 p.i = pos_3;
449 break :blk_3 false;
450 } or true)) break :blk_0 true;
446 break :blk_3 match_3;
447 } and p.parseEQUAL() and p.parseExpr()) break :blk_2 true;
448 p.i = pos_2;
449 if (blk_3: {
450 const pos_3 = p.i;
451 const match_3 = p.parseAssignOp();
452 p.i = pos_3;
453 break :blk_3 !match_3;
454 } and blk_3: {
455 const pos_3 = p.i;
456 const match_3 = p.parseCOMMA();
457 p.i = pos_3;
458 break :blk_3 !match_3;
459 }) break :blk_2 true;
460 p.i = pos_2;
461 break :blk_2 false;
462 }) break :blk_0 true;
451463 p.i = pos_0;
452464 break :blk_0 false;
453465 };
......@@ -455,12 +467,19 @@ const Parser = struct {
455467 pub fn parseSingleAssignExpr(p: *Parser) bool {
456468 return blk_0: {
457469 const pos_0 = p.i;
458 if (p.parseExpr() and (blk_3: {
459 const pos_3 = p.i;
460 if (p.parseAssignOp() and p.parseExpr()) break :blk_3 true;
461 p.i = pos_3;
462 break :blk_3 false;
463 } or true)) break :blk_0 true;
470 if (p.parseExpr() and blk_2: {
471 const pos_2 = p.i;
472 if (p.parseAssignOp() and p.parseExpr()) break :blk_2 true;
473 p.i = pos_2;
474 if (blk_3: {
475 const pos_3 = p.i;
476 const match_3 = p.parseAssignOp();
477 p.i = pos_3;
478 break :blk_3 !match_3;
479 }) break :blk_2 true;
480 p.i = pos_2;
481 break :blk_2 false;
482 }) break :blk_0 true;
464483 p.i = pos_0;
465484 break :blk_0 false;
466485 };
......@@ -484,6 +503,11 @@ const Parser = struct {
484503 break :blk_3 false;
485504 }) {}
486505 break :blk_1 true;
506 } and blk_1: {
507 const pos_1 = p.i;
508 const match_1 = p.parseOrOp();
509 p.i = pos_1;
510 break :blk_1 !match_1;
487511 }) break :blk_0 true;
488512 p.i = pos_0;
489513 break :blk_0 false;
......@@ -500,6 +524,11 @@ const Parser = struct {
500524 break :blk_3 false;
501525 }) {}
502526 break :blk_1 true;
527 } and blk_1: {
528 const pos_1 = p.i;
529 const match_1 = p.parseAndOp();
530 p.i = pos_1;
531 break :blk_1 !match_1;
503532 }) break :blk_0 true;
504533 p.i = pos_0;
505534 break :blk_0 false;
......@@ -508,12 +537,19 @@ const Parser = struct {
508537 pub fn parseCompareExpr(p: *Parser) bool {
509538 return blk_0: {
510539 const pos_0 = p.i;
511 if (p.parseBitwiseExpr() and (blk_3: {
512 const pos_3 = p.i;
513 if (p.parseCompareOp() and p.parseBitwiseExpr()) break :blk_3 true;
514 p.i = pos_3;
515 break :blk_3 false;
516 } or true)) break :blk_0 true;
540 if (p.parseBitwiseExpr() and blk_2: {
541 const pos_2 = p.i;
542 if (p.parseCompareOp() and p.parseBitwiseExpr()) break :blk_2 true;
543 p.i = pos_2;
544 if (blk_3: {
545 const pos_3 = p.i;
546 const match_3 = p.parseCompareOp();
547 p.i = pos_3;
548 break :blk_3 !match_3;
549 }) break :blk_2 true;
550 p.i = pos_2;
551 break :blk_2 false;
552 }) break :blk_0 true;
517553 p.i = pos_0;
518554 break :blk_0 false;
519555 };
......@@ -529,6 +565,11 @@ const Parser = struct {
529565 break :blk_3 false;
530566 }) {}
531567 break :blk_1 true;
568 } and blk_1: {
569 const pos_1 = p.i;
570 const match_1 = p.parseBitwiseOp();
571 p.i = pos_1;
572 break :blk_1 !match_1;
532573 }) break :blk_0 true;
533574 p.i = pos_0;
534575 break :blk_0 false;
......@@ -545,6 +586,11 @@ const Parser = struct {
545586 break :blk_3 false;
546587 }) {}
547588 break :blk_1 true;
589 } and blk_1: {
590 const pos_1 = p.i;
591 const match_1 = p.parseBitShiftOp();
592 p.i = pos_1;
593 break :blk_1 !match_1;
548594 }) break :blk_0 true;
549595 p.i = pos_0;
550596 break :blk_0 false;
......@@ -561,6 +607,11 @@ const Parser = struct {
561607 break :blk_3 false;
562608 }) {}
563609 break :blk_1 true;
610 } and blk_1: {
611 const pos_1 = p.i;
612 const match_1 = p.parseAdditionOp();
613 p.i = pos_1;
614 break :blk_1 !match_1;
564615 }) break :blk_0 true;
565616 p.i = pos_0;
566617 break :blk_0 false;
......@@ -577,6 +628,11 @@ const Parser = struct {
577628 break :blk_3 false;
578629 }) {}
579630 break :blk_1 true;
631 } and blk_1: {
632 const pos_1 = p.i;
633 const match_1 = p.parseMultiplyOp();
634 p.i = pos_1;
635 break :blk_1 !match_1;
580636 }) break :blk_0 true;
581637 p.i = pos_0;
582638 break :blk_0 false;
......@@ -588,6 +644,11 @@ const Parser = struct {
588644 if (blk_1: {
589645 while (p.parsePrefixOp()) {}
590646 break :blk_1 true;
647 } and blk_1: {
648 const pos_1 = p.i;
649 const match_1 = p.parsePrefixOp();
650 p.i = pos_1;
651 break :blk_1 !match_1;
591652 } and p.parsePrimaryExpr()) break :blk_0 true;
592653 p.i = pos_0;
593654 break :blk_0 false;
......@@ -624,12 +685,19 @@ const Parser = struct {
624685 pub fn parseIfExpr(p: *Parser) bool {
625686 return blk_0: {
626687 const pos_0 = p.i;
627 if (p.parseIfPrefix() and p.parseExpr() and (blk_3: {
628 const pos_3 = p.i;
629 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseExpr()) break :blk_3 true;
630 p.i = pos_3;
631 break :blk_3 false;
632 } or true)) break :blk_0 true;
688 if (p.parseIfPrefix() and p.parseExpr() and blk_2: {
689 const pos_2 = p.i;
690 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseExpr()) break :blk_2 true;
691 p.i = pos_2;
692 if (blk_3: {
693 const pos_3 = p.i;
694 const match_3 = p.parseKEYWORD_else();
695 p.i = pos_3;
696 break :blk_3 !match_3;
697 }) break :blk_2 true;
698 p.i = pos_2;
699 break :blk_2 false;
700 }) break :blk_0 true;
633701 p.i = pos_0;
634702 break :blk_0 false;
635703 };
......@@ -696,7 +764,19 @@ const Parser = struct {
696764 pub fn parseCurlySuffixExpr(p: *Parser) bool {
697765 return blk_0: {
698766 const pos_0 = p.i;
699 if (p.parseTypeExpr() and (p.parseInitList() or true)) break :blk_0 true;
767 if (p.parseTypeExpr() and blk_2: {
768 const pos_2 = p.i;
769 if (p.parseInitList()) break :blk_2 true;
770 p.i = pos_2;
771 if (blk_3: {
772 const pos_3 = p.i;
773 const match_3 = p.parseLBRACE();
774 p.i = pos_3;
775 break :blk_3 !match_3;
776 }) break :blk_2 true;
777 p.i = pos_2;
778 break :blk_2 false;
779 }) break :blk_0 true;
700780 p.i = pos_0;
701781 break :blk_0 false;
702782 };
......@@ -735,6 +815,11 @@ const Parser = struct {
735815 if (blk_1: {
736816 while (p.parsePrefixTypeOp()) {}
737817 break :blk_1 true;
818 } and blk_1: {
819 const pos_1 = p.i;
820 const match_1 = p.parsePrefixTypeOpPrefix();
821 p.i = pos_1;
822 break :blk_1 !match_1;
738823 } and p.parseErrorUnionExpr()) break :blk_0 true;
739824 p.i = pos_0;
740825 break :blk_0 false;
......@@ -743,12 +828,19 @@ const Parser = struct {
743828 pub fn parseErrorUnionExpr(p: *Parser) bool {
744829 return blk_0: {
745830 const pos_0 = p.i;
746 if (p.parseSuffixExpr() and (blk_3: {
747 const pos_3 = p.i;
748 if (p.parseEXCLAMATIONMARK() and p.parseTypeExpr()) break :blk_3 true;
749 p.i = pos_3;
750 break :blk_3 false;
751 } or true)) break :blk_0 true;
831 if (p.parseSuffixExpr() and blk_2: {
832 const pos_2 = p.i;
833 if (p.parseEXCLAMATIONMARK() and p.parseTypeExpr()) break :blk_2 true;
834 p.i = pos_2;
835 if (blk_3: {
836 const pos_3 = p.i;
837 const match_3 = p.parseEXCLAMATIONMARK();
838 p.i = pos_3;
839 break :blk_3 !match_3;
840 }) break :blk_2 true;
841 p.i = pos_2;
842 break :blk_2 false;
843 }) break :blk_0 true;
752844 p.i = pos_0;
753845 break :blk_0 false;
754846 };
......@@ -757,15 +849,13 @@ const Parser = struct {
757849 return blk_0: {
758850 const pos_0 = p.i;
759851 if (p.parsePrimaryTypeExpr() and blk_1: {
760 while (blk_3: {
761 const pos_3 = p.i;
762 if (p.parseSuffixOp()) break :blk_3 true;
763 p.i = pos_3;
764 if (p.parseFnCallArguments()) break :blk_3 true;
765 p.i = pos_3;
766 break :blk_3 false;
767 }) {}
852 while (p.parseSuffixOp()) {}
768853 break :blk_1 true;
854 } and blk_1: {
855 const pos_1 = p.i;
856 const match_1 = p.parseSuffixOpPrefix();
857 p.i = pos_1;
858 break :blk_1 !match_1;
769859 }) break :blk_0 true;
770860 p.i = pos_0;
771861 break :blk_0 false;
......@@ -845,12 +935,19 @@ const Parser = struct {
845935 pub fn parseIfTypeExpr(p: *Parser) bool {
846936 return blk_0: {
847937 const pos_0 = p.i;
848 if (p.parseIfPrefix() and p.parseTypeExpr() and (blk_3: {
849 const pos_3 = p.i;
850 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseTypeExpr()) break :blk_3 true;
851 p.i = pos_3;
852 break :blk_3 false;
853 } or true)) break :blk_0 true;
938 if (p.parseIfPrefix() and p.parseTypeExpr() and blk_2: {
939 const pos_2 = p.i;
940 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseTypeExpr()) break :blk_2 true;
941 p.i = pos_2;
942 if (blk_3: {
943 const pos_3 = p.i;
944 const match_3 = p.parseKEYWORD_else();
945 p.i = pos_3;
946 break :blk_3 !match_3;
947 }) break :blk_2 true;
948 p.i = pos_2;
949 break :blk_2 false;
950 }) break :blk_0 true;
854951 p.i = pos_0;
855952 break :blk_0 false;
856953 };
......@@ -905,12 +1002,19 @@ const Parser = struct {
9051002 pub fn parseWhileTypeExpr(p: *Parser) bool {
9061003 return blk_0: {
9071004 const pos_0 = p.i;
908 if (p.parseWhilePrefix() and p.parseTypeExpr() and (blk_3: {
909 const pos_3 = p.i;
910 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseTypeExpr()) break :blk_3 true;
911 p.i = pos_3;
912 break :blk_3 false;
913 } or true)) break :blk_0 true;
1005 if (p.parseWhilePrefix() and p.parseTypeExpr() and blk_2: {
1006 const pos_2 = p.i;
1007 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseTypeExpr()) break :blk_2 true;
1008 p.i = pos_2;
1009 if (blk_3: {
1010 const pos_3 = p.i;
1011 const match_3 = p.parseKEYWORD_else();
1012 p.i = pos_3;
1013 break :blk_3 !match_3;
1014 }) break :blk_2 true;
1015 p.i = pos_2;
1016 break :blk_2 false;
1017 }) break :blk_0 true;
9141018 p.i = pos_0;
9151019 break :blk_0 false;
9161020 };
......@@ -1539,6 +1643,20 @@ const Parser = struct {
15391643 break :blk_0 false;
15401644 };
15411645 }
1646 pub fn parsePrefixTypeOpPrefix(p: *Parser) bool {
1647 return blk_0: {
1648 const pos_0 = p.i;
1649 if (p.parseQUESTIONMARK()) break :blk_0 true;
1650 p.i = pos_0;
1651 if (p.parseKEYWORD_anyframe() and p.parseMINUSRARROW()) break :blk_0 true;
1652 p.i = pos_0;
1653 if (p.parseLBRACKET()) break :blk_0 true;
1654 p.i = pos_0;
1655 if (p.parseASTERISK()) break :blk_0 true;
1656 p.i = pos_0;
1657 break :blk_0 false;
1658 };
1659 }
15421660 pub fn parseSuffixOp(p: *Parser) bool {
15431661 return blk_0: {
15441662 const pos_0 = p.i;
......@@ -1560,6 +1678,24 @@ const Parser = struct {
15601678 p.i = pos_0;
15611679 if (p.parseDOTQUESTIONMARK()) break :blk_0 true;
15621680 p.i = pos_0;
1681 if (p.parseFnCallArguments()) break :blk_0 true;
1682 p.i = pos_0;
1683 break :blk_0 false;
1684 };
1685 }
1686 pub fn parseSuffixOpPrefix(p: *Parser) bool {
1687 return blk_0: {
1688 const pos_0 = p.i;
1689 if (p.parseLBRACKET()) break :blk_0 true;
1690 p.i = pos_0;
1691 if (p.parseDOT() and p.parseIDENTIFIER()) break :blk_0 true;
1692 p.i = pos_0;
1693 if (p.parseDOTASTERISK()) break :blk_0 true;
1694 p.i = pos_0;
1695 if (p.parseDOTQUESTIONMARK()) break :blk_0 true;
1696 p.i = pos_0;
1697 if (p.parseLPAREN()) break :blk_0 true;
1698 p.i = pos_0;
15631699 break :blk_0 false;
15641700 };
15651701 }
......@@ -1610,7 +1746,12 @@ const Parser = struct {
16101746 pub fn parseArrayTypeStart(p: *Parser) bool {
16111747 return blk_0: {
16121748 const pos_0 = p.i;
1613 if (p.parseLBRACKET() and p.parseExpr() and (blk_3: {
1749 if (p.parseLBRACKET() and blk_1: {
1750 const pos_1 = p.i;
1751 const match_1 = p.parseASTERISK();
1752 p.i = pos_1;
1753 break :blk_1 !match_1;
1754 } and p.parseExpr() and (blk_3: {
16141755 const pos_3 = p.i;
16151756 if (p.parseCOLON() and p.parseExpr()) break :blk_3 true;
16161757 p.i = pos_3;