| 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,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 | Root <- ContainerMembers skip eof | 39 | Root <- ContainerMembers skip eof |
| 2 | 40 | ||
| 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 *** |
| 67 | 105 | ||
| 68 | # An assignment or a destructure whose LHS are all lvalue expressions. | 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 | Expr <- BoolOrExpr | 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 | PrimaryExpr | 129 | PrimaryExpr |
| 92 | <- AsmExpr | 130 | <- AsmExpr |
| ... | @@ -101,7 +139,7 @@ PrimaryExpr | ... | @@ -101,7 +139,7 @@ PrimaryExpr |
| 101 | / Block | 139 | / Block |
| 102 | / CurlySuffixExpr | 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 | Block <- LBRACE BlockStatement* RBRACE | 144 | Block <- LBRACE BlockStatement* RBRACE |
| 107 | 145 | ||
| ... | @@ -111,19 +149,18 @@ ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) | ... | @@ -111,19 +149,18 @@ ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) |
| 111 | 149 | ||
| 112 | WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? | 150 | WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? |
| 113 | 151 | ||
| 114 | CurlySuffixExpr <- TypeExpr InitList? | 152 | CurlySuffixExpr <- TypeExpr (InitList / !LBRACE) |
| 115 | 153 | ||
| 116 | InitList | 154 | InitList |
| 117 | <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | 155 | <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE |
| 118 | / LBRACE Expr (COMMA Expr)* COMMA? RBRACE | 156 | / LBRACE Expr (COMMA Expr)* COMMA? RBRACE |
| 119 | / LBRACE RBRACE | 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 | 163 | SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix |
| 126 | <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* | ||
| 127 | 164 | ||
| 128 | PrimaryTypeExpr | 165 | PrimaryTypeExpr |
| 129 | <- BUILTINIDENTIFIER FnCallArguments | 166 | <- BUILTINIDENTIFIER FnCallArguments |
| ... | @@ -150,7 +187,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE | ... | @@ -150,7 +187,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE |
| 150 | 187 | ||
| 151 | GroupedExpr <- LPAREN Expr RPAREN | 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 | LabeledTypeExpr | 192 | LabeledTypeExpr |
| 156 | <- BlockLabel Block | 193 | <- BlockLabel Block |
| ... | @@ -161,7 +198,7 @@ LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) | ... | @@ -161,7 +198,7 @@ LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) |
| 161 | 198 | ||
| 162 | ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) | 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 | SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE | 203 | SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE |
| 167 | 204 | ||
| ... | @@ -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 | / ArrayTypeStart | 357 | / ArrayTypeStart |
| 321 | 358 | ||
| 359 | PrefixTypeOpPrefix | ||
| 360 | <- QUESTIONMARK | ||
| 361 | / KEYWORD_anyframe MINUSRARROW | ||
| 362 | / LBRACKET | ||
| 363 | / ASTERISK | ||
| 364 | |||
| 322 | SuffixOp | 365 | SuffixOp |
| 323 | <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET | 366 | <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET |
| 324 | / DOT IDENTIFIER | 367 | / DOT IDENTIFIER |
| 325 | / DOTASTERISK | 368 | / DOTASTERISK |
| 326 | / DOTQUESTIONMARK | 369 | / DOTQUESTIONMARK |
| 370 | / FnCallArguments | ||
| 371 | |||
| 372 | SuffixOpPrefix | ||
| 373 | <- LBRACKET | ||
| 374 | / DOT IDENTIFIER | ||
| 375 | / DOTASTERISK | ||
| 376 | / DOTQUESTIONMARK | ||
| 377 | / LPAREN | ||
| 327 | 378 | ||
| 328 | FnCallArguments <- LPAREN ExprList RPAREN | 379 | FnCallArguments <- LPAREN ExprList RPAREN |
| 329 | 380 | ||
| ... | @@ -334,7 +385,7 @@ SinglePtrTypeStart <- ASTERISK | ... | @@ -334,7 +385,7 @@ SinglePtrTypeStart <- ASTERISK |
| 334 | 385 | ||
| 335 | ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET | 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 | # ContainerDecl specific | 390 | # ContainerDecl specific |
| 340 | ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE | 391 | ContainerDeclAuto <- 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. |
| 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 | pub const Error = error{ParseError} || Allocator.Error; | 16 | pub const Error = error{ParseError} || Allocator.Error; |
| 4 | 17 | ||
| 5 | gpa: Allocator, | 18 | gpa: 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 | } |
| 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 | /// AssignOp | 1429 | /// AssignOp |
| 1417 | /// <- ASTERISKEQUAL | 1430 | /// <- 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 | } |
| 1439 | 1452 | ||
| 1440 | /// SingleAssignExpr <- Expr (AssignOp Expr)? | 1453 | /// SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp) |
| 1441 | fn parseSingleAssignExpr(p: *Parse) !?Node.Index { | 1454 | fn 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 | } |
| 1645 | 1658 | ||
| 1646 | /// PrefixExpr <- PrefixOp* PrimaryExpr | 1659 | /// PrefixExpr <- PrefixOp* PrimaryExpr / !PrefixOp |
| 1647 | /// | 1660 | /// |
| 1648 | /// PrefixOp | 1661 | /// PrefixOp |
| 1649 | /// <- EXCLAMATIONMARK | 1662 | /// <- 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 | } |
| 1675 | 1688 | ||
| 1676 | /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr | 1689 | /// TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr |
| 1677 | /// | 1690 | /// |
| 1678 | /// PrefixTypeOp | 1691 | /// PrefixTypeOp |
| 1679 | /// <- QUESTIONMARK | 1692 | /// <- QUESTIONMARK |
| 1680 | /// / KEYWORD_anyframe MINUSRARROW | 1693 | /// / 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 | /// / ArrayTypeStart | 1696 | /// / ArrayTypeStart |
| 1685 | /// | 1697 | /// |
| 1698 | /// PrefixTypeOpPrefix | ||
| 1699 | /// <- QUESTIONMARK | ||
| 1700 | /// / KEYWORD_anyframe MINUSRARROW | ||
| 1701 | /// / LBRACKET | ||
| 1702 | /// / ASTERISK | ||
| 1703 | /// | ||
| 1686 | /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET | 1704 | /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET |
| 1687 | /// | 1705 | /// |
| 1688 | /// SinglePtrTypeStart <- ASTERISK | 1706 | /// SinglePtrTypeStart <- ASTERISK |
| 1689 | /// | 1707 | /// |
| 1690 | /// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET | 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 | /// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN | 1712 | /// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN |
| 1695 | fn parseTypeExpr(p: *Parse) Error!?Node.Index { | 1713 | fn 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 | /// PrimaryExpr | 1922 | /// PrimaryExpr |
| 1905 | /// <- AsmExpr | 1923 | /// <- AsmExpr |
| 1906 | /// / IfExpr | 1924 | /// / IfExpr |
| 1907 | /// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) | 1925 | /// / KEYWORD_break BreakLabel? Expr? |
| 1908 | /// / KEYWORD_comptime Expr !ExprSuffix | 1926 | /// / KEYWORD_comptime Expr |
| 1909 | /// / KEYWORD_nosuspend Expr !ExprSuffix | 1927 | /// / KEYWORD_nosuspend Expr |
| 1910 | /// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) | 1928 | /// / KEYWORD_continue BreakLabel? Expr? |
| 1911 | /// / KEYWORD_resume Expr !ExprSuffix | 1929 | /// / KEYWORD_resume Expr |
| 1912 | /// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart) | 1930 | /// / KEYWORD_return Expr? |
| 1913 | /// / BlockLabel? LoopExpr | 1931 | /// / BlockLabel? LoopExpr |
| 1914 | /// / Block | 1932 | /// / Block |
| 1915 | /// / CurlySuffixExpr | 1933 | /// / CurlySuffixExpr |
| 1916 | fn parsePrimaryExpr(p: *Parse) !?Node.Index { | 1934 | fn 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 | } |
| 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 | /// Block <- LBRACE BlockStatement* RBRACE | 2026 | /// Block <- LBRACE BlockStatement* RBRACE |
| 2014 | fn parseBlock(p: *Parse) !?Node.Index { | 2027 | fn 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)? !ExprSuffi | 2119 | /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi |
| 2107 | fn parseWhileExpr(p: *Parse) !?Node.Index { | 2120 | fn 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 | } |
| 2155 | 2168 | ||
| 2156 | /// CurlySuffixExpr <- TypeExpr InitList? | 2169 | /// CurlySuffixExpr <- TypeExpr (InitList / !LBRACE) |
| 2157 | /// | 2170 | /// |
| 2158 | /// InitList | 2171 | /// InitList |
| 2159 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | 2172 | /// <- 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 | } |
| 2257 | 2270 | ||
| 2258 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? | 2271 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK) |
| 2259 | fn parseErrorUnionExpr(p: *Parse) !?Node.Index { | 2272 | fn 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 | } |
| 2271 | 2284 | ||
| 2272 | /// SuffixExpr | 2285 | /// SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix |
| 2273 | /// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* | ||
| 2274 | /// | ||
| 2275 | /// FnCallArguments <- LPAREN ExprList RPAREN | ||
| 2276 | /// | ||
| 2277 | /// ExprList <- (Expr COMMA)* Expr? | ||
| 2278 | fn parseSuffixExpr(p: *Parse) !?Node.Index { | 2286 | fn 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 | } |
| 2326 | 2293 | ||
| 2327 | /// PrimaryTypeExpr | 2294 | /// PrimaryTypeExpr |
| ... | @@ -2331,17 +2298,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index { | ... | @@ -2331,17 +2298,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index { |
| 2331 | /// / DOT IDENTIFIER | 2298 | /// / DOT IDENTIFIER |
| 2332 | /// / DOT InitList | 2299 | /// / DOT InitList |
| 2333 | /// / ErrorSetDecl | 2300 | /// / ErrorSetDecl |
| 2334 | /// / FLOAT | ||
| 2335 | /// / FnProto | 2301 | /// / FnProto |
| 2336 | /// / GroupedExpr | 2302 | /// / GroupedExpr |
| 2337 | /// / LabeledTypeExpr | 2303 | /// / LabeledTypeExpr |
| 2338 | /// / IDENTIFIER !(COLON LabelableExpr) | 2304 | /// / IDENTIFIER |
| 2339 | /// / IfTypeExpr | 2305 | /// / IfTypeExpr |
| 2340 | /// / INTEGER | 2306 | /// / KEYWORD_comptime TypeExpr |
| 2341 | /// / KEYWORD_comptime TypeExpr !ExprSuffix | ||
| 2342 | /// / KEYWORD_error DOT IDENTIFIER | 2307 | /// / KEYWORD_error DOT IDENTIFIER |
| 2343 | /// / KEYWORD_anyframe | 2308 | /// / KEYWORD_anyframe |
| 2344 | /// / KEYWORD_unreachable | 2309 | /// / KEYWORD_unreachable |
| 2310 | /// / NUMBERLITERAL | ||
| 2345 | /// / STRINGLITERAL | 2311 | /// / STRINGLITERAL |
| 2346 | /// | 2312 | /// |
| 2347 | /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto | 2313 | /// 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 | }, |
| 2398 | 2364 | ||
| 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), |
| 2403 | 2369 | ||
| 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 | }, |
| 2410 | 2376 | ||
| 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(), |
| 2416 | 2382 | ||
| 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 { |
| 2637 | 2601 | ||
| 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)? !ExprSuffix | 2604 | /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) |
| 2641 | fn parseWhileTypeExpr(p: *Parse) !?Node.Index { | 2605 | fn 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 IDENTIFIER | 3070 | /// / DOT IDENTIFIER |
| 3107 | /// / DOTASTERISK | 3071 | /// / DOTASTERISK |
| 3108 | /// / DOTQUESTIONMARK | 3072 | /// / DOTQUESTIONMARK |
| 3073 | /// / FnCallArguments | ||
| 3074 | /// | ||
| 3075 | /// FnCallArguments <- LPAREN ExprList RPAREN | ||
| 3076 | /// | ||
| 3077 | /// ExprList <- (Expr COMMA)* Expr? | ||
| 3109 | fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { | 3078 | fn 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_opaque | 3217 | /// / 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)? |
| 3211 | fn parseContainerDeclAuto(p: *Parse) !?Node.Index { | 3220 | fn 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 RPAREN | 3440 | /// FnCallArguments <- LPAREN ExprList RPAREN |
| 3432 | /// | 3441 | /// |
| 3433 | /// ExprList <- (Expr COMMA)* Expr? | 3442 | /// ExprList <- (Expr COMMA)* Expr? |
| 3434 | fn parseBuiltinCall(p: *Parse) !Node.Index { | 3443 | fn 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 | } |
| 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 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? | 3495 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? |
| 3483 | fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index { | 3496 | fn 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 | } |
| 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 | 3531 | /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) |
| 3519 | fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index { | 3532 | fn 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); |
| 3521 | 3534 | ||
| 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; |