authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-06-17 15:18:24+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 11:48:59+02:00
logb4185600466bd14e39e68cd9f07017a8dc1fcf8e
tree211f0cc7fe177f6591bf4c9ad52a5dfb6138c642
parente488959c1f0504dc3b2aae19d79211e725916c76
signaturelock-open Commit is signed but in an unrecognized format.

grammar: statement-level consistency with Parse.zig

This is a first pass at consistency with Parse.zig on the statement level, adding constant lookaheads to the grammar in several places to match the behavior of Parse.zig.

3 files changed, 100 insertions(+), 86 deletions(-)

doc/langref/grammar.peg+11-13
...@@ -27,39 +27,37 @@ BlockStatement...@@ -27,39 +27,37 @@ BlockStatement
27 <- Statement27 <- Statement
28 / KEYWORD_defer BlockExprStatement28 / KEYWORD_defer BlockExprStatement
29 / KEYWORD_errdefer BlockExprStatement29 / KEYWORD_errdefer BlockExprStatement
30 / (KEYWORD_comptime)? VarAssignStatement30 / (KEYWORD_comptime !BlockExprPrefix)? VarAssignStatement
3131
32Statement32Statement
33 <- ExprStatement
34 / KEYWORD_suspend BlockExprStatement
35 / (KEYWORD_comptime)? AssignExpr SEMICOLON
36
37ExprStatement
38 <- IfStatement33 <- IfStatement
39 / LabeledStatement34 / LabeledStatement
40 / KEYWORD_nosuspend BlockExprStatement35 / KEYWORD_nosuspend BlockExprStatement
41 / KEYWORD_comptime BlockExpr36 / KEYWORD_comptime BlockExpr
37 / KEYWORD_suspend BlockExprStatement
38 / (KEYWORD_comptime !BlockExprPrefix)? AssignExpr SEMICOLON
4239
43IfStatement40IfStatement
44 <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?41 <- IfPrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else)
45 / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )42 / IfPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement)
4643
47LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)44LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)
4845
49LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)46LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
5047
51ForStatement48ForStatement
52 <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )49 <- ForPrefix BlockExpr (KEYWORD_else Statement / !KEYWORD_else)
53 / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )50 / ForPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Statement)
5451
55WhileStatement52WhileStatement
56 <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?53 <- WhilePrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else)
57 / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )54 / WhilePrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement)
5855
59BlockExprStatement56BlockExprStatement
60 <- BlockExpr57 <- BlockExpr
61 / !BlockExpr AssignExpr SEMICOLON58 / !BlockExprPrefix AssignExpr SEMICOLON
6259
60BlockExprPrefix <- BlockLabel? LBRACE
63BlockExpr <- BlockLabel? Block61BlockExpr <- BlockLabel? Block
6462
65# An assignment or a destructure whose LHS are all lvalue expressions or variable declarations.63# An assignment or a destructure whose LHS are all lvalue expressions or variable declarations.
lib/std/zig/Parse.zig+17-40
...@@ -864,7 +864,7 @@ fn parseGlobalVarDecl(p: *Parse) !?Node.Index {...@@ -864,7 +864,7 @@ fn parseGlobalVarDecl(p: *Parse) !?Node.Index {
864 return var_decl;864 return var_decl;
865}865}
866866
867/// ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)?867// ContainerField <- doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)?
868fn expectContainerField(p: *Parse) !Node.Index {868fn expectContainerField(p: *Parse) !Node.Index {
869 _ = p.eatToken(.keyword_comptime);869 _ = p.eatToken(.keyword_comptime);
870 const main_token = p.tok_i;870 const main_token = p.tok_i;
...@@ -910,18 +910,15 @@ fn expectContainerField(p: *Parse) !Node.Index {...@@ -910,18 +910,15 @@ fn expectContainerField(p: *Parse) !Node.Index {
910/// <- Statement910/// <- Statement
911/// / KEYWORD_defer BlockExprStatement911/// / KEYWORD_defer BlockExprStatement
912/// / KEYWORD_errdefer BlockExprStatement912/// / KEYWORD_errdefer BlockExprStatement
913/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement913/// / (KEYWORD_comptime !BlockExprPrefix)? VarAssignStatement
914///914///
915/// Statement915/// Statement
916/// <- ExprStatement
917/// / KEYWORD_suspend BlockExprStatement
918/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON
919///
920/// ExprStatement
921/// <- IfStatement916/// <- IfStatement
922/// / LabeledStatement917/// / LabeledStatement
923/// / KEYWORD_nosuspend BlockExprStatement918/// / KEYWORD_nosuspend BlockExprStatement
924/// / KEYWORD_comptime BlockExpr919/// / KEYWORD_comptime BlockExpr
920/// / KEYWORD_suspend BlockExprStatement
921/// / (KEYWORD_comptime !BlockExprPrefix)? AssignExpr SEMICOLON
925fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {922fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
926 if (p.eatToken(.keyword_comptime)) |comptime_token| {923 if (p.eatToken(.keyword_comptime)) |comptime_token| {
927 const opt_block_expr = try p.parseBlockExpr();924 const opt_block_expr = try p.parseBlockExpr();
...@@ -934,7 +931,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {...@@ -934,7 +931,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
934 }931 }
935932
936 if (is_block_level) {933 if (is_block_level) {
937 return p.expectVarDeclExprStatement(comptime_token);934 return p.expectVarAssignStatement(comptime_token);
938 } else {935 } else {
939 const assign = try p.expectAssignExpr();936 const assign = try p.expectAssignExpr();
940 try p.expectSemicolon(.expected_semi_after_stmt, true);937 try p.expectSemicolon(.expected_semi_after_stmt, true);
...@@ -995,7 +992,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {...@@ -995,7 +992,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
995 if (try p.parseLabeledStatement()) |labeled_statement| return labeled_statement;992 if (try p.parseLabeledStatement()) |labeled_statement| return labeled_statement;
996993
997 if (is_block_level) {994 if (is_block_level) {
998 return p.expectVarDeclExprStatement(null);995 return p.expectVarAssignStatement(null);
999 } else {996 } else {
1000 const assign = try p.expectAssignExpr();997 const assign = try p.expectAssignExpr();
1001 try p.expectSemicolon(.expected_semi_after_stmt, true);998 try p.expectSemicolon(.expected_semi_after_stmt, true);
...@@ -1003,30 +1000,8 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {...@@ -1003,30 +1000,8 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
1003 }1000 }
1004}1001}
10051002
1006/// ComptimeStatement
1007/// <- BlockExpr
1008/// / VarDeclExprStatement
1009fn expectComptimeStatement(p: *Parse, comptime_token: TokenIndex) !Node.Index {
1010 const maybe_block_expr = try p.parseBlockExpr();
1011 if (maybe_block_expr) |block_expr| {
1012 return p.addNode(.{
1013 .tag = .@"comptime",
1014 .main_token = comptime_token,
1015 .data = .{
1016 .lhs = .{ .node = block_expr },
1017 .rhs = undefined,
1018 },
1019 });
1020 }
1021 return p.expectVarDeclExprStatement(comptime_token);
1022}
1023
1024/// VarDeclExprStatement
1025/// <- Expr
1026/// / VarAssignStatement
1027///
1028/// VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON1003/// VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON
1029fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index {1004fn expectVarAssignStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index {
1030 const scratch_top = p.scratch.items.len;1005 const scratch_top = p.scratch.items.len;
1031 defer p.scratch.shrinkRetainingCapacity(scratch_top);1006 defer p.scratch.shrinkRetainingCapacity(scratch_top);
10321007
...@@ -1138,7 +1113,7 @@ fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Inde...@@ -1138,7 +1113,7 @@ fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Inde
11381113
1139/// If a parse error occurs, reports an error, but then finds the next statement1114/// If a parse error occurs, reports an error, but then finds the next statement
1140/// and returns that one instead. If a parse error occurs but there is no following1115/// and returns that one instead. If a parse error occurs but there is no following
1141/// statement, returns 0.1116/// statement, returns null.
1142fn expectStatementRecoverable(p: *Parse) Error!?Node.Index {1117fn expectStatementRecoverable(p: *Parse) Error!?Node.Index {
1143 while (true) {1118 while (true) {
1144 return p.expectStatement(true) catch |err| switch (err) {1119 return p.expectStatement(true) catch |err| switch (err) {
...@@ -1156,8 +1131,10 @@ fn expectStatementRecoverable(p: *Parse) Error!?Node.Index {...@@ -1156,8 +1131,10 @@ fn expectStatementRecoverable(p: *Parse) Error!?Node.Index {
1156}1131}
11571132
1158/// IfStatement1133/// IfStatement
1159/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?1134/// <- IfPrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else)
1160/// / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )1135/// / IfPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement)
1136///
1137/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
1161fn expectIfStatement(p: *Parse) !Node.Index {1138fn expectIfStatement(p: *Parse) !Node.Index {
1162 const if_token = p.assertToken(.keyword_if);1139 const if_token = p.assertToken(.keyword_if);
1163 _ = try p.expectToken(.l_paren);1140 _ = try p.expectToken(.l_paren);
...@@ -1252,8 +1229,8 @@ fn parseLoopStatement(p: *Parse) !?Node.Index {...@@ -1252,8 +1229,8 @@ fn parseLoopStatement(p: *Parse) !?Node.Index {
1252}1229}
12531230
1254/// ForStatement1231/// ForStatement
1255/// <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )1232/// <- ForPrefix BlockExpr (KEYWORD_else Statement / !KEYWORD_else)
1256/// / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement )1233/// / ForPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Statement)
1257fn parseForStatement(p: *Parse) !?Node.Index {1234fn parseForStatement(p: *Parse) !?Node.Index {
1258 const for_token = p.eatToken(.keyword_for) orelse return null;1235 const for_token = p.eatToken(.keyword_for) orelse return null;
12591236
...@@ -1309,8 +1286,8 @@ fn parseForStatement(p: *Parse) !?Node.Index {...@@ -1309,8 +1286,8 @@ fn parseForStatement(p: *Parse) !?Node.Index {
1309/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?1286/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
1310///1287///
1311/// WhileStatement1288/// WhileStatement
1312/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?1289/// <- WhilePrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else)
1313/// / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )1290/// / WhilePrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement)
1314fn parseWhileStatement(p: *Parse) !?Node.Index {1291fn parseWhileStatement(p: *Parse) !?Node.Index {
1315 const while_token = p.eatToken(.keyword_while) orelse return null;1292 const while_token = p.eatToken(.keyword_while) orelse return null;
1316 _ = try p.expectToken(.l_paren);1293 _ = try p.expectToken(.l_paren);
...@@ -1400,7 +1377,7 @@ fn parseWhileStatement(p: *Parse) !?Node.Index {...@@ -1400,7 +1377,7 @@ fn parseWhileStatement(p: *Parse) !?Node.Index {
14001377
1401/// BlockExprStatement1378/// BlockExprStatement
1402/// <- BlockExpr1379/// <- BlockExpr
1403/// / !BlockExpr AssignExpr SEMICOLON1380/// / !BlockExprPrefix AssignExpr SEMICOLON
1404fn parseBlockExprStatement(p: *Parse) !?Node.Index {1381fn parseBlockExprStatement(p: *Parse) !?Node.Index {
1405 const block_expr = try p.parseBlockExpr();1382 const block_expr = try p.parseBlockExpr();
1406 if (block_expr) |expr| return expr;1383 if (block_expr) |expr| return expr;
lib/std/zig/parser_generated_oracle.zig+72-33
...@@ -190,7 +190,12 @@ const Parser = struct {...@@ -190,7 +190,12 @@ const Parser = struct {
190 p.i = pos_0;190 p.i = pos_0;
191 if ((blk_3: {191 if ((blk_3: {
192 const pos_3 = p.i;192 const pos_3 = p.i;
193 if (p.parseKEYWORD_comptime()) break :blk_3 true;193 if (p.parseKEYWORD_comptime() and blk_4: {
194 const pos_4 = p.i;
195 const match_4 = p.parseBlockExprPrefix();
196 p.i = pos_4;
197 break :blk_4 !match_4;
198 }) break :blk_3 true;
194 p.i = pos_3;199 p.i = pos_3;
195 break :blk_3 false;200 break :blk_3 false;
196 } or true) and p.parseVarAssignStatement()) break :blk_0 true;201 } or true) and p.parseVarAssignStatement()) break :blk_0 true;
...@@ -201,13 +206,24 @@ const Parser = struct {...@@ -201,13 +206,24 @@ const Parser = struct {
201 pub fn parseStatement(p: *Parser) bool {206 pub fn parseStatement(p: *Parser) bool {
202 return blk_0: {207 return blk_0: {
203 const pos_0 = p.i;208 const pos_0 = p.i;
204 if (p.parseExprStatement()) break :blk_0 true;209 if (p.parseIfStatement()) break :blk_0 true;
210 p.i = pos_0;
211 if (p.parseLabeledStatement()) break :blk_0 true;
212 p.i = pos_0;
213 if (p.parseKEYWORD_nosuspend() and p.parseBlockExprStatement()) break :blk_0 true;
214 p.i = pos_0;
215 if (p.parseKEYWORD_comptime() and p.parseBlockExpr()) break :blk_0 true;
205 p.i = pos_0;216 p.i = pos_0;
206 if (p.parseKEYWORD_suspend() and p.parseBlockExprStatement()) break :blk_0 true;217 if (p.parseKEYWORD_suspend() and p.parseBlockExprStatement()) break :blk_0 true;
207 p.i = pos_0;218 p.i = pos_0;
208 if ((blk_3: {219 if ((blk_3: {
209 const pos_3 = p.i;220 const pos_3 = p.i;
210 if (p.parseKEYWORD_comptime()) break :blk_3 true;221 if (p.parseKEYWORD_comptime() and blk_4: {
222 const pos_4 = p.i;
223 const match_4 = p.parseBlockExprPrefix();
224 p.i = pos_4;
225 break :blk_4 !match_4;
226 }) break :blk_3 true;
211 p.i = pos_3;227 p.i = pos_3;
212 break :blk_3 false;228 break :blk_3 false;
213 } or true) and p.parseAssignExpr() and p.parseSEMICOLON()) break :blk_0 true;229 } or true) and p.parseAssignExpr() and p.parseSEMICOLON()) break :blk_0 true;
...@@ -215,31 +231,29 @@ const Parser = struct {...@@ -215,31 +231,29 @@ const Parser = struct {
215 break :blk_0 false;231 break :blk_0 false;
216 };232 };
217 }233 }
218 pub fn parseExprStatement(p: *Parser) bool {
219 return blk_0: {
220 const pos_0 = p.i;
221 if (p.parseIfStatement()) break :blk_0 true;
222 p.i = pos_0;
223 if (p.parseLabeledStatement()) break :blk_0 true;
224 p.i = pos_0;
225 if (p.parseKEYWORD_nosuspend() and p.parseBlockExprStatement()) break :blk_0 true;
226 p.i = pos_0;
227 if (p.parseKEYWORD_comptime() and p.parseBlockExpr()) break :blk_0 true;
228 p.i = pos_0;
229 break :blk_0 false;
230 };
231 }
232 pub fn parseIfStatement(p: *Parser) bool {234 pub fn parseIfStatement(p: *Parser) bool {
233 return blk_0: {235 return blk_0: {
234 const pos_0 = p.i;236 const pos_0 = p.i;
235 if (p.parseIfPrefix() and p.parseBlockExpr() and (blk_3: {237 if (p.parseIfPrefix() and p.parseBlockExpr() and blk_2: {
236 const pos_3 = p.i;238 const pos_2 = p.i;
237 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseStatement()) break :blk_3 true;239 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseStatement()) break :blk_2 true;
238 p.i = pos_3;240 p.i = pos_2;
239 break :blk_3 false;241 if (blk_3: {
240 } or true)) break :blk_0 true;242 const pos_3 = p.i;
243 const match_3 = p.parseKEYWORD_else();
244 p.i = pos_3;
245 break :blk_3 !match_3;
246 }) break :blk_2 true;
247 p.i = pos_2;
248 break :blk_2 false;
249 }) break :blk_0 true;
241 p.i = pos_0;250 p.i = pos_0;
242 if (p.parseIfPrefix() and p.parseAssignExpr() and blk_2: {251 if (p.parseIfPrefix() and blk_1: {
252 const pos_1 = p.i;
253 const match_1 = p.parseBlockExprPrefix();
254 p.i = pos_1;
255 break :blk_1 !match_1;
256 } and p.parseAssignExpr() and blk_2: {
243 const pos_2 = p.i;257 const pos_2 = p.i;
244 if (p.parseSEMICOLON()) break :blk_2 true;258 if (p.parseSEMICOLON()) break :blk_2 true;
245 p.i = pos_2;259 p.i = pos_2;
...@@ -300,7 +314,12 @@ const Parser = struct {...@@ -300,7 +314,12 @@ const Parser = struct {
300 break :blk_2 false;314 break :blk_2 false;
301 }) break :blk_0 true;315 }) break :blk_0 true;
302 p.i = pos_0;316 p.i = pos_0;
303 if (p.parseForPrefix() and p.parseAssignExpr() and blk_2: {317 if (p.parseForPrefix() and blk_1: {
318 const pos_1 = p.i;
319 const match_1 = p.parseBlockExprPrefix();
320 p.i = pos_1;
321 break :blk_1 !match_1;
322 } and p.parseAssignExpr() and blk_2: {
304 const pos_2 = p.i;323 const pos_2 = p.i;
305 if (p.parseSEMICOLON()) break :blk_2 true;324 if (p.parseSEMICOLON()) break :blk_2 true;
306 p.i = pos_2;325 p.i = pos_2;
...@@ -315,14 +334,26 @@ const Parser = struct {...@@ -315,14 +334,26 @@ const Parser = struct {
315 pub fn parseWhileStatement(p: *Parser) bool {334 pub fn parseWhileStatement(p: *Parser) bool {
316 return blk_0: {335 return blk_0: {
317 const pos_0 = p.i;336 const pos_0 = p.i;
318 if (p.parseWhilePrefix() and p.parseBlockExpr() and (blk_3: {337 if (p.parseWhilePrefix() and p.parseBlockExpr() and blk_2: {
319 const pos_3 = p.i;338 const pos_2 = p.i;
320 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseStatement()) break :blk_3 true;339 if (p.parseKEYWORD_else() and (p.parsePayload() or true) and p.parseStatement()) break :blk_2 true;
321 p.i = pos_3;340 p.i = pos_2;
322 break :blk_3 false;341 if (blk_3: {
323 } or true)) break :blk_0 true;342 const pos_3 = p.i;
343 const match_3 = p.parseKEYWORD_else();
344 p.i = pos_3;
345 break :blk_3 !match_3;
346 }) break :blk_2 true;
347 p.i = pos_2;
348 break :blk_2 false;
349 }) break :blk_0 true;
324 p.i = pos_0;350 p.i = pos_0;
325 if (p.parseWhilePrefix() and p.parseAssignExpr() and blk_2: {351 if (p.parseWhilePrefix() and blk_1: {
352 const pos_1 = p.i;
353 const match_1 = p.parseBlockExprPrefix();
354 p.i = pos_1;
355 break :blk_1 !match_1;
356 } and p.parseAssignExpr() and blk_2: {
326 const pos_2 = p.i;357 const pos_2 = p.i;
327 if (p.parseSEMICOLON()) break :blk_2 true;358 if (p.parseSEMICOLON()) break :blk_2 true;
328 p.i = pos_2;359 p.i = pos_2;
...@@ -341,7 +372,7 @@ const Parser = struct {...@@ -341,7 +372,7 @@ const Parser = struct {
341 p.i = pos_0;372 p.i = pos_0;
342 if (blk_1: {373 if (blk_1: {
343 const pos_1 = p.i;374 const pos_1 = p.i;
344 const match_1 = p.parseBlockExpr();375 const match_1 = p.parseBlockExprPrefix();
345 p.i = pos_1;376 p.i = pos_1;
346 break :blk_1 !match_1;377 break :blk_1 !match_1;
347 } and p.parseAssignExpr() and p.parseSEMICOLON()) break :blk_0 true;378 } and p.parseAssignExpr() and p.parseSEMICOLON()) break :blk_0 true;
...@@ -349,6 +380,14 @@ const Parser = struct {...@@ -349,6 +380,14 @@ const Parser = struct {
349 break :blk_0 false;380 break :blk_0 false;
350 };381 };
351 }382 }
383 pub fn parseBlockExprPrefix(p: *Parser) bool {
384 return blk_0: {
385 const pos_0 = p.i;
386 if ((p.parseBlockLabel() or true) and p.parseLBRACE()) break :blk_0 true;
387 p.i = pos_0;
388 break :blk_0 false;
389 };
390 }
352 pub fn parseBlockExpr(p: *Parser) bool {391 pub fn parseBlockExpr(p: *Parser) bool {
353 return blk_0: {392 return blk_0: {
354 const pos_0 = p.i;393 const pos_0 = p.i;