authorgravatar for goon.pri.low@gmail.comKendall Condon <goon.pri.low@gmail.com> 2026-03-22 17:13:44-04:00
committergravatar for goon.pri.low@gmail.comKendall Condon <goon.pri.low@gmail.com> 2026-03-25 17:29:56-04:00
log785fb1be111186525bf288fa3460945404f676eb
treeea9b801ad5b85ecd25daf51338d1b864333cc25b
parent2aee0cd6b95d8154a8245d2d1d7be3f6058c659c

fix several inconsistencies between parser and PEG

- PEG / Parser Changes All the changes made here are to places where the PEG was more permissive than the parser. Changes to the parser make it more permissive and changes to the PEG make it more strict. When choosing between these two options for discrepancies, I opted for the choice that was more natural and increased code readability. Changes to the Parser * Tuple types can now be `inline` and `extern` (e.g. `extern struct`). * Break labels are now only consumed if both the colon and identifier are present instead of failing if there is only a colon. * Labeled blocks are no longer parsed in PrimaryExpr (so they are now allowed to have CurlySuffixExpr) as in the PEG. * While expressions can now be grouped on the same line. * Added distinction in error messages for "a multiline string literal" so places where only single string literals are allowed do not give "expected 'a string literal', found 'a string literal'". Changes to the PEG * Made it so extern functions cannot have a body * Made it so ... can be only the last function argument * Made it so many item pointers can't have bit alignment * Made it so asm inputs / outputs can not be multiline string literals * Added distinction between block-level statements and regular statements -- Pointer Qualifier Order The PEG allowed for duplicated qualifiers, which the parser did not. The simplest fix for this was to make each be allowed zero or one times which required giving them a order similar to how FnProto already works. The chosen order is the same as used by zig fmt. The parser still accepts them in any order similar to functions. -- Backtracking Made it so several places could not backtrack in the PEG. A common pattern for this was (A / !A). --- !ExprSuffix Expressions ending with expressions now have !ExprSuffix after. This change prevents expressions such as `if (a) T else U{}` being be parsable as `(if (a) T else U){}`. It also stops some backtracking, take for example: `if (a) for (b) |c| d else |e| f` It may seem at first that the else clause belongs to the `for`, however it actually belongs to the `if` because for else-clauses cannot have a payload. This is fixed by a new `KEYWORD_else / !KEYWORD_else`, however this alone does not fix more complex cases such as: `if (a) for (b) |c| d() else |e| f` The PEG would first attempt to parse it as expected but fail due to the new guard. It will then backtrack to `if (a) (for (b) |c| d)() else |e| f` which is surprising but avoids the new gaurd. So, !ExprSuffix is required to disallow this type of backtracking. --- !LabelableExpr For identifiers, excluding labels is necessary despite ordered choice due to pointer bit alignment. For example `*align(a : b: for (c) e) T` could backtrack to `*align(a : b : (for (c) e)) T`. --- !SinglePtrTypeStart Prevents expressions like `break * break` which is parsed as `break (*break)` backtracking to `(break) * (break)` --- !BlockExpr Prevents expressions like `test { {} = a; }` being backtracked to and parsed as `test { ({} = a); }` (the parenthesis are just for demonstration, that expression is not legal either) --- !ExprStatement In addition to splitting up block level statements, statements that are also parsable as expressions are now part of ExprStatement to disallow backtracking.

5 files changed, 189 insertions(+), 143 deletions(-)

