| author | |
| committer | |
| log | 0c7688332d10b5ae460e756c2d5a3f58ead26367 |
| tree | 5784e37e87bee15ccfa4140254ebcd3ba3e3553a |
| parent | b4185600466bd14e39e68cd9f07017a8dc1fcf8e |
| signature |
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 | ||
| 1 | 39 | Root <- ContainerMembers skip eof |
| 2 | 40 | |
| 3 | 41 | # *** Top level *** |
| ... | ... | @@ -66,27 +104,27 @@ VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL |
| 66 | 104 | # *** Expression Level *** |
| 67 | 105 | |
| 68 | 106 | # An assignment or a destructure whose LHS are all lvalue expressions. |
| 69 | AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)? | |
| 107 | AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA) | |
| 70 | 108 | |
| 71 | SingleAssignExpr <- Expr (AssignOp Expr)? | |
| 109 | SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp) | |
| 72 | 110 | |
| 73 | 111 | Expr <- BoolOrExpr |
| 74 | 112 | |
| 75 | BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* | |
| 113 | BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp | |
| 76 | 114 | |
| 77 | BoolAndExpr <- CompareExpr (AndOp CompareExpr)* | |
| 115 | BoolAndExpr <- CompareExpr (AndOp CompareExpr)* !AndOp | |
| 78 | 116 | |
| 79 | CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? | |
| 117 | CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr / !CompareOp) | |
| 80 | 118 | |
| 81 | BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* | |
| 119 | BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* !BitwiseOp | |
| 82 | 120 | |
| 83 | BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* | |
| 121 | BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* !BitShiftOp | |
| 84 | 122 | |
| 85 | AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* | |
| 123 | AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* !AdditionOp | |
| 86 | 124 | |
| 87 | MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* | |
| 125 | MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* !MultiplyOp | |
| 88 | 126 | |
| 89 | PrefixExpr <- PrefixOp* PrimaryExpr | |
| 127 | PrefixExpr <- PrefixOp* !PrefixOp PrimaryExpr | |
| 90 | 128 | |
| 91 | 129 | PrimaryExpr |
| 92 | 130 | <- AsmExpr |
| ... | ... | @@ -101,7 +139,7 @@ PrimaryExpr |
| 101 | 139 | / Block |
| 102 | 140 | / CurlySuffixExpr |
| 103 | 141 | |
| 104 | IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? | |
| 142 | IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else) | |
| 105 | 143 | |
| 106 | 144 | Block <- LBRACE BlockStatement* RBRACE |
| 107 | 145 | |
| ... | ... | @@ -111,19 +149,18 @@ ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) |
| 111 | 149 | |
| 112 | 150 | WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? |
| 113 | 151 | |
| 114 | CurlySuffixExpr <- TypeExpr InitList? | |
| 152 | CurlySuffixExpr <- TypeExpr (InitList / !LBRACE) | |
| 115 | 153 | |
| 116 | 154 | InitList |
| 117 | 155 | <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE |
| 118 | 156 | / LBRACE Expr (COMMA Expr)* COMMA? RBRACE |
| 119 | 157 | / LBRACE RBRACE |
| 120 | 158 | |
| 121 | TypeExpr <- PrefixTypeOp* ErrorUnionExpr | |
| 159 | TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr | |
| 122 | 160 | |
| 123 | ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? | |
| 161 | ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK) | |
| 124 | 162 | |
| 125 | SuffixExpr | |
| 126 | <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* | |
| 163 | SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix | |
| 127 | 164 | |
| 128 | 165 | PrimaryTypeExpr |
| 129 | 166 | <- BUILTINIDENTIFIER FnCallArguments |
| ... | ... | @@ -150,7 +187,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE |
| 150 | 187 | |
| 151 | 188 | GroupedExpr <- LPAREN Expr RPAREN |
| 152 | 189 | |
| 153 | IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? | |
| 190 | IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) | |
| 154 | 191 | |
| 155 | 192 | LabeledTypeExpr |
| 156 | 193 | <- BlockLabel Block |
| ... | ... | @@ -161,7 +198,7 @@ LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) |
| 161 | 198 | |
| 162 | 199 | ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) |
| 163 | 200 | |
| 164 | WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? | |
| 201 | WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) | |
| 165 | 202 | |
| 166 | 203 | SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE |
| 167 | 204 | |
| ... | ... | @@ -319,11 +356,25 @@ PrefixTypeOp |
| 319 | 356 | / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? |
| 320 | 357 | / ArrayTypeStart |
| 321 | 358 | |
| 359 | PrefixTypeOpPrefix | |
| 360 | <- QUESTIONMARK | |
| 361 | / KEYWORD_anyframe MINUSRARROW | |
| 362 | / LBRACKET | |
| 363 | / ASTERISK | |
| 364 | ||
| 322 | 365 | SuffixOp |
| 323 | 366 | <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET |
| 324 | 367 | / DOT IDENTIFIER |
| 325 | 368 | / DOTASTERISK |
| 326 | 369 | / DOTQUESTIONMARK |
| 370 | / FnCallArguments | |
| 371 | ||
| 372 | SuffixOpPrefix | |
| 373 | <- LBRACKET | |
| 374 | / DOT IDENTIFIER | |
| 375 | / DOTASTERISK | |
| 376 | / DOTQUESTIONMARK | |
| 377 | / LPAREN | |
| 327 | 378 | |
| 328 | 379 | FnCallArguments <- LPAREN ExprList RPAREN |
| 329 | 380 | |
| ... | ... | @@ -334,7 +385,7 @@ SinglePtrTypeStart <- ASTERISK |
| 334 | 385 | |
| 335 | 386 | ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET |
| 336 | 387 | |
| 337 | ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET | |
| 388 | ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET | |
| 338 | 389 | |
| 339 | 390 | # ContainerDecl specific |
| 340 | 391 | ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE |
lib/std/zig/Parse.zig+126-113| ... | ... | @@ -1,5 +1,18 @@ |
| 1 | 1 | //! Represents in-progress parsing, will be converted to an Ast after completion. |
| 2 | 2 | |
| 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 | ||
| 3 | 16 | pub const Error = error{ParseError} || Allocator.Error; |
| 4 | 17 | |
| 5 | 18 | gpa: Allocator, |
| ... | ... | @@ -1411,7 +1424,7 @@ fn parseBlockExpr(p: *Parse) Error!?Node.Index { |
| 1411 | 1424 | } |
| 1412 | 1425 | } |
| 1413 | 1426 | |
| 1414 | /// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)? | |
| 1427 | /// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA) | |
| 1415 | 1428 | /// |
| 1416 | 1429 | /// AssignOp |
| 1417 | 1430 | /// <- ASTERISKEQUAL |
| ... | ... | @@ -1437,7 +1450,7 @@ fn parseAssignExpr(p: *Parse) !?Node.Index { |
| 1437 | 1450 | return try p.finishAssignExpr(expr); |
| 1438 | 1451 | } |
| 1439 | 1452 | |
| 1440 | /// SingleAssignExpr <- Expr (AssignOp Expr)? | |
| 1453 | /// SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp) | |
| 1441 | 1454 | fn parseSingleAssignExpr(p: *Parse) !?Node.Index { |
| 1442 | 1455 | const lhs = try p.parseExpr() orelse return null; |
| 1443 | 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 | 1656 | return node; |
| 1644 | 1657 | } |
| 1645 | 1658 | |
| 1646 | /// PrefixExpr <- PrefixOp* PrimaryExpr | |
| 1659 | /// PrefixExpr <- PrefixOp* PrimaryExpr / !PrefixOp | |
| 1647 | 1660 | /// |
| 1648 | 1661 | /// PrefixOp |
| 1649 | 1662 | /// <- EXCLAMATIONMARK |
| ... | ... | @@ -1673,23 +1686,28 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index { |
| 1673 | 1686 | return try p.parsePrefixExpr() orelse return p.fail(.expected_prefix_expr); |
| 1674 | 1687 | } |
| 1675 | 1688 | |
| 1676 | /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr | |
| 1689 | /// TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr | |
| 1677 | 1690 | /// |
| 1678 | 1691 | /// PrefixTypeOp |
| 1679 | 1692 | /// <- QUESTIONMARK |
| 1680 | 1693 | /// / KEYWORD_anyframe MINUSRARROW |
| 1681 | 1694 | /// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? |
| 1682 | 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 | 1696 | /// / ArrayTypeStart |
| 1685 | 1697 | /// |
| 1698 | /// PrefixTypeOpPrefix | |
| 1699 | /// <- QUESTIONMARK | |
| 1700 | /// / KEYWORD_anyframe MINUSRARROW | |
| 1701 | /// / LBRACKET | |
| 1702 | /// / ASTERISK | |
| 1703 | /// | |
| 1686 | 1704 | /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET |
| 1687 | 1705 | /// |
| 1688 | 1706 | /// SinglePtrTypeStart <- ASTERISK |
| 1689 | 1707 | /// |
| 1690 | 1708 | /// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET |
| 1691 | 1709 | /// |
| 1692 | /// ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET | |
| 1710 | /// ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET | |
| 1693 | 1711 | /// |
| 1694 | 1712 | /// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN |
| 1695 | 1713 | fn parseTypeExpr(p: *Parse) Error!?Node.Index { |
| ... | ... | @@ -1904,19 +1922,19 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index { |
| 1904 | 1922 | /// PrimaryExpr |
| 1905 | 1923 | /// <- AsmExpr |
| 1906 | 1924 | /// / 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? | |
| 1913 | 1931 | /// / BlockLabel? LoopExpr |
| 1914 | 1932 | /// / Block |
| 1915 | 1933 | /// / CurlySuffixExpr |
| 1916 | 1934 | fn parsePrimaryExpr(p: *Parse) !?Node.Index { |
| 1917 | 1935 | switch (p.tokenTag(p.tok_i)) { |
| 1918 | 1936 | .keyword_asm => return try p.expectAsmExpr(), |
| 1919 | .keyword_if => return try p.parseIfExpr(), | |
| 1937 | .keyword_if => return try p.expectIf(expectExpr), | |
| 1920 | 1938 | .keyword_break => { |
| 1921 | 1939 | return try p.addNode(.{ |
| 1922 | 1940 | .tag = .@"break", |
| ... | ... | @@ -1971,18 +1989,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index { |
| 1971 | 1989 | .keyword_inline => { |
| 1972 | 1990 | p.tok_i += 3; |
| 1973 | 1991 | 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(), | |
| 1976 | 1994 | else => return p.fail(.expected_inlinable), |
| 1977 | 1995 | } |
| 1978 | 1996 | }, |
| 1979 | 1997 | .keyword_for => { |
| 1980 | 1998 | p.tok_i += 2; |
| 1981 | return try p.parseFor(expectExpr); | |
| 1999 | return try p.expectFor(expectExpr); | |
| 1982 | 2000 | }, |
| 1983 | 2001 | .keyword_while => { |
| 1984 | 2002 | p.tok_i += 2; |
| 1985 | return try p.parseWhileExpr(); | |
| 2003 | return try p.expectWhileExpr(); | |
| 1986 | 2004 | }, |
| 1987 | 2005 | else => return try p.parseCurlySuffixExpr(), |
| 1988 | 2006 | } |
| ... | ... | @@ -1993,23 +2011,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index { |
| 1993 | 2011 | .keyword_inline => { |
| 1994 | 2012 | p.tok_i += 1; |
| 1995 | 2013 | 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(), | |
| 1998 | 2016 | else => return p.fail(.expected_inlinable), |
| 1999 | 2017 | } |
| 2000 | 2018 | }, |
| 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(), | |
| 2003 | 2021 | .l_brace => return try p.parseBlock(), |
| 2004 | 2022 | else => return try p.parseCurlySuffixExpr(), |
| 2005 | 2023 | } |
| 2006 | 2024 | } |
| 2007 | 2025 | |
| 2008 | /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix | |
| 2009 | fn parseIfExpr(p: *Parse) !?Node.Index { | |
| 2010 | return try p.parseIf(expectExpr); | |
| 2011 | } | |
| 2012 | ||
| 2013 | 2026 | /// Block <- LBRACE BlockStatement* RBRACE |
| 2014 | 2027 | fn parseBlock(p: *Parse) !?Node.Index { |
| 2015 | 2028 | const lbrace = p.eatToken(.l_brace) orelse return null; |
| ... | ... | @@ -2104,8 +2117,8 @@ fn forPrefix(p: *Parse) Error!usize { |
| 2104 | 2117 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? |
| 2105 | 2118 | /// |
| 2106 | 2119 | /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi |
| 2107 | fn parseWhileExpr(p: *Parse) !?Node.Index { | |
| 2108 | const while_token = p.eatToken(.keyword_while) orelse return null; | |
| 2120 | fn expectWhileExpr(p: *Parse) !Node.Index { | |
| 2121 | const while_token = p.assertToken(.keyword_while); | |
| 2109 | 2122 | _ = try p.expectToken(.l_paren); |
| 2110 | 2123 | const condition = try p.expectExpr(); |
| 2111 | 2124 | _ = try p.expectToken(.r_paren); |
| ... | ... | @@ -2153,7 +2166,7 @@ fn parseWhileExpr(p: *Parse) !?Node.Index { |
| 2153 | 2166 | }); |
| 2154 | 2167 | } |
| 2155 | 2168 | |
| 2156 | /// CurlySuffixExpr <- TypeExpr InitList? | |
| 2169 | /// CurlySuffixExpr <- TypeExpr (InitList / !LBRACE) | |
| 2157 | 2170 | /// |
| 2158 | 2171 | /// InitList |
| 2159 | 2172 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE |
| ... | ... | @@ -2255,7 +2268,7 @@ fn parseCurlySuffixExpr(p: *Parse) !?Node.Index { |
| 2255 | 2268 | } |
| 2256 | 2269 | } |
| 2257 | 2270 | |
| 2258 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? | |
| 2271 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK) | |
| 2259 | 2272 | fn parseErrorUnionExpr(p: *Parse) !?Node.Index { |
| 2260 | 2273 | const suffix_expr = try p.parseSuffixExpr() orelse return null; |
| 2261 | 2274 | const bang = p.eatToken(.bang) orelse return suffix_expr; |
| ... | ... | @@ -2269,59 +2282,13 @@ fn parseErrorUnionExpr(p: *Parse) !?Node.Index { |
| 2269 | 2282 | }); |
| 2270 | 2283 | } |
| 2271 | 2284 | |
| 2272 | /// SuffixExpr | |
| 2273 | /// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* | |
| 2274 | /// | |
| 2275 | /// FnCallArguments <- LPAREN ExprList RPAREN | |
| 2276 | /// | |
| 2277 | /// ExprList <- (Expr COMMA)* Expr? | |
| 2285 | /// SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix | |
| 2278 | 2286 | fn parseSuffixExpr(p: *Parse) !?Node.Index { |
| 2279 | 2287 | 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; | |
| 2324 | 2290 | } |
| 2291 | return res; | |
| 2325 | 2292 | } |
| 2326 | 2293 | |
| 2327 | 2294 | /// PrimaryTypeExpr |
| ... | ... | @@ -2331,17 +2298,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index { |
| 2331 | 2298 | /// / DOT IDENTIFIER |
| 2332 | 2299 | /// / DOT InitList |
| 2333 | 2300 | /// / ErrorSetDecl |
| 2334 | /// / FLOAT | |
| 2335 | 2301 | /// / FnProto |
| 2336 | 2302 | /// / GroupedExpr |
| 2337 | 2303 | /// / LabeledTypeExpr |
| 2338 | /// / IDENTIFIER !(COLON LabelableExpr) | |
| 2304 | /// / IDENTIFIER | |
| 2339 | 2305 | /// / IfTypeExpr |
| 2340 | /// / INTEGER | |
| 2341 | /// / KEYWORD_comptime TypeExpr !ExprSuffix | |
| 2306 | /// / KEYWORD_comptime TypeExpr | |
| 2342 | 2307 | /// / KEYWORD_error DOT IDENTIFIER |
| 2343 | 2308 | /// / KEYWORD_anyframe |
| 2344 | 2309 | /// / KEYWORD_unreachable |
| 2310 | /// / NUMBERLITERAL | |
| 2345 | 2311 | /// / STRINGLITERAL |
| 2346 | 2312 | /// |
| 2347 | 2313 | /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto |
| ... | ... | @@ -2396,23 +2362,23 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2396 | 2362 | }); |
| 2397 | 2363 | }, |
| 2398 | 2364 | |
| 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), | |
| 2402 | 2368 | .keyword_switch => return try p.expectSwitchExpr(false), |
| 2403 | 2369 | |
| 2404 | 2370 | .keyword_extern, |
| 2405 | 2371 | .keyword_packed, |
| 2406 | 2372 | => { |
| 2407 | 2373 | p.tok_i += 1; |
| 2408 | return try p.parseContainerDeclAuto(); | |
| 2374 | return try p.expectContainerDeclAuto(); | |
| 2409 | 2375 | }, |
| 2410 | 2376 | |
| 2411 | 2377 | .keyword_struct, |
| 2412 | 2378 | .keyword_opaque, |
| 2413 | 2379 | .keyword_enum, |
| 2414 | 2380 | .keyword_union, |
| 2415 | => return try p.parseContainerDeclAuto(), | |
| 2381 | => return try p.expectContainerDeclAuto(), | |
| 2416 | 2382 | |
| 2417 | 2383 | .keyword_comptime => return try p.addNode(.{ |
| 2418 | 2384 | .tag = .@"comptime", |
| ... | ... | @@ -2438,18 +2404,18 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2438 | 2404 | .keyword_inline => { |
| 2439 | 2405 | p.tok_i += 3; |
| 2440 | 2406 | 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(), | |
| 2443 | 2409 | else => return p.fail(.expected_inlinable), |
| 2444 | 2410 | } |
| 2445 | 2411 | }, |
| 2446 | 2412 | .keyword_for => { |
| 2447 | 2413 | p.tok_i += 2; |
| 2448 | return try p.parseFor(expectTypeExpr); | |
| 2414 | return try p.expectFor(expectTypeExpr); | |
| 2449 | 2415 | }, |
| 2450 | 2416 | .keyword_while => { |
| 2451 | 2417 | p.tok_i += 2; |
| 2452 | return try p.parseWhileTypeExpr(); | |
| 2418 | return try p.expectWhileTypeExpr(); | |
| 2453 | 2419 | }, |
| 2454 | 2420 | .keyword_switch => { |
| 2455 | 2421 | p.tok_i += 2; |
| ... | ... | @@ -2457,7 +2423,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2457 | 2423 | }, |
| 2458 | 2424 | .l_brace => { |
| 2459 | 2425 | p.tok_i += 2; |
| 2460 | return try p.parseBlock(); | |
| 2426 | return (try p.parseBlock()).?; | |
| 2461 | 2427 | }, |
| 2462 | 2428 | else => return try p.addNode(.{ |
| 2463 | 2429 | .tag = .identifier, |
| ... | ... | @@ -2474,13 +2440,13 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2474 | 2440 | .keyword_inline => { |
| 2475 | 2441 | p.tok_i += 1; |
| 2476 | 2442 | 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(), | |
| 2479 | 2445 | else => return p.fail(.expected_inlinable), |
| 2480 | 2446 | } |
| 2481 | 2447 | }, |
| 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(), | |
| 2484 | 2450 | .period => switch (p.tokenTag(p.tok_i + 1)) { |
| 2485 | 2451 | .identifier => { |
| 2486 | 2452 | p.tok_i += 1; |
| ... | ... | @@ -2608,10 +2574,8 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2608 | 2574 | }, |
| 2609 | 2575 | else => { |
| 2610 | 2576 | 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); | |
| 2615 | 2579 | return try p.addNode(.{ |
| 2616 | 2580 | .tag = .error_value, |
| 2617 | 2581 | .main_token = main_token, |
| ... | ... | @@ -2637,9 +2601,9 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index { |
| 2637 | 2601 | |
| 2638 | 2602 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? |
| 2639 | 2603 | /// |
| 2640 | /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix | |
| 2641 | fn 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) | |
| 2605 | fn expectWhileTypeExpr(p: *Parse) !Node.Index { | |
| 2606 | const while_token = p.assertToken(.keyword_while); | |
| 2643 | 2607 | _ = try p.expectToken(.l_paren); |
| 2644 | 2608 | const condition = try p.expectExpr(); |
| 2645 | 2609 | _ = try p.expectToken(.r_paren); |
| ... | ... | @@ -3106,6 +3070,11 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers { |
| 3106 | 3070 | /// / DOT IDENTIFIER |
| 3107 | 3071 | /// / DOTASTERISK |
| 3108 | 3072 | /// / DOTQUESTIONMARK |
| 3073 | /// / FnCallArguments | |
| 3074 | /// | |
| 3075 | /// FnCallArguments <- LPAREN ExprList RPAREN | |
| 3076 | /// | |
| 3077 | /// ExprList <- (Expr COMMA)* Expr? | |
| 3109 | 3078 | fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { |
| 3110 | 3079 | switch (p.tokenTag(p.tok_i)) { |
| 3111 | 3080 | .l_bracket => { |
| ... | ... | @@ -3195,6 +3164,46 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { |
| 3195 | 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 | 3207 | else => return null, |
| 3199 | 3208 | } |
| 3200 | 3209 | } |
| ... | ... | @@ -3208,7 +3217,7 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { |
| 3208 | 3217 | /// / KEYWORD_opaque |
| 3209 | 3218 | /// / KEYWORD_enum (LPAREN Expr RPAREN)? |
| 3210 | 3219 | /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? |
| 3211 | fn parseContainerDeclAuto(p: *Parse) !?Node.Index { | |
| 3220 | fn expectContainerDeclAuto(p: *Parse) !Node.Index { | |
| 3212 | 3221 | const main_token = p.nextToken(); |
| 3213 | 3222 | const arg_expr = switch (p.tokenTag(main_token)) { |
| 3214 | 3223 | .keyword_opaque => null, |
| ... | ... | @@ -3431,7 +3440,7 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { |
| 3431 | 3440 | /// FnCallArguments <- LPAREN ExprList RPAREN |
| 3432 | 3441 | /// |
| 3433 | 3442 | /// ExprList <- (Expr COMMA)* Expr? |
| 3434 | fn parseBuiltinCall(p: *Parse) !Node.Index { | |
| 3443 | fn expectBuiltinCall(p: *Parse) !Node.Index { | |
| 3435 | 3444 | const builtin_token = p.assertToken(.builtin); |
| 3436 | 3445 | _ = p.eatToken(.l_paren) orelse { |
| 3437 | 3446 | try p.warn(.expected_param_list); |
| ... | ... | @@ -3479,9 +3488,13 @@ fn parseBuiltinCall(p: *Parse) !Node.Index { |
| 3479 | 3488 | } |
| 3480 | 3489 | } |
| 3481 | 3490 | |
| 3491 | /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else) | |
| 3492 | /// | |
| 3493 | /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) | |
| 3494 | /// | |
| 3482 | 3495 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? |
| 3483 | fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index { | |
| 3484 | const if_token = p.eatToken(.keyword_if) orelse return null; | |
| 3496 | fn expectIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index { | |
| 3497 | const if_token = p.assertToken(.keyword_if); | |
| 3485 | 3498 | _ = try p.expectToken(.l_paren); |
| 3486 | 3499 | const condition = try p.expectExpr(); |
| 3487 | 3500 | _ = try p.expectToken(.r_paren); |
| ... | ... | @@ -3513,11 +3526,11 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N |
| 3513 | 3526 | }); |
| 3514 | 3527 | } |
| 3515 | 3528 | |
| 3516 | /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix | |
| 3529 | /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) | |
| 3517 | 3530 | /// |
| 3518 | /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix | |
| 3519 | fn 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) | |
| 3532 | fn expectFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index { | |
| 3533 | const for_token = p.assertToken(.keyword_for); | |
| 3521 | 3534 | |
| 3522 | 3535 | const scratch_top = p.scratch.items.len; |
| 3523 | 3536 | defer p.scratch.shrinkRetainingCapacity(scratch_top); |
lib/std/zig/parser_generated_oracle.zig+204-63| ... | ... | @@ -429,25 +429,37 @@ const Parser = struct { |
| 429 | 429 | pub fn parseAssignExpr(p: *Parser) bool { |
| 430 | 430 | return blk_0: { |
| 431 | 431 | 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; | |
| 443 | 443 | }) { |
| 444 | match_4 = true; | |
| 444 | match_3 = true; | |
| 445 | 445 | } |
| 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; | |
| 451 | 463 | p.i = pos_0; |
| 452 | 464 | break :blk_0 false; |
| 453 | 465 | }; |
| ... | ... | @@ -455,12 +467,19 @@ const Parser = struct { |
| 455 | 467 | pub fn parseSingleAssignExpr(p: *Parser) bool { |
| 456 | 468 | return blk_0: { |
| 457 | 469 | 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; | |
| 464 | 483 | p.i = pos_0; |
| 465 | 484 | break :blk_0 false; |
| 466 | 485 | }; |
| ... | ... | @@ -484,6 +503,11 @@ const Parser = struct { |
| 484 | 503 | break :blk_3 false; |
| 485 | 504 | }) {} |
| 486 | 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 | 511 | }) break :blk_0 true; |
| 488 | 512 | p.i = pos_0; |
| 489 | 513 | break :blk_0 false; |
| ... | ... | @@ -500,6 +524,11 @@ const Parser = struct { |
| 500 | 524 | break :blk_3 false; |
| 501 | 525 | }) {} |
| 502 | 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 | 532 | }) break :blk_0 true; |
| 504 | 533 | p.i = pos_0; |
| 505 | 534 | break :blk_0 false; |
| ... | ... | @@ -508,12 +537,19 @@ const Parser = struct { |
| 508 | 537 | pub fn parseCompareExpr(p: *Parser) bool { |
| 509 | 538 | return blk_0: { |
| 510 | 539 | 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; | |
| 517 | 553 | p.i = pos_0; |
| 518 | 554 | break :blk_0 false; |
| 519 | 555 | }; |
| ... | ... | @@ -529,6 +565,11 @@ const Parser = struct { |
| 529 | 565 | break :blk_3 false; |
| 530 | 566 | }) {} |
| 531 | 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 | 573 | }) break :blk_0 true; |
| 533 | 574 | p.i = pos_0; |
| 534 | 575 | break :blk_0 false; |
| ... | ... | @@ -545,6 +586,11 @@ const Parser = struct { |
| 545 | 586 | break :blk_3 false; |
| 546 | 587 | }) {} |
| 547 | 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 | 594 | }) break :blk_0 true; |
| 549 | 595 | p.i = pos_0; |
| 550 | 596 | break :blk_0 false; |
| ... | ... | @@ -561,6 +607,11 @@ const Parser = struct { |
| 561 | 607 | break :blk_3 false; |
| 562 | 608 | }) {} |
| 563 | 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 | 615 | }) break :blk_0 true; |
| 565 | 616 | p.i = pos_0; |
| 566 | 617 | break :blk_0 false; |
| ... | ... | @@ -577,6 +628,11 @@ const Parser = struct { |
| 577 | 628 | break :blk_3 false; |
| 578 | 629 | }) {} |
| 579 | 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 | 636 | }) break :blk_0 true; |
| 581 | 637 | p.i = pos_0; |
| 582 | 638 | break :blk_0 false; |
| ... | ... | @@ -588,6 +644,11 @@ const Parser = struct { |
| 588 | 644 | if (blk_1: { |
| 589 | 645 | while (p.parsePrefixOp()) {} |
| 590 | 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 | 652 | } and p.parsePrimaryExpr()) break :blk_0 true; |
| 592 | 653 | p.i = pos_0; |
| 593 | 654 | break :blk_0 false; |
| ... | ... | @@ -624,12 +685,19 @@ const Parser = struct { |
| 624 | 685 | pub fn parseIfExpr(p: *Parser) bool { |
| 625 | 686 | return blk_0: { |
| 626 | 687 | 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; | |
| 633 | 701 | p.i = pos_0; |
| 634 | 702 | break :blk_0 false; |
| 635 | 703 | }; |
| ... | ... | @@ -696,7 +764,19 @@ const Parser = struct { |
| 696 | 764 | pub fn parseCurlySuffixExpr(p: *Parser) bool { |
| 697 | 765 | return blk_0: { |
| 698 | 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 | 780 | p.i = pos_0; |
| 701 | 781 | break :blk_0 false; |
| 702 | 782 | }; |
| ... | ... | @@ -735,6 +815,11 @@ const Parser = struct { |
| 735 | 815 | if (blk_1: { |
| 736 | 816 | while (p.parsePrefixTypeOp()) {} |
| 737 | 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 | 823 | } and p.parseErrorUnionExpr()) break :blk_0 true; |
| 739 | 824 | p.i = pos_0; |
| 740 | 825 | break :blk_0 false; |
| ... | ... | @@ -743,12 +828,19 @@ const Parser = struct { |
| 743 | 828 | pub fn parseErrorUnionExpr(p: *Parser) bool { |
| 744 | 829 | return blk_0: { |
| 745 | 830 | 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; | |
| 752 | 844 | p.i = pos_0; |
| 753 | 845 | break :blk_0 false; |
| 754 | 846 | }; |
| ... | ... | @@ -757,15 +849,13 @@ const Parser = struct { |
| 757 | 849 | return blk_0: { |
| 758 | 850 | const pos_0 = p.i; |
| 759 | 851 | 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()) {} | |
| 768 | 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 | 859 | }) break :blk_0 true; |
| 770 | 860 | p.i = pos_0; |
| 771 | 861 | break :blk_0 false; |
| ... | ... | @@ -845,12 +935,19 @@ const Parser = struct { |
| 845 | 935 | pub fn parseIfTypeExpr(p: *Parser) bool { |
| 846 | 936 | return blk_0: { |
| 847 | 937 | 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; | |
| 854 | 951 | p.i = pos_0; |
| 855 | 952 | break :blk_0 false; |
| 856 | 953 | }; |
| ... | ... | @@ -905,12 +1002,19 @@ const Parser = struct { |
| 905 | 1002 | pub fn parseWhileTypeExpr(p: *Parser) bool { |
| 906 | 1003 | return blk_0: { |
| 907 | 1004 | 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; | |
| 914 | 1018 | p.i = pos_0; |
| 915 | 1019 | break :blk_0 false; |
| 916 | 1020 | }; |
| ... | ... | @@ -1539,6 +1643,20 @@ const Parser = struct { |
| 1539 | 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 | 1660 | pub fn parseSuffixOp(p: *Parser) bool { |
| 1543 | 1661 | return blk_0: { |
| 1544 | 1662 | const pos_0 = p.i; |
| ... | ... | @@ -1560,6 +1678,24 @@ const Parser = struct { |
| 1560 | 1678 | p.i = pos_0; |
| 1561 | 1679 | if (p.parseDOTQUESTIONMARK()) break :blk_0 true; |
| 1562 | 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 | 1699 | break :blk_0 false; |
| 1564 | 1700 | }; |
| 1565 | 1701 | } |
| ... | ... | @@ -1610,7 +1746,12 @@ const Parser = struct { |
| 1610 | 1746 | pub fn parseArrayTypeStart(p: *Parser) bool { |
| 1611 | 1747 | return blk_0: { |
| 1612 | 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 | 1755 | const pos_3 = p.i; |
| 1615 | 1756 | if (p.parseCOLON() and p.parseExpr()) break :blk_3 true; |
| 1616 | 1757 | p.i = pos_3; |