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,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
1Root <- ContainerMembers skip eof39Root <- ContainerMembers skip eof
240
3# *** Top level ***41# *** Top level ***
...@@ -66,27 +104,27 @@ VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL...@@ -66,27 +104,27 @@ VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL
66# *** Expression Level ***104# *** Expression Level ***
67105
68# An assignment or a destructure whose LHS are all lvalue expressions.106# 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
73Expr <- BoolOrExpr111Expr <- 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* PrimaryExpr127PrefixExpr <- PrefixOp* !PrefixOp PrimaryExpr
90128
91PrimaryExpr129PrimaryExpr
92 <- AsmExpr130 <- AsmExpr
...@@ -101,7 +139,7 @@ PrimaryExpr...@@ -101,7 +139,7 @@ PrimaryExpr
101 / Block139 / Block
102 / CurlySuffixExpr140 / CurlySuffixExpr
103141
104IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?142IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else)
105143
106Block <- LBRACE BlockStatement* RBRACE144Block <- LBRACE BlockStatement* RBRACE
107145
...@@ -111,19 +149,18 @@ ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else)...@@ -111,19 +149,18 @@ ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else)
111149
112WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?150WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
113151
114CurlySuffixExpr <- TypeExpr InitList?152CurlySuffixExpr <- TypeExpr (InitList / !LBRACE)
115153
116InitList154InitList
117 <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE155 <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
118 / LBRACE Expr (COMMA Expr)* COMMA? RBRACE156 / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
119 / LBRACE RBRACE157 / LBRACE RBRACE
120158
121TypeExpr <- PrefixTypeOp* ErrorUnionExpr159TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr
122160
123ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?161ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK)
124162
125SuffixExpr163SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix
126 <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
127164
128PrimaryTypeExpr165PrimaryTypeExpr
129 <- BUILTINIDENTIFIER FnCallArguments166 <- BUILTINIDENTIFIER FnCallArguments
...@@ -150,7 +187,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE...@@ -150,7 +187,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
150187
151GroupedExpr <- LPAREN Expr RPAREN188GroupedExpr <- LPAREN Expr RPAREN
152189
153IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?190IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
154191
155LabeledTypeExpr192LabeledTypeExpr
156 <- BlockLabel Block193 <- BlockLabel Block
...@@ -161,7 +198,7 @@ LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)...@@ -161,7 +198,7 @@ LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
161198
162ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else)199ForTypeExpr <- 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
166SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE203SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
167204
...@@ -319,11 +356,25 @@ PrefixTypeOp...@@ -319,11 +356,25 @@ PrefixTypeOp
319 / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?356 / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
320 / ArrayTypeStart357 / ArrayTypeStart
321358
359PrefixTypeOpPrefix
360 <- QUESTIONMARK
361 / KEYWORD_anyframe MINUSRARROW
362 / LBRACKET
363 / ASTERISK
364
322SuffixOp365SuffixOp
323 <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET366 <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET
324 / DOT IDENTIFIER367 / DOT IDENTIFIER
325 / DOTASTERISK368 / DOTASTERISK
326 / DOTQUESTIONMARK369 / DOTQUESTIONMARK
370 / FnCallArguments
371
372SuffixOpPrefix
373 <- LBRACKET
374 / DOT IDENTIFIER
375 / DOTASTERISK
376 / DOTQUESTIONMARK
377 / LPAREN
327378
328FnCallArguments <- LPAREN ExprList RPAREN379FnCallArguments <- LPAREN ExprList RPAREN
329380
...@@ -334,7 +385,7 @@ SinglePtrTypeStart <- ASTERISK...@@ -334,7 +385,7 @@ SinglePtrTypeStart <- ASTERISK
334385
335ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET386ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
336387
337ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET388ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET
338389
339# ContainerDecl specific390# ContainerDecl specific
340ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE391ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
lib/std/zig/Parse.zig+126-113
...@@ -1,5 +1,18 @@...@@ -1,5 +1,18 @@
1//! Represents in-progress parsing, will be converted to an Ast after completion.1//! 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
3pub const Error = error{ParseError} || Allocator.Error;16pub const Error = error{ParseError} || Allocator.Error;
417
5gpa: Allocator,18gpa: Allocator,
...@@ -1411,7 +1424,7 @@ fn parseBlockExpr(p: *Parse) Error!?Node.Index {...@@ -1411,7 +1424,7 @@ fn parseBlockExpr(p: *Parse) Error!?Node.Index {
1411 }1424 }
1412}1425}
14131426
1414/// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)?1427/// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA)
1415///1428///
1416/// AssignOp1429/// AssignOp
1417/// <- ASTERISKEQUAL1430/// <- ASTERISKEQUAL
...@@ -1437,7 +1450,7 @@ fn parseAssignExpr(p: *Parse) !?Node.Index {...@@ -1437,7 +1450,7 @@ fn parseAssignExpr(p: *Parse) !?Node.Index {
1437 return try p.finishAssignExpr(expr);1450 return try p.finishAssignExpr(expr);
1438}1451}
14391452
1440/// SingleAssignExpr <- Expr (AssignOp Expr)?1453/// SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp)
1441fn parseSingleAssignExpr(p: *Parse) !?Node.Index {1454fn parseSingleAssignExpr(p: *Parse) !?Node.Index {
1442 const lhs = try p.parseExpr() orelse return null;1455 const lhs = try p.parseExpr() orelse return null;
1443 const tag = assignOpNode(p.tokenTag(p.tok_i)) orelse return lhs;1456 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 {...@@ -1643,7 +1656,7 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index {
1643 return node;1656 return node;
1644}1657}
16451658
1646/// PrefixExpr <- PrefixOp* PrimaryExpr1659/// PrefixExpr <- PrefixOp* PrimaryExpr / !PrefixOp
1647///1660///
1648/// PrefixOp1661/// PrefixOp
1649/// <- EXCLAMATIONMARK1662/// <- EXCLAMATIONMARK
...@@ -1673,23 +1686,28 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index {...@@ -1673,23 +1686,28 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index {
1673 return try p.parsePrefixExpr() orelse return p.fail(.expected_prefix_expr);1686 return try p.parsePrefixExpr() orelse return p.fail(.expected_prefix_expr);
1674}1687}
16751688
1676/// TypeExpr <- PrefixTypeOp* ErrorUnionExpr1689/// TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr
1677///1690///
1678/// PrefixTypeOp1691/// PrefixTypeOp
1679/// <- QUESTIONMARK1692/// <- QUESTIONMARK
1680/// / KEYWORD_anyframe MINUSRARROW1693/// / KEYWORD_anyframe MINUSRARROW
1681/// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?1694/// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
1682/// / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?1695/// / 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)*
1684/// / ArrayTypeStart1696/// / ArrayTypeStart
1685///1697///
1698/// PrefixTypeOpPrefix
1699/// <- QUESTIONMARK
1700/// / KEYWORD_anyframe MINUSRARROW
1701/// / LBRACKET
1702/// / ASTERISK
1703///
1686/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET1704/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
1687///1705///
1688/// SinglePtrTypeStart <- ASTERISK1706/// SinglePtrTypeStart <- ASTERISK
1689///1707///
1690/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET1708/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
1691///1709///
1692/// ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET1710/// ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET
1693///1711///
1694/// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN1712/// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
1695fn parseTypeExpr(p: *Parse) Error!?Node.Index {1713fn parseTypeExpr(p: *Parse) Error!?Node.Index {
...@@ -1904,19 +1922,19 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index {...@@ -1904,19 +1922,19 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index {
1904/// PrimaryExpr1922/// PrimaryExpr
1905/// <- AsmExpr1923/// <- AsmExpr
1906/// / IfExpr1924/// / IfExpr
1907/// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)1925/// / KEYWORD_break BreakLabel? Expr?
1908/// / KEYWORD_comptime Expr !ExprSuffix1926/// / KEYWORD_comptime Expr
1909/// / KEYWORD_nosuspend Expr !ExprSuffix1927/// / KEYWORD_nosuspend Expr
1910/// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)1928/// / KEYWORD_continue BreakLabel? Expr?
1911/// / KEYWORD_resume Expr !ExprSuffix1929/// / KEYWORD_resume Expr
1912/// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart)1930/// / KEYWORD_return Expr?
1913/// / BlockLabel? LoopExpr1931/// / BlockLabel? LoopExpr
1914/// / Block1932/// / Block
1915/// / CurlySuffixExpr1933/// / CurlySuffixExpr
1916fn parsePrimaryExpr(p: *Parse) !?Node.Index {1934fn parsePrimaryExpr(p: *Parse) !?Node.Index {
1917 switch (p.tokenTag(p.tok_i)) {1935 switch (p.tokenTag(p.tok_i)) {
1918 .keyword_asm => return try p.expectAsmExpr(),1936 .keyword_asm => return try p.expectAsmExpr(),
1919 .keyword_if => return try p.parseIfExpr(),1937 .keyword_if => return try p.expectIf(expectExpr),
1920 .keyword_break => {1938 .keyword_break => {
1921 return try p.addNode(.{1939 return try p.addNode(.{
1922 .tag = .@"break",1940 .tag = .@"break",
...@@ -1971,18 +1989,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {...@@ -1971,18 +1989,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {
1971 .keyword_inline => {1989 .keyword_inline => {
1972 p.tok_i += 3;1990 p.tok_i += 3;
1973 switch (p.tokenTag(p.tok_i)) {1991 switch (p.tokenTag(p.tok_i)) {
1974 .keyword_for => return try p.parseFor(expectExpr),1992 .keyword_for => return try p.expectFor(expectExpr),
1975 .keyword_while => return try p.parseWhileExpr(),1993 .keyword_while => return try p.expectWhileExpr(),
1976 else => return p.fail(.expected_inlinable),1994 else => return p.fail(.expected_inlinable),
1977 }1995 }
1978 },1996 },
1979 .keyword_for => {1997 .keyword_for => {
1980 p.tok_i += 2;1998 p.tok_i += 2;
1981 return try p.parseFor(expectExpr);1999 return try p.expectFor(expectExpr);
1982 },2000 },
1983 .keyword_while => {2001 .keyword_while => {
1984 p.tok_i += 2;2002 p.tok_i += 2;
1985 return try p.parseWhileExpr();2003 return try p.expectWhileExpr();
1986 },2004 },
1987 else => return try p.parseCurlySuffixExpr(),2005 else => return try p.parseCurlySuffixExpr(),
1988 }2006 }
...@@ -1993,23 +2011,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {...@@ -1993,23 +2011,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {
1993 .keyword_inline => {2011 .keyword_inline => {
1994 p.tok_i += 1;2012 p.tok_i += 1;
1995 switch (p.tokenTag(p.tok_i)) {2013 switch (p.tokenTag(p.tok_i)) {
1996 .keyword_for => return try p.parseFor(expectExpr),2014 .keyword_for => return try p.expectFor(expectExpr),
1997 .keyword_while => return try p.parseWhileExpr(),2015 .keyword_while => return try p.expectWhileExpr(),
1998 else => return p.fail(.expected_inlinable),2016 else => return p.fail(.expected_inlinable),
1999 }2017 }
2000 },2018 },
2001 .keyword_for => return try p.parseFor(expectExpr),2019 .keyword_for => return try p.expectFor(expectExpr),
2002 .keyword_while => return try p.parseWhileExpr(),2020 .keyword_while => return try p.expectWhileExpr(),
2003 .l_brace => return try p.parseBlock(),2021 .l_brace => return try p.parseBlock(),
2004 else => return try p.parseCurlySuffixExpr(),2022 else => return try p.parseCurlySuffixExpr(),
2005 }2023 }
2006}2024}
20072025
2008/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
2009fn parseIfExpr(p: *Parse) !?Node.Index {
2010 return try p.parseIf(expectExpr);
2011}
2012
2013/// Block <- LBRACE BlockStatement* RBRACE2026/// Block <- LBRACE BlockStatement* RBRACE
2014fn parseBlock(p: *Parse) !?Node.Index {2027fn parseBlock(p: *Parse) !?Node.Index {
2015 const lbrace = p.eatToken(.l_brace) orelse return null;2028 const lbrace = p.eatToken(.l_brace) orelse return null;
...@@ -2104,8 +2117,8 @@ fn forPrefix(p: *Parse) Error!usize {...@@ -2104,8 +2117,8 @@ fn forPrefix(p: *Parse) Error!usize {
2104/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?2117/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2105///2118///
2106/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi2119/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi
2107fn parseWhileExpr(p: *Parse) !?Node.Index {2120fn expectWhileExpr(p: *Parse) !Node.Index {
2108 const while_token = p.eatToken(.keyword_while) orelse return null;2121 const while_token = p.assertToken(.keyword_while);
2109 _ = try p.expectToken(.l_paren);2122 _ = try p.expectToken(.l_paren);
2110 const condition = try p.expectExpr();2123 const condition = try p.expectExpr();
2111 _ = try p.expectToken(.r_paren);2124 _ = try p.expectToken(.r_paren);
...@@ -2153,7 +2166,7 @@ fn parseWhileExpr(p: *Parse) !?Node.Index {...@@ -2153,7 +2166,7 @@ fn parseWhileExpr(p: *Parse) !?Node.Index {
2153 });2166 });
2154}2167}
21552168
2156/// CurlySuffixExpr <- TypeExpr InitList?2169/// CurlySuffixExpr <- TypeExpr (InitList / !LBRACE)
2157///2170///
2158/// InitList2171/// InitList
2159/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE2172/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
...@@ -2255,7 +2268,7 @@ fn parseCurlySuffixExpr(p: *Parse) !?Node.Index {...@@ -2255,7 +2268,7 @@ fn parseCurlySuffixExpr(p: *Parse) !?Node.Index {
2255 }2268 }
2256}2269}
22572270
2258/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?2271/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK)
2259fn parseErrorUnionExpr(p: *Parse) !?Node.Index {2272fn parseErrorUnionExpr(p: *Parse) !?Node.Index {
2260 const suffix_expr = try p.parseSuffixExpr() orelse return null;2273 const suffix_expr = try p.parseSuffixExpr() orelse return null;
2261 const bang = p.eatToken(.bang) orelse return suffix_expr;2274 const bang = p.eatToken(.bang) orelse return suffix_expr;
...@@ -2269,59 +2282,13 @@ fn parseErrorUnionExpr(p: *Parse) !?Node.Index {...@@ -2269,59 +2282,13 @@ fn parseErrorUnionExpr(p: *Parse) !?Node.Index {
2269 });2282 });
2270}2283}
22712284
2272/// SuffixExpr2285/// SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix
2273/// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
2274///
2275/// FnCallArguments <- LPAREN ExprList RPAREN
2276///
2277/// ExprList <- (Expr COMMA)* Expr?
2278fn parseSuffixExpr(p: *Parse) !?Node.Index {2286fn parseSuffixExpr(p: *Parse) !?Node.Index {
2279 var res = try p.parsePrimaryTypeExpr() orelse return null;2287 var res = try p.parsePrimaryTypeExpr() orelse return null;
2280 while (true) {2288 while (try p.parseSuffixOp(res)) |suffix_op| {
2281 const opt_suffix_op = try p.parseSuffixOp(res);2289 res = suffix_op;
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 };
2324 }2290 }
2291 return res;
2325}2292}
23262293
2327/// PrimaryTypeExpr2294/// PrimaryTypeExpr
...@@ -2331,17 +2298,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index {...@@ -2331,17 +2298,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index {
2331/// / DOT IDENTIFIER2298/// / DOT IDENTIFIER
2332/// / DOT InitList2299/// / DOT InitList
2333/// / ErrorSetDecl2300/// / ErrorSetDecl
2334/// / FLOAT
2335/// / FnProto2301/// / FnProto
2336/// / GroupedExpr2302/// / GroupedExpr
2337/// / LabeledTypeExpr2303/// / LabeledTypeExpr
2338/// / IDENTIFIER !(COLON LabelableExpr)2304/// / IDENTIFIER
2339/// / IfTypeExpr2305/// / IfTypeExpr
2340/// / INTEGER2306/// / KEYWORD_comptime TypeExpr
2341/// / KEYWORD_comptime TypeExpr !ExprSuffix
2342/// / KEYWORD_error DOT IDENTIFIER2307/// / KEYWORD_error DOT IDENTIFIER
2343/// / KEYWORD_anyframe2308/// / KEYWORD_anyframe
2344/// / KEYWORD_unreachable2309/// / KEYWORD_unreachable
2310/// / NUMBERLITERAL
2345/// / STRINGLITERAL2311/// / STRINGLITERAL
2346///2312///
2347/// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto2313/// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
...@@ -2396,23 +2362,23 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {...@@ -2396,23 +2362,23 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
2396 });2362 });
2397 },2363 },
23982364
2399 .builtin => return try p.parseBuiltinCall(),2365 .builtin => return try p.expectBuiltinCall(),
2400 .keyword_fn => return try p.parseFnProto(),2366 .keyword_fn => return (try p.parseFnProto()).?,
2401 .keyword_if => return try p.parseIf(expectTypeExpr),2367 .keyword_if => return try p.expectIf(expectTypeExpr),
2402 .keyword_switch => return try p.expectSwitchExpr(false),2368 .keyword_switch => return try p.expectSwitchExpr(false),
24032369
2404 .keyword_extern,2370 .keyword_extern,
2405 .keyword_packed,2371 .keyword_packed,
2406 => {2372 => {
2407 p.tok_i += 1;2373 p.tok_i += 1;
2408 return try p.parseContainerDeclAuto();2374 return try p.expectContainerDeclAuto();
2409 },2375 },
24102376
2411 .keyword_struct,2377 .keyword_struct,
2412 .keyword_opaque,2378 .keyword_opaque,
2413 .keyword_enum,2379 .keyword_enum,
2414 .keyword_union,2380 .keyword_union,
2415 => return try p.parseContainerDeclAuto(),2381 => return try p.expectContainerDeclAuto(),
24162382
2417 .keyword_comptime => return try p.addNode(.{2383 .keyword_comptime => return try p.addNode(.{
2418 .tag = .@"comptime",2384 .tag = .@"comptime",
...@@ -2438,18 +2404,18 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {...@@ -2438,18 +2404,18 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
2438 .keyword_inline => {2404 .keyword_inline => {
2439 p.tok_i += 3;2405 p.tok_i += 3;
2440 switch (p.tokenTag(p.tok_i)) {2406 switch (p.tokenTag(p.tok_i)) {
2441 .keyword_for => return try p.parseFor(expectTypeExpr),2407 .keyword_for => return try p.expectFor(expectTypeExpr),
2442 .keyword_while => return try p.parseWhileTypeExpr(),2408 .keyword_while => return try p.expectWhileTypeExpr(),
2443 else => return p.fail(.expected_inlinable),2409 else => return p.fail(.expected_inlinable),
2444 }2410 }
2445 },2411 },
2446 .keyword_for => {2412 .keyword_for => {
2447 p.tok_i += 2;2413 p.tok_i += 2;
2448 return try p.parseFor(expectTypeExpr);2414 return try p.expectFor(expectTypeExpr);
2449 },2415 },
2450 .keyword_while => {2416 .keyword_while => {
2451 p.tok_i += 2;2417 p.tok_i += 2;
2452 return try p.parseWhileTypeExpr();2418 return try p.expectWhileTypeExpr();
2453 },2419 },
2454 .keyword_switch => {2420 .keyword_switch => {
2455 p.tok_i += 2;2421 p.tok_i += 2;
...@@ -2457,7 +2423,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {...@@ -2457,7 +2423,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
2457 },2423 },
2458 .l_brace => {2424 .l_brace => {
2459 p.tok_i += 2;2425 p.tok_i += 2;
2460 return try p.parseBlock();2426 return (try p.parseBlock()).?;
2461 },2427 },
2462 else => return try p.addNode(.{2428 else => return try p.addNode(.{
2463 .tag = .identifier,2429 .tag = .identifier,
...@@ -2474,13 +2440,13 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {...@@ -2474,13 +2440,13 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
2474 .keyword_inline => {2440 .keyword_inline => {
2475 p.tok_i += 1;2441 p.tok_i += 1;
2476 switch (p.tokenTag(p.tok_i)) {2442 switch (p.tokenTag(p.tok_i)) {
2477 .keyword_for => return try p.parseFor(expectTypeExpr),2443 .keyword_for => return try p.expectFor(expectTypeExpr),
2478 .keyword_while => return try p.parseWhileTypeExpr(),2444 .keyword_while => return try p.expectWhileTypeExpr(),
2479 else => return p.fail(.expected_inlinable),2445 else => return p.fail(.expected_inlinable),
2480 }2446 }
2481 },2447 },
2482 .keyword_for => return try p.parseFor(expectTypeExpr),2448 .keyword_for => return try p.expectFor(expectTypeExpr),
2483 .keyword_while => return try p.parseWhileTypeExpr(),2449 .keyword_while => return try p.expectWhileTypeExpr(),
2484 .period => switch (p.tokenTag(p.tok_i + 1)) {2450 .period => switch (p.tokenTag(p.tok_i + 1)) {
2485 .identifier => {2451 .identifier => {
2486 p.tok_i += 1;2452 p.tok_i += 1;
...@@ -2608,10 +2574,8 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {...@@ -2608,10 +2574,8 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
2608 },2574 },
2609 else => {2575 else => {
2610 const main_token = p.nextToken();2576 const main_token = p.nextToken();
2611 const period = p.eatToken(.period);2577 _ = try p.expectToken(.period);
2612 if (period == null) return p.failExpected(.period);2578 _ = try p.expectToken(.identifier);
2613 const identifier = p.eatToken(.identifier);
2614 if (identifier == null) return p.failExpected(.identifier);
2615 return try p.addNode(.{2579 return try p.addNode(.{
2616 .tag = .error_value,2580 .tag = .error_value,
2617 .main_token = main_token,2581 .main_token = main_token,
...@@ -2637,9 +2601,9 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index {...@@ -2637,9 +2601,9 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index {
26372601
2638/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?2602/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2639///2603///
2640/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix2604/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
2641fn parseWhileTypeExpr(p: *Parse) !?Node.Index {2605fn expectWhileTypeExpr(p: *Parse) !Node.Index {
2642 const while_token = p.eatToken(.keyword_while) orelse return null;2606 const while_token = p.assertToken(.keyword_while);
2643 _ = try p.expectToken(.l_paren);2607 _ = try p.expectToken(.l_paren);
2644 const condition = try p.expectExpr();2608 const condition = try p.expectExpr();
2645 _ = try p.expectToken(.r_paren);2609 _ = try p.expectToken(.r_paren);
...@@ -3106,6 +3070,11 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers {...@@ -3106,6 +3070,11 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers {
3106/// / DOT IDENTIFIER3070/// / DOT IDENTIFIER
3107/// / DOTASTERISK3071/// / DOTASTERISK
3108/// / DOTQUESTIONMARK3072/// / DOTQUESTIONMARK
3073/// / FnCallArguments
3074///
3075/// FnCallArguments <- LPAREN ExprList RPAREN
3076///
3077/// ExprList <- (Expr COMMA)* Expr?
3109fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {3078fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
3110 switch (p.tokenTag(p.tok_i)) {3079 switch (p.tokenTag(p.tok_i)) {
3111 .l_bracket => {3080 .l_bracket => {
...@@ -3195,6 +3164,46 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {...@@ -3195,6 +3164,46 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
3195 return null;3164 return null;
3196 },3165 },
3197 },3166 },
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 },
3198 else => return null,3207 else => return null,
3199 }3208 }
3200}3209}
...@@ -3208,7 +3217,7 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {...@@ -3208,7 +3217,7 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
3208/// / KEYWORD_opaque3217/// / KEYWORD_opaque
3209/// / KEYWORD_enum (LPAREN Expr RPAREN)?3218/// / KEYWORD_enum (LPAREN Expr RPAREN)?
3210/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?3219/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
3211fn parseContainerDeclAuto(p: *Parse) !?Node.Index {3220fn expectContainerDeclAuto(p: *Parse) !Node.Index {
3212 const main_token = p.nextToken();3221 const main_token = p.nextToken();
3213 const arg_expr = switch (p.tokenTag(main_token)) {3222 const arg_expr = switch (p.tokenTag(main_token)) {
3214 .keyword_opaque => null,3223 .keyword_opaque => null,
...@@ -3431,7 +3440,7 @@ fn parseParamDeclList(p: *Parse) !SmallSpan {...@@ -3431,7 +3440,7 @@ fn parseParamDeclList(p: *Parse) !SmallSpan {
3431/// FnCallArguments <- LPAREN ExprList RPAREN3440/// FnCallArguments <- LPAREN ExprList RPAREN
3432///3441///
3433/// ExprList <- (Expr COMMA)* Expr?3442/// ExprList <- (Expr COMMA)* Expr?
3434fn parseBuiltinCall(p: *Parse) !Node.Index {3443fn expectBuiltinCall(p: *Parse) !Node.Index {
3435 const builtin_token = p.assertToken(.builtin);3444 const builtin_token = p.assertToken(.builtin);
3436 _ = p.eatToken(.l_paren) orelse {3445 _ = p.eatToken(.l_paren) orelse {
3437 try p.warn(.expected_param_list);3446 try p.warn(.expected_param_list);
...@@ -3479,9 +3488,13 @@ fn parseBuiltinCall(p: *Parse) !Node.Index {...@@ -3479,9 +3488,13 @@ fn parseBuiltinCall(p: *Parse) !Node.Index {
3479 }3488 }
3480}3489}
34813490
3491/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else)
3492///
3493/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
3494///
3482/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?3495/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
3483fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index {3496fn expectIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index {
3484 const if_token = p.eatToken(.keyword_if) orelse return null;3497 const if_token = p.assertToken(.keyword_if);
3485 _ = try p.expectToken(.l_paren);3498 _ = try p.expectToken(.l_paren);
3486 const condition = try p.expectExpr();3499 const condition = try p.expectExpr();
3487 _ = try p.expectToken(.r_paren);3500 _ = try p.expectToken(.r_paren);
...@@ -3513,11 +3526,11 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N...@@ -3513,11 +3526,11 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N
3513 });3526 });
3514}3527}
35153528
3516/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix3529/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else)
3517///3530///
3518/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix3531/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else)
3519fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index {3532fn expectFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index {
3520 const for_token = p.eatToken(.keyword_for) orelse return null;3533 const for_token = p.assertToken(.keyword_for);
35213534
3522 const scratch_top = p.scratch.items.len;3535 const scratch_top = p.scratch.items.len;
3523 defer p.scratch.shrinkRetainingCapacity(scratch_top);3536 defer p.scratch.shrinkRetainingCapacity(scratch_top);
lib/std/zig/parser_generated_oracle.zig+204-63
...@@ -429,25 +429,37 @@ const Parser = struct {...@@ -429,25 +429,37 @@ const Parser = struct {
429 pub fn parseAssignExpr(p: *Parser) bool {429 pub fn parseAssignExpr(p: *Parser) bool {
430 return blk_0: {430 return blk_0: {
431 const pos_0 = p.i;431 const pos_0 = p.i;
432 if (p.parseExpr() and (blk_3: {432 if (p.parseExpr() and blk_2: {
433 const pos_3 = p.i;433 const pos_2 = p.i;
434 if (p.parseAssignOp() and p.parseExpr()) break :blk_3 true;434 if (p.parseAssignOp() and p.parseExpr()) break :blk_2 true;
435 p.i = pos_3;435 p.i = pos_2;
436 if (blk_4: {436 if (blk_3: {
437 var match_4 = false;437 var match_3 = false;
438 while (blk_6: {438 while (blk_5: {
439 const pos_6 = p.i;439 const pos_5 = p.i;
440 if (p.parseCOMMA() and p.parseExpr()) break :blk_6 true;440 if (p.parseCOMMA() and p.parseExpr()) break :blk_5 true;
441 p.i = pos_6;441 p.i = pos_5;
442 break :blk_6 false;442 break :blk_5 false;
443 }) {443 }) {
444 match_4 = true;444 match_3 = true;
445 }445 }
446 break :blk_4 match_4;446 break :blk_3 match_3;
447 } and p.parseEQUAL() and p.parseExpr()) break :blk_3 true;447 } and p.parseEQUAL() and p.parseExpr()) break :blk_2 true;
448 p.i = pos_3;448 p.i = pos_2;
449 break :blk_3 false;449 if (blk_3: {
450 } or true)) break :blk_0 true;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;
451 p.i = pos_0;463 p.i = pos_0;
452 break :blk_0 false;464 break :blk_0 false;
453 };465 };
...@@ -455,12 +467,19 @@ const Parser = struct {...@@ -455,12 +467,19 @@ const Parser = struct {
455 pub fn parseSingleAssignExpr(p: *Parser) bool {467 pub fn parseSingleAssignExpr(p: *Parser) bool {
456 return blk_0: {468 return blk_0: {
457 const pos_0 = p.i;469 const pos_0 = p.i;
458 if (p.parseExpr() and (blk_3: {470 if (p.parseExpr() and blk_2: {
459 const pos_3 = p.i;471 const pos_2 = p.i;
460 if (p.parseAssignOp() and p.parseExpr()) break :blk_3 true;472 if (p.parseAssignOp() and p.parseExpr()) break :blk_2 true;
461 p.i = pos_3;473 p.i = pos_2;
462 break :blk_3 false;474 if (blk_3: {
463 } or true)) break :blk_0 true;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;
464 p.i = pos_0;483 p.i = pos_0;
465 break :blk_0 false;484 break :blk_0 false;
466 };485 };
...@@ -484,6 +503,11 @@ const Parser = struct {...@@ -484,6 +503,11 @@ const Parser = struct {
484 break :blk_3 false;503 break :blk_3 false;
485 }) {}504 }) {}
486 break :blk_1 true;505 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;
487 }) break :blk_0 true;511 }) break :blk_0 true;
488 p.i = pos_0;512 p.i = pos_0;
489 break :blk_0 false;513 break :blk_0 false;
...@@ -500,6 +524,11 @@ const Parser = struct {...@@ -500,6 +524,11 @@ const Parser = struct {
500 break :blk_3 false;524 break :blk_3 false;
501 }) {}525 }) {}
502 break :blk_1 true;526 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;
503 }) break :blk_0 true;532 }) break :blk_0 true;
504 p.i = pos_0;533 p.i = pos_0;
505 break :blk_0 false;534 break :blk_0 false;
...@@ -508,12 +537,19 @@ const Parser = struct {...@@ -508,12 +537,19 @@ const Parser = struct {
508 pub fn parseCompareExpr(p: *Parser) bool {537 pub fn parseCompareExpr(p: *Parser) bool {
509 return blk_0: {538 return blk_0: {
510 const pos_0 = p.i;539 const pos_0 = p.i;
511 if (p.parseBitwiseExpr() and (blk_3: {540 if (p.parseBitwiseExpr() and blk_2: {
512 const pos_3 = p.i;541 const pos_2 = p.i;
513 if (p.parseCompareOp() and p.parseBitwiseExpr()) break :blk_3 true;542 if (p.parseCompareOp() and p.parseBitwiseExpr()) break :blk_2 true;
514 p.i = pos_3;543 p.i = pos_2;
515 break :blk_3 false;544 if (blk_3: {
516 } or true)) break :blk_0 true;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;
517 p.i = pos_0;553 p.i = pos_0;
518 break :blk_0 false;554 break :blk_0 false;
519 };555 };
...@@ -529,6 +565,11 @@ const Parser = struct {...@@ -529,6 +565,11 @@ const Parser = struct {
529 break :blk_3 false;565 break :blk_3 false;
530 }) {}566 }) {}
531 break :blk_1 true;567 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;
532 }) break :blk_0 true;573 }) break :blk_0 true;
533 p.i = pos_0;574 p.i = pos_0;
534 break :blk_0 false;575 break :blk_0 false;
...@@ -545,6 +586,11 @@ const Parser = struct {...@@ -545,6 +586,11 @@ const Parser = struct {
545 break :blk_3 false;586 break :blk_3 false;
546 }) {}587 }) {}
547 break :blk_1 true;588 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;
548 }) break :blk_0 true;594 }) break :blk_0 true;
549 p.i = pos_0;595 p.i = pos_0;
550 break :blk_0 false;596 break :blk_0 false;
...@@ -561,6 +607,11 @@ const Parser = struct {...@@ -561,6 +607,11 @@ const Parser = struct {
561 break :blk_3 false;607 break :blk_3 false;
562 }) {}608 }) {}
563 break :blk_1 true;609 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;
564 }) break :blk_0 true;615 }) break :blk_0 true;
565 p.i = pos_0;616 p.i = pos_0;
566 break :blk_0 false;617 break :blk_0 false;
...@@ -577,6 +628,11 @@ const Parser = struct {...@@ -577,6 +628,11 @@ const Parser = struct {
577 break :blk_3 false;628 break :blk_3 false;
578 }) {}629 }) {}
579 break :blk_1 true;630 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;
580 }) break :blk_0 true;636 }) break :blk_0 true;
581 p.i = pos_0;637 p.i = pos_0;
582 break :blk_0 false;638 break :blk_0 false;
...@@ -588,6 +644,11 @@ const Parser = struct {...@@ -588,6 +644,11 @@ const Parser = struct {
588 if (blk_1: {644 if (blk_1: {
589 while (p.parsePrefixOp()) {}645 while (p.parsePrefixOp()) {}
590 break :blk_1 true;646 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;
591 } and p.parsePrimaryExpr()) break :blk_0 true;652 } and p.parsePrimaryExpr()) break :blk_0 true;
592 p.i = pos_0;653 p.i = pos_0;
593 break :blk_0 false;654 break :blk_0 false;
...@@ -624,12 +685,19 @@ const Parser = struct {...@@ -624,12 +685,19 @@ const Parser = struct {
624 pub fn parseIfExpr(p: *Parser) bool {685 pub fn parseIfExpr(p: *Parser) bool {
625 return blk_0: {686 return blk_0: {
626 const pos_0 = p.i;687 const pos_0 = p.i;
627 if (p.parseIfPrefix() and p.parseExpr() and (blk_3: {688 if (p.parseIfPrefix() and p.parseExpr() and blk_2: {
628 const pos_3 = p.i;689 const pos_2 = p.i;
629 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseExpr()) break :blk_3 true;690 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseExpr()) break :blk_2 true;
630 p.i = pos_3;691 p.i = pos_2;
631 break :blk_3 false;692 if (blk_3: {
632 } or true)) break :blk_0 true;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;
633 p.i = pos_0;701 p.i = pos_0;
634 break :blk_0 false;702 break :blk_0 false;
635 };703 };
...@@ -696,7 +764,19 @@ const Parser = struct {...@@ -696,7 +764,19 @@ const Parser = struct {
696 pub fn parseCurlySuffixExpr(p: *Parser) bool {764 pub fn parseCurlySuffixExpr(p: *Parser) bool {
697 return blk_0: {765 return blk_0: {
698 const pos_0 = p.i;766 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;
700 p.i = pos_0;780 p.i = pos_0;
701 break :blk_0 false;781 break :blk_0 false;
702 };782 };
...@@ -735,6 +815,11 @@ const Parser = struct {...@@ -735,6 +815,11 @@ const Parser = struct {
735 if (blk_1: {815 if (blk_1: {
736 while (p.parsePrefixTypeOp()) {}816 while (p.parsePrefixTypeOp()) {}
737 break :blk_1 true;817 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;
738 } and p.parseErrorUnionExpr()) break :blk_0 true;823 } and p.parseErrorUnionExpr()) break :blk_0 true;
739 p.i = pos_0;824 p.i = pos_0;
740 break :blk_0 false;825 break :blk_0 false;
...@@ -743,12 +828,19 @@ const Parser = struct {...@@ -743,12 +828,19 @@ const Parser = struct {
743 pub fn parseErrorUnionExpr(p: *Parser) bool {828 pub fn parseErrorUnionExpr(p: *Parser) bool {
744 return blk_0: {829 return blk_0: {
745 const pos_0 = p.i;830 const pos_0 = p.i;
746 if (p.parseSuffixExpr() and (blk_3: {831 if (p.parseSuffixExpr() and blk_2: {
747 const pos_3 = p.i;832 const pos_2 = p.i;
748 if (p.parseEXCLAMATIONMARK() and p.parseTypeExpr()) break :blk_3 true;833 if (p.parseEXCLAMATIONMARK() and p.parseTypeExpr()) break :blk_2 true;
749 p.i = pos_3;834 p.i = pos_2;
750 break :blk_3 false;835 if (blk_3: {
751 } or true)) break :blk_0 true;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;
752 p.i = pos_0;844 p.i = pos_0;
753 break :blk_0 false;845 break :blk_0 false;
754 };846 };
...@@ -757,15 +849,13 @@ const Parser = struct {...@@ -757,15 +849,13 @@ const Parser = struct {
757 return blk_0: {849 return blk_0: {
758 const pos_0 = p.i;850 const pos_0 = p.i;
759 if (p.parsePrimaryTypeExpr() and blk_1: {851 if (p.parsePrimaryTypeExpr() and blk_1: {
760 while (blk_3: {852 while (p.parseSuffixOp()) {}
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 }) {}
768 break :blk_1 true;853 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;
769 }) break :blk_0 true;859 }) break :blk_0 true;
770 p.i = pos_0;860 p.i = pos_0;
771 break :blk_0 false;861 break :blk_0 false;
...@@ -845,12 +935,19 @@ const Parser = struct {...@@ -845,12 +935,19 @@ const Parser = struct {
845 pub fn parseIfTypeExpr(p: *Parser) bool {935 pub fn parseIfTypeExpr(p: *Parser) bool {
846 return blk_0: {936 return blk_0: {
847 const pos_0 = p.i;937 const pos_0 = p.i;
848 if (p.parseIfPrefix() and p.parseTypeExpr() and (blk_3: {938 if (p.parseIfPrefix() and p.parseTypeExpr() and blk_2: {
849 const pos_3 = p.i;939 const pos_2 = p.i;
850 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseTypeExpr()) break :blk_3 true;940 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseTypeExpr()) break :blk_2 true;
851 p.i = pos_3;941 p.i = pos_2;
852 break :blk_3 false;942 if (blk_3: {
853 } or true)) break :blk_0 true;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;
854 p.i = pos_0;951 p.i = pos_0;
855 break :blk_0 false;952 break :blk_0 false;
856 };953 };
...@@ -905,12 +1002,19 @@ const Parser = struct {...@@ -905,12 +1002,19 @@ const Parser = struct {
905 pub fn parseWhileTypeExpr(p: *Parser) bool {1002 pub fn parseWhileTypeExpr(p: *Parser) bool {
906 return blk_0: {1003 return blk_0: {
907 const pos_0 = p.i;1004 const pos_0 = p.i;
908 if (p.parseWhilePrefix() and p.parseTypeExpr() and (blk_3: {1005 if (p.parseWhilePrefix() and p.parseTypeExpr() and blk_2: {
909 const pos_3 = p.i;1006 const pos_2 = p.i;
910 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseTypeExpr()) break :blk_3 true;1007 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseTypeExpr()) break :blk_2 true;
911 p.i = pos_3;1008 p.i = pos_2;
912 break :blk_3 false;1009 if (blk_3: {
913 } or true)) break :blk_0 true;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;
914 p.i = pos_0;1018 p.i = pos_0;
915 break :blk_0 false;1019 break :blk_0 false;
916 };1020 };
...@@ -1539,6 +1643,20 @@ const Parser = struct {...@@ -1539,6 +1643,20 @@ const Parser = struct {
1539 break :blk_0 false;1643 break :blk_0 false;
1540 };1644 };
1541 }1645 }
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 }
1542 pub fn parseSuffixOp(p: *Parser) bool {1660 pub fn parseSuffixOp(p: *Parser) bool {
1543 return blk_0: {1661 return blk_0: {
1544 const pos_0 = p.i;1662 const pos_0 = p.i;
...@@ -1560,6 +1678,24 @@ const Parser = struct {...@@ -1560,6 +1678,24 @@ const Parser = struct {
1560 p.i = pos_0;1678 p.i = pos_0;
1561 if (p.parseDOTQUESTIONMARK()) break :blk_0 true;1679 if (p.parseDOTQUESTIONMARK()) break :blk_0 true;
1562 p.i = pos_0;1680 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;
1563 break :blk_0 false;1699 break :blk_0 false;
1564 };1700 };
1565 }1701 }
...@@ -1610,7 +1746,12 @@ const Parser = struct {...@@ -1610,7 +1746,12 @@ const Parser = struct {
1610 pub fn parseArrayTypeStart(p: *Parser) bool {1746 pub fn parseArrayTypeStart(p: *Parser) bool {
1611 return blk_0: {1747 return blk_0: {
1612 const pos_0 = p.i;1748 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: {
1614 const pos_3 = p.i;1755 const pos_3 = p.i;
1615 if (p.parseCOLON() and p.parseExpr()) break :blk_3 true;1756 if (p.parseCOLON() and p.parseExpr()) break :blk_3 true;
1616 p.i = pos_3;1757 p.i = pos_3;