doc/langref.html.in+74-55
...@@ -7944,58 +7944,60 @@ TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block...@@ -7944,58 +7944,60 @@ TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block
7944ComptimeDecl <- KEYWORD_comptime Block7944ComptimeDecl <- KEYWORD_comptime Block
79457945
7946Decl7946Decl
7947 <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)7947 <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)
7948 / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON
7948 / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl7949 / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl
79497950
7950FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr7951FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix
79517952
7952VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection?7953VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection?
79537954
7954GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON7955GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON
79557956
7956ContainerField <- doc_comment? KEYWORD_comptime? !KEYWORD_fn (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)?7957ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)?
79577958
7958# *** Block Level ***7959# *** Block Level ***
7959Statement7960BlockStatement
7960 <- KEYWORD_comptime ComptimeStatement7961 <- Statement
7961 / KEYWORD_nosuspend BlockExprStatement
7962 / KEYWORD_suspend BlockExprStatement
7963 / KEYWORD_defer BlockExprStatement7962 / KEYWORD_defer BlockExprStatement
7964 / KEYWORD_errdefer Payload? BlockExprStatement7963 / KEYWORD_errdefer Payload? BlockExprStatement
7965 / IfStatement7964 / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
7966 / LabeledStatement
7967 / VarDeclExprStatement
79687965
7969ComptimeStatement7966Statement
7970 <- BlockExpr7967 <- ExprStatement
7971 / VarDeclExprStatement7968 / KEYWORD_suspend BlockExprStatement
7969 / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON
7970
7971ExprStatement
7972 <- IfStatement
7973 / LabeledStatement
7974 / KEYWORD_nosuspend BlockExprStatement
7975 / KEYWORD_comptime BlockExpr
79727976
7973IfStatement7977IfStatement
7974 <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?7978 <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
7975 / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )7979 / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
79767980
7977LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)7981LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)
79787982
7979LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)7983LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
79807984
7981ForStatement7985ForStatement
7982 <- ForPrefix BlockExpr ( KEYWORD_else Statement )?7986 <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )
7983 / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )7987 / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement )
79847988
7985WhileStatement7989WhileStatement
7986 <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?7990 <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
7987 / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )7991 / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
79887992
7989BlockExprStatement7993BlockExprStatement
7990 <- BlockExpr7994 <- BlockExpr
7991 / AssignExpr SEMICOLON7995 / !BlockExpr AssignExpr SEMICOLON
79927996
7993BlockExpr <- BlockLabel? Block7997BlockExpr <- BlockLabel? Block
79947998
7995# An expression, assignment, or any destructure, as a statement.7999# An assignment or a destructure whose LHS are all lvalue expressions or variable declarations.
7996VarDeclExprStatement8000VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON
7997 <- VarDeclProto (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON
7998 / Expr (AssignOp Expr / (COMMA (VarDeclProto / Expr))+ EQUAL Expr)? SEMICOLON
79998001
8000# *** Expression Level ***8002# *** Expression Level ***
80018003
...@@ -8025,25 +8027,25 @@ PrefixExpr <- PrefixOp* PrimaryExpr...@@ -8025,25 +8027,25 @@ PrefixExpr <- PrefixOp* PrimaryExpr
8025PrimaryExpr8027PrimaryExpr
8026 <- AsmExpr8028 <- AsmExpr
8027 / IfExpr8029 / IfExpr
8028 / KEYWORD_break BreakLabel? Expr?8030 / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
8029 / KEYWORD_comptime Expr8031 / KEYWORD_comptime Expr !ExprSuffix
8030 / KEYWORD_nosuspend Expr8032 / KEYWORD_nosuspend Expr !ExprSuffix
8031 / KEYWORD_continue BreakLabel? Expr?8033 / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
8032 / KEYWORD_resume Expr8034 / KEYWORD_resume Expr !ExprSuffix
8033 / KEYWORD_return Expr?8035 / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart)
8034 / BlockLabel? LoopExpr8036 / BlockLabel? LoopExpr
8035 / Block8037 / Block
8036 / CurlySuffixExpr8038 / CurlySuffixExpr
80378039
8038IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?8040IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
80398041
8040Block <- LBRACE Statement* RBRACE8042Block <- LBRACE BlockStatement* RBRACE
80418043
8042LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)8044LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
80438045
8044ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?8046ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix
80458047
8046WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?8048WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
80478049
8048CurlySuffixExpr <- TypeExpr InitList?8050CurlySuffixExpr <- TypeExpr InitList?
80498051
...@@ -8070,10 +8072,10 @@ PrimaryTypeExpr...@@ -8070,10 +8072,10 @@ PrimaryTypeExpr
8070 / FnProto8072 / FnProto
8071 / GroupedExpr8073 / GroupedExpr
8072 / LabeledTypeExpr8074 / LabeledTypeExpr
8073 / IDENTIFIER8075 / IDENTIFIER !(COLON LabelableExpr)
8074 / IfTypeExpr8076 / IfTypeExpr
8075 / INTEGER8077 / INTEGER
8076 / KEYWORD_comptime TypeExpr8078 / KEYWORD_comptime TypeExpr !ExprSuffix
8077 / KEYWORD_error DOT IDENTIFIER8079 / KEYWORD_error DOT IDENTIFIER
8078 / KEYWORD_anyframe8080 / KEYWORD_anyframe
8079 / KEYWORD_unreachable8081 / KEYWORD_unreachable
...@@ -8085,7 +8087,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE...@@ -8085,7 +8087,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
80858087
8086GroupedExpr <- LPAREN Expr RPAREN8088GroupedExpr <- LPAREN Expr RPAREN
80878089
8088IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?8090IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
80898091
8090LabeledTypeExpr8092LabeledTypeExpr
8091 <- BlockLabel Block8093 <- BlockLabel Block
...@@ -8094,9 +8096,9 @@ LabeledTypeExpr...@@ -8094,9 +8096,9 @@ LabeledTypeExpr
80948096
8095LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)8097LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
80968098
8097ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?8099ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix
80988100
8099WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?8101WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
81008102
8101SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE8103SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
81028104
...@@ -8105,11 +8107,11 @@ AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN...@@ -8105,11 +8107,11 @@ AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
81058107
8106AsmOutput <- COLON AsmOutputList AsmInput?8108AsmOutput <- COLON AsmOutputList AsmInput?
81078109
8108AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN8110AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
81098111
8110AsmInput <- COLON AsmInputList AsmClobbers?8112AsmInput <- COLON AsmInputList AsmClobbers?
81118113
8112AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN8114AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN
81138115
8114AsmClobbers <- COLON Expr8116AsmClobbers <- COLON Expr
81158117
...@@ -8129,9 +8131,7 @@ AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN...@@ -8129,9 +8131,7 @@ AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
8129# Fn specific8131# Fn specific
8130CallConv <- KEYWORD_callconv LPAREN Expr RPAREN8132CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
81318133
8132ParamDecl8134ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime / !KEYWORD_comptime) (IDENTIFIER COLON / !(IDENTIFIER_COLON)) ParamType
8133 <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
8134 / DOT3
81358135
8136ParamType8136ParamType
8137 <- KEYWORD_anytype8137 <- KEYWORD_anytype
...@@ -8237,8 +8237,8 @@ PrefixOp...@@ -8237,8 +8237,8 @@ PrefixOp
8237PrefixTypeOp8237PrefixTypeOp
8238 <- QUESTIONMARK8238 <- QUESTIONMARK
8239 / KEYWORD_anyframe MINUSRARROW8239 / KEYWORD_anyframe MINUSRARROW
8240 / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*8240 / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
8241 / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*8241 / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
8242 / ArrayTypeStart8242 / ArrayTypeStart
82438243
8244SuffixOp8244SuffixOp
...@@ -8249,15 +8249,31 @@ SuffixOp...@@ -8249,15 +8249,31 @@ SuffixOp
82498249
8250FnCallArguments <- LPAREN ExprList RPAREN8250FnCallArguments <- LPAREN ExprList RPAREN
82518251
8252ExprSuffix
8253 <- KEYWORD_or
8254 / KEYWORD_and
8255 / CompareOp
8256 / BitwiseOp
8257 / BitShiftOp
8258 / AdditionOp
8259 / MultiplyOp
8260 / EXCLAMATIONMARK
8261 / SuffixOp
8262 / FnCallArguments
8263
8264LabelableExpr
8265 <- Block
8266 / SwitchExpr
8267 / LoopExpr
8268
8252# Ptr specific8269# Ptr specific
8253SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET8270SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
82548271
8255PtrTypeStart8272SinglePtrTypeStart <- ASTERISK / ASTERISK2
8256 <- ASTERISK8273
8257 / ASTERISK28274ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
8258 / LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
82598275
8260ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET8276ArrayTypeStart <- LBRACKET Expr !(ASTERISK / ASTERISK2) (COLON Expr)? RBRACKET
82618277
8262# ContainerDecl specific8278# ContainerDecl specific
8263ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE8279ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
...@@ -8266,11 +8282,13 @@ ContainerDeclType...@@ -8266,11 +8282,13 @@ ContainerDeclType
8266 <- KEYWORD_struct (LPAREN Expr RPAREN)?8282 <- KEYWORD_struct (LPAREN Expr RPAREN)?
8267 / KEYWORD_opaque8283 / KEYWORD_opaque
8268 / KEYWORD_enum (LPAREN Expr RPAREN)?8284 / KEYWORD_enum (LPAREN Expr RPAREN)?
8269 / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?8285 / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / !KEYWORD_enum Expr) RPAREN)?
82708286
8271# Alignment8287# Alignment
8272ByteAlign <- KEYWORD_align LPAREN Expr RPAREN8288ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
82738289
8290BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
8291
8274# Lists8292# Lists
8275IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?8293IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?
82768294
...@@ -8280,7 +8298,7 @@ AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?...@@ -8280,7 +8298,7 @@ AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
82808298
8281AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?8299AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
82828300
8283ParamDeclList <- (ParamDecl COMMA)* ParamDecl?8301ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)?
82848302
8285ExprList <- (Expr COMMA)* Expr?8303ExprList <- (Expr COMMA)* Expr?
82868304
...@@ -8337,6 +8355,7 @@ multibyte_utf8 <-...@@ -8337,6 +8355,7 @@ multibyte_utf8 <-
8337 / oxC2_oxDF ox80_oxBF8355 / oxC2_oxDF ox80_oxBF
83388356
8339non_control_ascii <- [\040-\176]8357non_control_ascii <- [\040-\176]
8358non_control_utf8 <- [\040-\377]
83408359
8341char_escape8360char_escape
8342 <- "\\x" hex hex8361 <- "\\x" hex hex
...@@ -8352,10 +8371,10 @@ string_char...@@ -8352,10 +8371,10 @@ string_char
8352 / char_escape8371 / char_escape
8353 / ![\\"\n] non_control_ascii8372 / ![\\"\n] non_control_ascii
83548373
8355container_doc_comment <- ('//!' [^\n]* [ \n]* skip)+8374container_doc_comment <- ('//!' non_control_utf8* [ \n]* skip)+
8356doc_comment <- ('///' [^\n]* [ \n]* skip)+8375doc_comment <- ('///' non_control_utf8* [ \n]* skip)+
8357line_comment <- '//' ![!/][^\n]* / '////' [^\n]*8376line_comment <- '//' ![!/] non_control_utf8* / '////' non_control_utf8*
8358line_string <- ('\\\\' [^\n]* [ \n]*)+8377line_string <- '\\\\' non_control_utf8* [ \n]*
8359skip <- ([ \n] / line_comment)*8378skip <- ([ \n] / line_comment)*
83608379
8361CHAR_LITERAL <- ['] char_char ['] skip8380CHAR_LITERAL <- ['] char_char ['] skip
lib/std/zig/Ast.zig-4
...@@ -504,9 +504,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void...@@ -504,9 +504,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void
504 .varargs_nonfinal => {504 .varargs_nonfinal => {
505 return w.writeAll("function prototype has parameter after varargs");505 return w.writeAll("function prototype has parameter after varargs");
506 },506 },
507 .expected_continue_expr => {
508 return w.writeAll("expected ':' before while continue expression");
509 },
510507
511 .expected_semi_after_decl => {508 .expected_semi_after_decl => {
512 return w.writeAll("expected ';' after declaration");509 return w.writeAll("expected ';' after declaration");
...@@ -2888,7 +2885,6 @@ pub const Error = struct {...@@ -2888,7 +2885,6 @@ pub const Error = struct {
2888 test_doc_comment,2885 test_doc_comment,
2889 comptime_doc_comment,2886 comptime_doc_comment,
2890 varargs_nonfinal,2887 varargs_nonfinal,
2891 expected_continue_expr,
2892 expected_semi_after_decl,2888 expected_semi_after_decl,
2893 expected_semi_after_stmt,2889 expected_semi_after_stmt,
2894 expected_comma_after_field,2890 expected_comma_after_field,
lib/std/zig/Parse.zig+83-74
...@@ -257,7 +257,7 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {...@@ -257,7 +257,7 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
257 while (true) {257 while (true) {
258 const doc_comment = try p.eatDocComments();258 const doc_comment = try p.eatDocComments();
259259
260 switch (p.tokenTag(p.tok_i)) {260 sw: switch (p.tokenTag(p.tok_i)) {
261 .keyword_test => {261 .keyword_test => {
262 if (doc_comment) |some| {262 if (doc_comment) |some| {
263 try p.warnMsg(.{ .tag = .test_doc_comment, .token = some });263 try p.warnMsg(.{ .tag = .test_doc_comment, .token = some });
...@@ -348,17 +348,7 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {...@@ -348,17 +348,7 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
348 p.findNextContainerMember();348 p.findNextContainerMember();
349 },349 },
350 },350 },
351 .keyword_pub => {351 .keyword_pub,
352 p.tok_i += 1;
353 const opt_top_level_decl = try p.expectTopLevelDeclRecoverable();
354 if (opt_top_level_decl) |top_level_decl| {
355 if (field_state == .seen) {
356 field_state = .{ .end = top_level_decl };
357 }
358 try p.scratch.append(p.gpa, top_level_decl);
359 }
360 trailing = p.tokenTag(p.tok_i - 1) == .semicolon;
361 },
362 .keyword_const,352 .keyword_const,
363 .keyword_var,353 .keyword_var,
364 .keyword_threadlocal,354 .keyword_threadlocal,
...@@ -367,7 +357,27 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {...@@ -367,7 +357,27 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
367 .keyword_inline,357 .keyword_inline,
368 .keyword_noinline,358 .keyword_noinline,
369 .keyword_fn,359 .keyword_fn,
370 => {360 => |t| {
361 if (t == .keyword_extern) {
362 switch (p.tokenTag(p.tok_i + 1)) {
363 .keyword_struct,
364 .keyword_union,
365 .keyword_enum,
366 .keyword_opaque,
367 => |ct| continue :sw ct,
368 else => {},
369 }
370 }
371 if (t == .keyword_inline) {
372 switch (p.tokenTag(p.tok_i + 1)) {
373 .keyword_for,
374 .keyword_while,
375 => |ct| continue :sw ct,
376 else => {},
377 }
378 }
379
380 p.tok_i += @intFromBool(t == .keyword_pub);
371 const opt_top_level_decl = try p.expectTopLevelDeclRecoverable();381 const opt_top_level_decl = try p.expectTopLevelDeclRecoverable();
372 if (opt_top_level_decl) |top_level_decl| {382 if (opt_top_level_decl) |top_level_decl| {
373 if (field_state == .seen) {383 if (field_state == .seen) {
...@@ -588,7 +598,8 @@ fn expectTestDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index {...@@ -588,7 +598,8 @@ fn expectTestDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index {
588}598}
589599
590/// Decl600/// Decl
591/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)601/// <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)
602/// / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON
592/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl603/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
593fn expectTopLevelDecl(p: *Parse) !?Node.Index {604fn expectTopLevelDecl(p: *Parse) !?Node.Index {
594 const extern_export_inline_token = p.nextToken();605 const extern_export_inline_token = p.nextToken();
...@@ -665,7 +676,7 @@ fn expectTopLevelDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index {...@@ -665,7 +676,7 @@ fn expectTopLevelDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index {
665 };676 };
666}677}
667678
668/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr679/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix
669fn parseFnProto(p: *Parse) !?Node.Index {680fn parseFnProto(p: *Parse) !?Node.Index {
670 const fn_token = p.eatToken(.keyword_fn) orelse return null;681 const fn_token = p.eatToken(.keyword_fn) orelse return null;
671682
...@@ -853,7 +864,7 @@ fn parseGlobalVarDecl(p: *Parse) !?Node.Index {...@@ -853,7 +864,7 @@ fn parseGlobalVarDecl(p: *Parse) !?Node.Index {
853 return var_decl;864 return var_decl;
854}865}
855866
856/// ContainerField <- doc_comment? KEYWORD_comptime? !KEYWORD_fn (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)?867/// ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)?
857fn expectContainerField(p: *Parse) !Node.Index {868fn expectContainerField(p: *Parse) !Node.Index {
858 _ = p.eatToken(.keyword_comptime);869 _ = p.eatToken(.keyword_comptime);
859 const main_token = p.tok_i;870 const main_token = p.tok_i;
...@@ -895,16 +906,23 @@ fn expectContainerField(p: *Parse) !Node.Index {...@@ -895,16 +906,23 @@ fn expectContainerField(p: *Parse) !Node.Index {
895 }906 }
896}907}
897908
898/// Statement909/// BlockStatement
899/// <- KEYWORD_comptime ComptimeStatement910/// <- Statement
900/// / KEYWORD_nosuspend BlockExprStatement
901/// / KEYWORD_suspend BlockExprStatement
902/// / KEYWORD_defer BlockExprStatement911/// / KEYWORD_defer BlockExprStatement
903/// / KEYWORD_errdefer Payload? BlockExprStatement912/// / KEYWORD_errdefer Payload? BlockExprStatement
904/// / IfStatement913/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
914///
915/// Statement
916/// <- ExprStatement
917/// / KEYWORD_suspend BlockExprStatement
918/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON
919///
920/// ExprStatement
921/// <- IfStatement
905/// / LabeledStatement922/// / LabeledStatement
906/// / VarDeclExprStatement923/// / KEYWORD_nosuspend BlockExprStatement
907fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index {924/// / KEYWORD_comptime BlockExpr
925fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
908 if (p.eatToken(.keyword_comptime)) |comptime_token| {926 if (p.eatToken(.keyword_comptime)) |comptime_token| {
909 const opt_block_expr = try p.parseBlockExpr();927 const opt_block_expr = try p.parseBlockExpr();
910 if (opt_block_expr) |block_expr| {928 if (opt_block_expr) |block_expr| {
...@@ -915,7 +933,7 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index {...@@ -915,7 +933,7 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index {
915 });933 });
916 }934 }
917935
918 if (allow_defer_var) {936 if (is_block_level) {
919 return p.expectVarDeclExprStatement(comptime_token);937 return p.expectVarDeclExprStatement(comptime_token);
920 } else {938 } else {
921 const assign = try p.expectAssignExpr();939 const assign = try p.expectAssignExpr();
...@@ -949,12 +967,12 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index {...@@ -949,12 +967,12 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index {
949 .data = .{ .node = block_expr },967 .data = .{ .node = block_expr },
950 });968 });
951 },969 },
952 .keyword_defer => if (allow_defer_var) return p.addNode(.{970 .keyword_defer => if (is_block_level) return p.addNode(.{
953 .tag = .@"defer",971 .tag = .@"defer",
954 .main_token = p.nextToken(),972 .main_token = p.nextToken(),
955 .data = .{ .node = try p.expectBlockExprStatement() },973 .data = .{ .node = try p.expectBlockExprStatement() },
956 }),974 }),
957 .keyword_errdefer => if (allow_defer_var) return p.addNode(.{975 .keyword_errdefer => if (is_block_level) return p.addNode(.{
958 .tag = .@"errdefer",976 .tag = .@"errdefer",
959 .main_token = p.nextToken(),977 .main_token = p.nextToken(),
960 .data = .{ .opt_token_and_node = .{978 .data = .{ .opt_token_and_node = .{
...@@ -979,7 +997,7 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index {...@@ -979,7 +997,7 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index {
979997
980 if (try p.parseLabeledStatement()) |labeled_statement| return labeled_statement;998 if (try p.parseLabeledStatement()) |labeled_statement| return labeled_statement;
981999
982 if (allow_defer_var) {1000 if (is_block_level) {
983 return p.expectVarDeclExprStatement(null);1001 return p.expectVarDeclExprStatement(null);
984 } else {1002 } else {
985 const assign = try p.expectAssignExpr();1003 const assign = try p.expectAssignExpr();
...@@ -1007,8 +1025,10 @@ fn expectComptimeStatement(p: *Parse, comptime_token: TokenIndex) !Node.Index {...@@ -1007,8 +1025,10 @@ fn expectComptimeStatement(p: *Parse, comptime_token: TokenIndex) !Node.Index {
1007}1025}
10081026
1009/// VarDeclExprStatement1027/// VarDeclExprStatement
1010/// <- VarDeclProto (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON1028/// <- Expr
1011/// / Expr (AssignOp Expr / (COMMA (VarDeclProto / Expr))+ EQUAL Expr)? SEMICOLON1029/// / VarAssignStatement
1030///
1031/// VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON
1012fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index {1032fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index {
1013 const scratch_top = p.scratch.items.len;1033 const scratch_top = p.scratch.items.len;
1014 defer p.scratch.shrinkRetainingCapacity(scratch_top);1034 defer p.scratch.shrinkRetainingCapacity(scratch_top);
...@@ -1140,7 +1160,7 @@ fn expectStatementRecoverable(p: *Parse) Error!?Node.Index {...@@ -1140,7 +1160,7 @@ fn expectStatementRecoverable(p: *Parse) Error!?Node.Index {
11401160
1141/// IfStatement1161/// IfStatement
1142/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?1162/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
1143/// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )1163/// / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
1144fn expectIfStatement(p: *Parse) !Node.Index {1164fn expectIfStatement(p: *Parse) !Node.Index {
1145 const if_token = p.assertToken(.keyword_if);1165 const if_token = p.assertToken(.keyword_if);
1146 _ = try p.expectToken(.l_paren);1166 _ = try p.expectToken(.l_paren);
...@@ -1235,8 +1255,8 @@ fn parseLoopStatement(p: *Parse) !?Node.Index {...@@ -1235,8 +1255,8 @@ fn parseLoopStatement(p: *Parse) !?Node.Index {
1235}1255}
12361256
1237/// ForStatement1257/// ForStatement
1238/// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?1258/// <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )
1239/// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )1259/// / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement )
1240fn parseForStatement(p: *Parse) !?Node.Index {1260fn parseForStatement(p: *Parse) !?Node.Index {
1241 const for_token = p.eatToken(.keyword_for) orelse return null;1261 const for_token = p.eatToken(.keyword_for) orelse return null;
12421262
...@@ -1293,7 +1313,7 @@ fn parseForStatement(p: *Parse) !?Node.Index {...@@ -1293,7 +1313,7 @@ fn parseForStatement(p: *Parse) !?Node.Index {
1293///1313///
1294/// WhileStatement1314/// WhileStatement
1295/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?1315/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
1296/// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )1316/// / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
1297fn parseWhileStatement(p: *Parse) !?Node.Index {1317fn parseWhileStatement(p: *Parse) !?Node.Index {
1298 const while_token = p.eatToken(.keyword_while) orelse return null;1318 const while_token = p.eatToken(.keyword_while) orelse return null;
1299 _ = try p.expectToken(.l_paren);1319 _ = try p.expectToken(.l_paren);
...@@ -1383,7 +1403,7 @@ fn parseWhileStatement(p: *Parse) !?Node.Index {...@@ -1383,7 +1403,7 @@ fn parseWhileStatement(p: *Parse) !?Node.Index {
13831403
1384/// BlockExprStatement1404/// BlockExprStatement
1385/// <- BlockExpr1405/// <- BlockExpr
1386/// / AssignExpr SEMICOLON1406/// / !BlockExpr AssignExpr SEMICOLON
1387fn parseBlockExprStatement(p: *Parse) !?Node.Index {1407fn parseBlockExprStatement(p: *Parse) !?Node.Index {
1388 const block_expr = try p.parseBlockExpr();1408 const block_expr = try p.parseBlockExpr();
1389 if (block_expr) |expr| return expr;1409 if (block_expr) |expr| return expr;
...@@ -1685,18 +1705,20 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index {...@@ -1685,18 +1705,20 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index {
1685/// PrefixTypeOp1705/// PrefixTypeOp
1686/// <- QUESTIONMARK1706/// <- QUESTIONMARK
1687/// / KEYWORD_anyframe MINUSRARROW1707/// / KEYWORD_anyframe MINUSRARROW
1688/// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*1708/// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
1709/// / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
1689/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*1710/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
1690/// / ArrayTypeStart1711/// / ArrayTypeStart
1691///1712///
1692/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET1713/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
1693///1714///
1694/// PtrTypeStart1715/// SinglePtrTypeStart <- ASTERISK / ASTERISK2
1695/// <- ASTERISK1716///
1696/// / ASTERISK21717/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
1697/// / LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET1718///
1719/// ArrayTypeStart <- LBRACKET Expr !(ASTERISK / ASTERISK2) (COLON Expr)? RBRACKET
1698///1720///
1699/// ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET1721/// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
1700fn parseTypeExpr(p: *Parse) Error!?Node.Index {1722fn parseTypeExpr(p: *Parse) Error!?Node.Index {
1701 switch (p.tokenTag(p.tok_i)) {1723 switch (p.tokenTag(p.tok_i)) {
1702 .question_mark => return try p.addNode(.{1724 .question_mark => return try p.addNode(.{
...@@ -1962,12 +1984,12 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index {...@@ -1962,12 +1984,12 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index {
1962/// PrimaryExpr1984/// PrimaryExpr
1963/// <- AsmExpr1985/// <- AsmExpr
1964/// / IfExpr1986/// / IfExpr
1965/// / KEYWORD_break BreakLabel? Expr?1987/// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
1966/// / KEYWORD_comptime Expr1988/// / KEYWORD_comptime Expr !ExprSuffix
1967/// / KEYWORD_nosuspend Expr1989/// / KEYWORD_nosuspend Expr !ExprSuffix
1968/// / KEYWORD_continue BreakLabel? Expr?1990/// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
1969/// / KEYWORD_resume Expr1991/// / KEYWORD_resume Expr !ExprSuffix
1970/// / KEYWORD_return Expr?1992/// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart)
1971/// / BlockLabel? LoopExpr1993/// / BlockLabel? LoopExpr
1972/// / Block1994/// / Block
1973/// / CurlySuffixExpr1995/// / CurlySuffixExpr
...@@ -2042,10 +2064,6 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {...@@ -2042,10 +2064,6 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {
2042 p.tok_i += 2;2064 p.tok_i += 2;
2043 return try p.parseWhileExpr();2065 return try p.parseWhileExpr();
2044 },2066 },
2045 .l_brace => {
2046 p.tok_i += 2;
2047 return try p.parseBlock();
2048 },
2049 else => return try p.parseCurlySuffixExpr(),2067 else => return try p.parseCurlySuffixExpr(),
2050 }2068 }
2051 } else {2069 } else {
...@@ -2067,12 +2085,12 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {...@@ -2067,12 +2085,12 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {
2067 }2085 }
2068}2086}
20692087
2070/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?2088/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
2071fn parseIfExpr(p: *Parse) !?Node.Index {2089fn parseIfExpr(p: *Parse) !?Node.Index {
2072 return try p.parseIf(expectExpr);2090 return try p.parseIf(expectExpr);
2073}2091}
20742092
2075/// Block <- LBRACE Statement* RBRACE2093/// Block <- LBRACE BlockStatement* RBRACE
2076fn parseBlock(p: *Parse) !?Node.Index {2094fn parseBlock(p: *Parse) !?Node.Index {
2077 const lbrace = p.eatToken(.l_brace) orelse return null;2095 const lbrace = p.eatToken(.l_brace) orelse return null;
2078 const scratch_top = p.scratch.items.len;2096 const scratch_top = p.scratch.items.len;
...@@ -2177,7 +2195,7 @@ fn forPrefix(p: *Parse) Error!usize {...@@ -2177,7 +2195,7 @@ fn forPrefix(p: *Parse) Error!usize {
21772195
2178/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?2196/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2179///2197///
2180/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?2198/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi
2181fn parseWhileExpr(p: *Parse) !?Node.Index {2199fn parseWhileExpr(p: *Parse) !?Node.Index {
2182 const while_token = p.eatToken(.keyword_while) orelse return null;2200 const while_token = p.eatToken(.keyword_while) orelse return null;
2183 _ = try p.expectToken(.l_paren);2201 _ = try p.expectToken(.l_paren);
...@@ -2409,10 +2427,10 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index {...@@ -2409,10 +2427,10 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index {
2409/// / FnProto2427/// / FnProto
2410/// / GroupedExpr2428/// / GroupedExpr
2411/// / LabeledTypeExpr2429/// / LabeledTypeExpr
2412/// / IDENTIFIER2430/// / IDENTIFIER !(COLON LabelableExpr)
2413/// / IfTypeExpr2431/// / IfTypeExpr
2414/// / INTEGER2432/// / INTEGER
2415/// / KEYWORD_comptime TypeExpr2433/// / KEYWORD_comptime TypeExpr !ExprSuffix
2416/// / KEYWORD_error DOT IDENTIFIER2434/// / KEYWORD_error DOT IDENTIFIER
2417/// / KEYWORD_anyframe2435/// / KEYWORD_anyframe
2418/// / KEYWORD_unreachable2436/// / KEYWORD_unreachable
...@@ -2431,7 +2449,7 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index {...@@ -2431,7 +2449,7 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index {
2431///2449///
2432/// GroupedExpr <- LPAREN Expr RPAREN2450/// GroupedExpr <- LPAREN Expr RPAREN
2433///2451///
2434/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?2452/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
2435///2453///
2436/// LabeledTypeExpr2454/// LabeledTypeExpr
2437/// <- BlockLabel Block2455/// <- BlockLabel Block
...@@ -2711,7 +2729,7 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index {...@@ -2711,7 +2729,7 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index {
27112729
2712/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?2730/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2713///2731///
2714/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?2732/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
2715fn parseWhileTypeExpr(p: *Parse) !?Node.Index {2733fn parseWhileTypeExpr(p: *Parse) !?Node.Index {
2716 const while_token = p.eatToken(.keyword_while) orelse return null;2734 const while_token = p.eatToken(.keyword_while) orelse return null;
2717 _ = try p.expectToken(.l_paren);2735 _ = try p.expectToken(.l_paren);
...@@ -2876,7 +2894,7 @@ fn expectAsmExpr(p: *Parse) !Node.Index {...@@ -2876,7 +2894,7 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
2876 });2894 });
2877}2895}
28782896
2879/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN2897/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
2880fn parseAsmOutputItem(p: *Parse) !?Node.Index {2898fn parseAsmOutputItem(p: *Parse) !?Node.Index {
2881 _ = p.eatToken(.l_bracket) orelse return null;2899 _ = p.eatToken(.l_bracket) orelse return null;
2882 const identifier = try p.expectToken(.identifier);2900 const identifier = try p.expectToken(.identifier);
...@@ -2902,7 +2920,7 @@ fn parseAsmOutputItem(p: *Parse) !?Node.Index {...@@ -2902,7 +2920,7 @@ fn parseAsmOutputItem(p: *Parse) !?Node.Index {
2902 });2920 });
2903}2921}
29042922
2905/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN2923/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN
2906fn parseAsmInputItem(p: *Parse) !?Node.Index {2924fn parseAsmInputItem(p: *Parse) !?Node.Index {
2907 _ = p.eatToken(.l_bracket) orelse return null;2925 _ = p.eatToken(.l_bracket) orelse return null;
2908 const identifier = try p.expectToken(.identifier);2926 const identifier = try p.expectToken(.identifier);
...@@ -2923,9 +2941,7 @@ fn parseAsmInputItem(p: *Parse) !?Node.Index {...@@ -2923,9 +2941,7 @@ fn parseAsmInputItem(p: *Parse) !?Node.Index {
29232941
2924/// BreakLabel <- COLON IDENTIFIER2942/// BreakLabel <- COLON IDENTIFIER
2925fn parseBreakLabel(p: *Parse) Error!OptionalTokenIndex {2943fn parseBreakLabel(p: *Parse) Error!OptionalTokenIndex {
2926 _ = p.eatToken(.colon) orelse return .none;2944 return if (p.eatTokens(&.{ .colon, .identifier })) |i| .fromToken(i + 1) else .none;
2927 const next_token = try p.expectToken(.identifier);
2928 return .fromToken(next_token);
2929}2945}
29302946
2931/// BlockLabel <- IDENTIFIER COLON2947/// BlockLabel <- IDENTIFIER COLON
...@@ -2950,12 +2966,7 @@ fn expectFieldInit(p: *Parse) !Node.Index {...@@ -2950,12 +2966,7 @@ fn expectFieldInit(p: *Parse) !Node.Index {
29502966
2951/// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN2967/// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
2952fn parseWhileContinueExpr(p: *Parse) !?Node.Index {2968fn parseWhileContinueExpr(p: *Parse) !?Node.Index {
2953 _ = p.eatToken(.colon) orelse {2969 _ = p.eatToken(.colon) orelse return null;
2954 if (p.tokenTag(p.tok_i) == .l_paren and
2955 p.tokensOnSameLine(p.tok_i - 1, p.tok_i))
2956 return p.fail(.expected_continue_expr);
2957 return null;
2958 };
2959 _ = try p.expectToken(.l_paren);2970 _ = try p.expectToken(.l_paren);
2960 const node = try p.parseAssignExpr() orelse return p.fail(.expected_expr_or_assignment);2971 const node = try p.parseAssignExpr() orelse return p.fail(.expected_expr_or_assignment);
2961 _ = try p.expectToken(.r_paren);2972 _ = try p.expectToken(.r_paren);
...@@ -2993,9 +3004,7 @@ fn parseAddrSpace(p: *Parse) !?Node.Index {...@@ -2993,9 +3004,7 @@ fn parseAddrSpace(p: *Parse) !?Node.Index {
2993/// such as in the case of anytype and `...`. Caller must look for rparen to find3004/// such as in the case of anytype and `...`. Caller must look for rparen to find
2994/// out when there are no more param decls left.3005/// out when there are no more param decls left.
2995///3006///
2996/// ParamDecl3007/// ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime / !KEYWORD_comptime) (IDENTIFIER COLON / !(IDENTIFIER_COLON)) ParamType
2997/// <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
2998/// / DOT3
2999///3008///
3000/// ParamType3009/// ParamType
3001/// <- KEYWORD_anytype3010/// <- KEYWORD_anytype
...@@ -3482,7 +3491,7 @@ fn parseSwitchProngList(p: *Parse) !Node.SubRange {...@@ -3482,7 +3491,7 @@ fn parseSwitchProngList(p: *Parse) !Node.SubRange {
3482 return p.listToSpan(p.scratch.items[scratch_top..]);3491 return p.listToSpan(p.scratch.items[scratch_top..]);
3483}3492}
34843493
3485/// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?3494/// ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)?
3486fn parseParamDeclList(p: *Parse) !SmallSpan {3495fn parseParamDeclList(p: *Parse) !SmallSpan {
3487 _ = try p.expectToken(.l_paren);3496 _ = try p.expectToken(.l_paren);
3488 const scratch_top = p.scratch.items.len;3497 const scratch_top = p.scratch.items.len;
...@@ -3604,9 +3613,9 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N...@@ -3604,9 +3613,9 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N
3604 });3613 });
3605}3614}
36063615
3607/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?3616/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix
3608///3617///
3609/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?3618/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix
3610fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index {3619fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index {
3611 const for_token = p.eatToken(.keyword_for) orelse return null;3620 const for_token = p.eatToken(.keyword_for) orelse return null;
36123621
lib/std/zig/parser_test.zig+30-9
...@@ -5472,17 +5472,11 @@ test "zig fmt: while continue expr" {...@@ -5472,17 +5472,11 @@ test "zig fmt: while continue expr" {
5472 \\ while (i > 0)5472 \\ while (i > 0)
5473 \\ (i * 2);5473 \\ (i * 2);
5474 \\}5474 \\}
5475 \\T: (while (true) ({
5476 \\ break usize;
5477 \\})),
5475 \\5478 \\
5476 );5479 );
5477 try testError(
5478 \\test {
5479 \\ while (i > 0) (i -= 1) {
5480 \\ print("test123", .{});
5481 \\ }
5482 \\}
5483 , &[_]Error{
5484 .expected_continue_expr,
5485 });
5486}5480}
54875481
5488test "zig fmt: canonicalize symbols (simple)" {5482test "zig fmt: canonicalize symbols (simple)" {
...@@ -6838,6 +6832,33 @@ test "zig fmt: error set with extra newline before comma" {...@@ -6838,6 +6832,33 @@ test "zig fmt: error set with extra newline before comma" {
6838 );6832 );
6839}6833}
68406834
6835test "zig fmt: extern container in tuple" {
6836 try testCanonical(
6837 \\const T = struct {
6838 \\ extern struct {},
6839 \\ extern union {},
6840 \\ extern enum {},
6841 \\};
6842 \\
6843 );
6844}
6845
6846test "zig fmt: break followed by colon" {
6847 try testCanonical(
6848 \\const a = [if (cond) len else break:0]u8;
6849 \\
6850 );
6851}
6852
6853test "zig fmt: array init of labeled block" {
6854 try testCanonical(
6855 \\const a = blk: {
6856 \\ break :blk T;
6857 \\}{ .a = false };
6858 \\
6859 );
6860}
6861
6841test "recovery: top level" {6862test "recovery: top level" {
6842 try testError(6863 try testError(
6843 \\test "" {inline}6864 \\test "" {inline}
lib/std/zig/tokenizer.zig+2-1
...@@ -313,7 +313,8 @@ pub const Token = struct {...@@ -313,7 +313,8 @@ pub const Token = struct {
313 return tag.lexeme() orelse switch (tag) {313 return tag.lexeme() orelse switch (tag) {
314 .invalid => "invalid token",314 .invalid => "invalid token",
315 .identifier => "an identifier",315 .identifier => "an identifier",
316 .string_literal, .multiline_string_literal_line => "a string literal",316 .string_literal => "a string literal",
317 .multiline_string_literal_line => "a multiline string literal",
317 .char_literal => "a character literal",318 .char_literal => "a character literal",
318 .eof => "EOF",319 .eof => "EOF",
319 .builtin => "a builtin function",320 .builtin => "a builtin function",