diff --git a/doc/langref.html.in b/doc/langref.html.in index 3642e9bc182044931fc269f47e913afb9bc829a8..a084a57825712b5f88ce17ffc5e70ae66b4e02ea 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7944,58 +7944,60 @@ TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block ComptimeDecl <- KEYWORD_comptime Block Decl - <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block) + <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block) + / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl -FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr +FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON -ContainerField <- doc_comment? KEYWORD_comptime? !KEYWORD_fn (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)? +ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)? # *** Block Level *** -Statement - <- KEYWORD_comptime ComptimeStatement - / KEYWORD_nosuspend BlockExprStatement - / KEYWORD_suspend BlockExprStatement +BlockStatement + <- Statement / KEYWORD_defer BlockExprStatement / KEYWORD_errdefer Payload? BlockExprStatement - / IfStatement + / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement + +Statement + <- ExprStatement + / KEYWORD_suspend BlockExprStatement + / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON + +ExprStatement + <- IfStatement / LabeledStatement - / VarDeclExprStatement - -ComptimeStatement - <- BlockExpr - / VarDeclExprStatement + / KEYWORD_nosuspend BlockExprStatement + / KEYWORD_comptime BlockExpr IfStatement <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? - / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) + / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr) LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) ForStatement - <- ForPrefix BlockExpr ( KEYWORD_else Statement )? - / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) + <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else ) + / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement ) WhileStatement <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? - / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) + / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) BlockExprStatement <- BlockExpr - / AssignExpr SEMICOLON + / !BlockExpr AssignExpr SEMICOLON BlockExpr <- BlockLabel? Block -# An expression, assignment, or any destructure, as a statement. -VarDeclExprStatement - <- VarDeclProto (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON - / Expr (AssignOp Expr / (COMMA (VarDeclProto / Expr))+ EQUAL Expr)? SEMICOLON +# An assignment or a destructure whose LHS are all lvalue expressions or variable declarations. +VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON # *** Expression Level *** @@ -8025,25 +8027,25 @@ PrefixExpr <- PrefixOp* PrimaryExpr PrimaryExpr <- AsmExpr / IfExpr - / KEYWORD_break BreakLabel? Expr? - / KEYWORD_comptime Expr - / KEYWORD_nosuspend Expr - / KEYWORD_continue BreakLabel? Expr? - / KEYWORD_resume Expr - / KEYWORD_return Expr? + / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) + / KEYWORD_comptime Expr !ExprSuffix + / KEYWORD_nosuspend Expr !ExprSuffix + / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) + / KEYWORD_resume Expr !ExprSuffix + / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart) / BlockLabel? LoopExpr / Block / CurlySuffixExpr -IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? +IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix -Block <- LBRACE Statement* RBRACE +Block <- LBRACE BlockStatement* RBRACE LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) -ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? +ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix -WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? +WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix CurlySuffixExpr <- TypeExpr InitList? @@ -8070,10 +8072,10 @@ PrimaryTypeExpr / FnProto / GroupedExpr / LabeledTypeExpr - / IDENTIFIER + / IDENTIFIER !(COLON LabelableExpr) / IfTypeExpr / INTEGER - / KEYWORD_comptime TypeExpr + / KEYWORD_comptime TypeExpr !ExprSuffix / KEYWORD_error DOT IDENTIFIER / KEYWORD_anyframe / KEYWORD_unreachable @@ -8085,7 +8087,7 @@ ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE GroupedExpr <- LPAREN Expr RPAREN -IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? +IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix LabeledTypeExpr <- BlockLabel Block @@ -8094,9 +8096,9 @@ LabeledTypeExpr LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) -ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)? +ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix -WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? +WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE @@ -8105,11 +8107,11 @@ AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN AsmOutput <- COLON AsmOutputList AsmInput? -AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN +AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN AsmInput <- COLON AsmInputList AsmClobbers? -AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN +AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN AsmClobbers <- COLON Expr @@ -8129,9 +8131,7 @@ AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN # Fn specific CallConv <- KEYWORD_callconv LPAREN Expr RPAREN -ParamDecl - <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType - / DOT3 +ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime / !KEYWORD_comptime) (IDENTIFIER COLON / !(IDENTIFIER_COLON)) ParamType ParamType <- KEYWORD_anytype @@ -8237,8 +8237,8 @@ PrefixOp PrefixTypeOp <- QUESTIONMARK / KEYWORD_anyframe MINUSRARROW - / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* - / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* + / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? + / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? / ArrayTypeStart SuffixOp @@ -8249,15 +8249,31 @@ SuffixOp FnCallArguments <- LPAREN ExprList RPAREN +ExprSuffix + <- KEYWORD_or + / KEYWORD_and + / CompareOp + / BitwiseOp + / BitShiftOp + / AdditionOp + / MultiplyOp + / EXCLAMATIONMARK + / SuffixOp + / FnCallArguments + +LabelableExpr + <- Block + / SwitchExpr + / LoopExpr + # Ptr specific SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET -PtrTypeStart - <- ASTERISK - / ASTERISK2 - / LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET +SinglePtrTypeStart <- ASTERISK / ASTERISK2 -ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET +ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET + +ArrayTypeStart <- LBRACKET Expr !(ASTERISK / ASTERISK2) (COLON Expr)? RBRACKET # ContainerDecl specific ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE @@ -8266,11 +8282,13 @@ ContainerDeclType <- KEYWORD_struct (LPAREN Expr RPAREN)? / KEYWORD_opaque / KEYWORD_enum (LPAREN Expr RPAREN)? - / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? + / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / !KEYWORD_enum Expr) RPAREN)? # Alignment ByteAlign <- KEYWORD_align LPAREN Expr RPAREN +BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN + # Lists IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)? @@ -8280,7 +8298,7 @@ AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? -ParamDeclList <- (ParamDecl COMMA)* ParamDecl? +ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)? ExprList <- (Expr COMMA)* Expr? @@ -8337,6 +8355,7 @@ multibyte_utf8 <- / oxC2_oxDF ox80_oxBF non_control_ascii <- [\040-\176] +non_control_utf8 <- [\040-\377] char_escape <- "\\x" hex hex @@ -8352,10 +8371,10 @@ string_char / char_escape / ![\\"\n] non_control_ascii -container_doc_comment <- ('//!' [^\n]* [ \n]* skip)+ -doc_comment <- ('///' [^\n]* [ \n]* skip)+ -line_comment <- '//' ![!/][^\n]* / '////' [^\n]* -line_string <- ('\\\\' [^\n]* [ \n]*)+ +container_doc_comment <- ('//!' non_control_utf8* [ \n]* skip)+ +doc_comment <- ('///' non_control_utf8* [ \n]* skip)+ +line_comment <- '//' ![!/] non_control_utf8* / '////' non_control_utf8* +line_string <- '\\\\' non_control_utf8* [ \n]* skip <- ([ \n] / line_comment)* CHAR_LITERAL <- ['] char_char ['] skip diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 7c73c3d4d762b94c69914875d237b167eb2929de..3e253543f173d869391212de5cfd3cfe2654da5f 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -504,9 +504,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void .varargs_nonfinal => { return w.writeAll("function prototype has parameter after varargs"); }, - .expected_continue_expr => { - return w.writeAll("expected ':' before while continue expression"); - }, .expected_semi_after_decl => { return w.writeAll("expected ';' after declaration"); @@ -2888,7 +2885,6 @@ pub const Error = struct { test_doc_comment, comptime_doc_comment, varargs_nonfinal, - expected_continue_expr, expected_semi_after_decl, expected_semi_after_stmt, expected_comma_after_field, diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index 5dcc183a2176af2b1f044765fc8230da54aec26c..541a74c3ea112bfa12738e6690d75db1184f8c66 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -257,7 +257,7 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { while (true) { const doc_comment = try p.eatDocComments(); - switch (p.tokenTag(p.tok_i)) { + sw: switch (p.tokenTag(p.tok_i)) { .keyword_test => { if (doc_comment) |some| { try p.warnMsg(.{ .tag = .test_doc_comment, .token = some }); @@ -348,17 +348,7 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { p.findNextContainerMember(); }, }, - .keyword_pub => { - p.tok_i += 1; - const opt_top_level_decl = try p.expectTopLevelDeclRecoverable(); - if (opt_top_level_decl) |top_level_decl| { - if (field_state == .seen) { - field_state = .{ .end = top_level_decl }; - } - try p.scratch.append(p.gpa, top_level_decl); - } - trailing = p.tokenTag(p.tok_i - 1) == .semicolon; - }, + .keyword_pub, .keyword_const, .keyword_var, .keyword_threadlocal, @@ -367,7 +357,27 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { .keyword_inline, .keyword_noinline, .keyword_fn, - => { + => |t| { + if (t == .keyword_extern) { + switch (p.tokenTag(p.tok_i + 1)) { + .keyword_struct, + .keyword_union, + .keyword_enum, + .keyword_opaque, + => |ct| continue :sw ct, + else => {}, + } + } + if (t == .keyword_inline) { + switch (p.tokenTag(p.tok_i + 1)) { + .keyword_for, + .keyword_while, + => |ct| continue :sw ct, + else => {}, + } + } + + p.tok_i += @intFromBool(t == .keyword_pub); const opt_top_level_decl = try p.expectTopLevelDeclRecoverable(); if (opt_top_level_decl) |top_level_decl| { if (field_state == .seen) { @@ -588,7 +598,8 @@ fn expectTestDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index { } /// Decl -/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block) +/// <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block) +/// / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl fn expectTopLevelDecl(p: *Parse) !?Node.Index { const extern_export_inline_token = p.nextToken(); @@ -665,7 +676,7 @@ fn expectTopLevelDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index { }; } -/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr +/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix fn parseFnProto(p: *Parse) !?Node.Index { const fn_token = p.eatToken(.keyword_fn) orelse return null; @@ -853,7 +864,7 @@ fn parseGlobalVarDecl(p: *Parse) !?Node.Index { return var_decl; } -/// ContainerField <- doc_comment? KEYWORD_comptime? !KEYWORD_fn (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)? +/// ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)? fn expectContainerField(p: *Parse) !Node.Index { _ = p.eatToken(.keyword_comptime); const main_token = p.tok_i; @@ -895,16 +906,23 @@ fn expectContainerField(p: *Parse) !Node.Index { } } -/// Statement -/// <- KEYWORD_comptime ComptimeStatement -/// / KEYWORD_nosuspend BlockExprStatement -/// / KEYWORD_suspend BlockExprStatement +/// BlockStatement +/// <- Statement /// / KEYWORD_defer BlockExprStatement /// / KEYWORD_errdefer Payload? BlockExprStatement -/// / IfStatement +/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement +/// +/// Statement +/// <- ExprStatement +/// / KEYWORD_suspend BlockExprStatement +/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON +/// +/// ExprStatement +/// <- IfStatement /// / LabeledStatement -/// / VarDeclExprStatement -fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index { +/// / KEYWORD_nosuspend BlockExprStatement +/// / KEYWORD_comptime BlockExpr +fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { if (p.eatToken(.keyword_comptime)) |comptime_token| { const opt_block_expr = try p.parseBlockExpr(); if (opt_block_expr) |block_expr| { @@ -915,7 +933,7 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index { }); } - if (allow_defer_var) { + if (is_block_level) { return p.expectVarDeclExprStatement(comptime_token); } else { const assign = try p.expectAssignExpr(); @@ -949,12 +967,12 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index { .data = .{ .node = block_expr }, }); }, - .keyword_defer => if (allow_defer_var) return p.addNode(.{ + .keyword_defer => if (is_block_level) return p.addNode(.{ .tag = .@"defer", .main_token = p.nextToken(), .data = .{ .node = try p.expectBlockExprStatement() }, }), - .keyword_errdefer => if (allow_defer_var) return p.addNode(.{ + .keyword_errdefer => if (is_block_level) return p.addNode(.{ .tag = .@"errdefer", .main_token = p.nextToken(), .data = .{ .opt_token_and_node = .{ @@ -979,7 +997,7 @@ fn expectStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index { if (try p.parseLabeledStatement()) |labeled_statement| return labeled_statement; - if (allow_defer_var) { + if (is_block_level) { return p.expectVarDeclExprStatement(null); } else { const assign = try p.expectAssignExpr(); @@ -1007,8 +1025,10 @@ fn expectComptimeStatement(p: *Parse, comptime_token: TokenIndex) !Node.Index { } /// VarDeclExprStatement -/// <- VarDeclProto (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON -/// / Expr (AssignOp Expr / (COMMA (VarDeclProto / Expr))+ EQUAL Expr)? SEMICOLON +/// <- Expr +/// / VarAssignStatement +/// +/// VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index { const scratch_top = p.scratch.items.len; defer p.scratch.shrinkRetainingCapacity(scratch_top); @@ -1140,7 +1160,7 @@ fn expectStatementRecoverable(p: *Parse) Error!?Node.Index { /// IfStatement /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? -/// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) +/// / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) fn expectIfStatement(p: *Parse) !Node.Index { const if_token = p.assertToken(.keyword_if); _ = try p.expectToken(.l_paren); @@ -1235,8 +1255,8 @@ fn parseLoopStatement(p: *Parse) !?Node.Index { } /// ForStatement -/// <- ForPrefix BlockExpr ( KEYWORD_else Statement )? -/// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) +/// <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else ) +/// / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement ) fn parseForStatement(p: *Parse) !?Node.Index { const for_token = p.eatToken(.keyword_for) orelse return null; @@ -1293,7 +1313,7 @@ fn parseForStatement(p: *Parse) !?Node.Index { /// /// WhileStatement /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? -/// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) +/// / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) fn parseWhileStatement(p: *Parse) !?Node.Index { const while_token = p.eatToken(.keyword_while) orelse return null; _ = try p.expectToken(.l_paren); @@ -1383,7 +1403,7 @@ fn parseWhileStatement(p: *Parse) !?Node.Index { /// BlockExprStatement /// <- BlockExpr -/// / AssignExpr SEMICOLON +/// / !BlockExpr AssignExpr SEMICOLON fn parseBlockExprStatement(p: *Parse) !?Node.Index { const block_expr = try p.parseBlockExpr(); if (block_expr) |expr| return expr; @@ -1685,18 +1705,20 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index { /// PrefixTypeOp /// <- QUESTIONMARK /// / KEYWORD_anyframe MINUSRARROW -/// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* +/// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? +/// / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? /// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* /// / ArrayTypeStart /// /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET /// -/// PtrTypeStart -/// <- ASTERISK -/// / ASTERISK2 -/// / LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET +/// SinglePtrTypeStart <- ASTERISK / ASTERISK2 /// -/// ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET +/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET +/// +/// ArrayTypeStart <- LBRACKET Expr !(ASTERISK / ASTERISK2) (COLON Expr)? RBRACKET +/// +/// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN fn parseTypeExpr(p: *Parse) Error!?Node.Index { switch (p.tokenTag(p.tok_i)) { .question_mark => return try p.addNode(.{ @@ -1962,12 +1984,12 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index { /// PrimaryExpr /// <- AsmExpr /// / IfExpr -/// / KEYWORD_break BreakLabel? Expr? -/// / KEYWORD_comptime Expr -/// / KEYWORD_nosuspend Expr -/// / KEYWORD_continue BreakLabel? Expr? -/// / KEYWORD_resume Expr -/// / KEYWORD_return Expr? +/// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) +/// / KEYWORD_comptime Expr !ExprSuffix +/// / KEYWORD_nosuspend Expr !ExprSuffix +/// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) +/// / KEYWORD_resume Expr !ExprSuffix +/// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart) /// / BlockLabel? LoopExpr /// / Block /// / CurlySuffixExpr @@ -2042,10 +2064,6 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index { p.tok_i += 2; return try p.parseWhileExpr(); }, - .l_brace => { - p.tok_i += 2; - return try p.parseBlock(); - }, else => return try p.parseCurlySuffixExpr(), } } else { @@ -2067,12 +2085,12 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index { } } -/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? +/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix fn parseIfExpr(p: *Parse) !?Node.Index { return try p.parseIf(expectExpr); } -/// Block <- LBRACE Statement* RBRACE +/// Block <- LBRACE BlockStatement* RBRACE fn parseBlock(p: *Parse) !?Node.Index { const lbrace = p.eatToken(.l_brace) orelse return null; const scratch_top = p.scratch.items.len; @@ -2177,7 +2195,7 @@ fn forPrefix(p: *Parse) Error!usize { /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? /// -/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? +/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi fn parseWhileExpr(p: *Parse) !?Node.Index { const while_token = p.eatToken(.keyword_while) orelse return null; _ = try p.expectToken(.l_paren); @@ -2409,10 +2427,10 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index { /// / FnProto /// / GroupedExpr /// / LabeledTypeExpr -/// / IDENTIFIER +/// / IDENTIFIER !(COLON LabelableExpr) /// / IfTypeExpr /// / INTEGER -/// / KEYWORD_comptime TypeExpr +/// / KEYWORD_comptime TypeExpr !ExprSuffix /// / KEYWORD_error DOT IDENTIFIER /// / KEYWORD_anyframe /// / KEYWORD_unreachable @@ -2431,7 +2449,7 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index { /// /// GroupedExpr <- LPAREN Expr RPAREN /// -/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? +/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix /// /// LabeledTypeExpr /// <- BlockLabel Block @@ -2711,7 +2729,7 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index { /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? /// -/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? +/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix fn parseWhileTypeExpr(p: *Parse) !?Node.Index { const while_token = p.eatToken(.keyword_while) orelse return null; _ = try p.expectToken(.l_paren); @@ -2876,7 +2894,7 @@ fn expectAsmExpr(p: *Parse) !Node.Index { }); } -/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN +/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN fn parseAsmOutputItem(p: *Parse) !?Node.Index { _ = p.eatToken(.l_bracket) orelse return null; const identifier = try p.expectToken(.identifier); @@ -2902,7 +2920,7 @@ fn parseAsmOutputItem(p: *Parse) !?Node.Index { }); } -/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN +/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN fn parseAsmInputItem(p: *Parse) !?Node.Index { _ = p.eatToken(.l_bracket) orelse return null; const identifier = try p.expectToken(.identifier); @@ -2923,9 +2941,7 @@ fn parseAsmInputItem(p: *Parse) !?Node.Index { /// BreakLabel <- COLON IDENTIFIER fn parseBreakLabel(p: *Parse) Error!OptionalTokenIndex { - _ = p.eatToken(.colon) orelse return .none; - const next_token = try p.expectToken(.identifier); - return .fromToken(next_token); + return if (p.eatTokens(&.{ .colon, .identifier })) |i| .fromToken(i + 1) else .none; } /// BlockLabel <- IDENTIFIER COLON @@ -2950,12 +2966,7 @@ fn expectFieldInit(p: *Parse) !Node.Index { /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN fn parseWhileContinueExpr(p: *Parse) !?Node.Index { - _ = p.eatToken(.colon) orelse { - if (p.tokenTag(p.tok_i) == .l_paren and - p.tokensOnSameLine(p.tok_i - 1, p.tok_i)) - return p.fail(.expected_continue_expr); - return null; - }; + _ = p.eatToken(.colon) orelse return null; _ = try p.expectToken(.l_paren); const node = try p.parseAssignExpr() orelse return p.fail(.expected_expr_or_assignment); _ = try p.expectToken(.r_paren); @@ -2993,9 +3004,7 @@ fn parseAddrSpace(p: *Parse) !?Node.Index { /// such as in the case of anytype and `...`. Caller must look for rparen to find /// out when there are no more param decls left. /// -/// ParamDecl -/// <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType -/// / DOT3 +/// ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime / !KEYWORD_comptime) (IDENTIFIER COLON / !(IDENTIFIER_COLON)) ParamType /// /// ParamType /// <- KEYWORD_anytype @@ -3482,7 +3491,7 @@ fn parseSwitchProngList(p: *Parse) !Node.SubRange { return p.listToSpan(p.scratch.items[scratch_top..]); } -/// ParamDeclList <- (ParamDecl COMMA)* ParamDecl? +/// ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)? fn parseParamDeclList(p: *Parse) !SmallSpan { _ = try p.expectToken(.l_paren); const scratch_top = p.scratch.items.len; @@ -3604,9 +3613,9 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N }); } -/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? +/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix /// -/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)? +/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index { const for_token = p.eatToken(.keyword_for) orelse return null; diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index b98207f904d5684ad900258cc38416a5fef6adb4..3fa306445957ca95787fdc56403ab2153f2bc45c 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -5472,17 +5472,11 @@ test "zig fmt: while continue expr" { \\ while (i > 0) \\ (i * 2); \\} + \\T: (while (true) ({ + \\ break usize; + \\})), \\ ); - try testError( - \\test { - \\ while (i > 0) (i -= 1) { - \\ print("test123", .{}); - \\ } - \\} - , &[_]Error{ - .expected_continue_expr, - }); } test "zig fmt: canonicalize symbols (simple)" { @@ -6838,6 +6832,33 @@ test "zig fmt: error set with extra newline before comma" { ); } +test "zig fmt: extern container in tuple" { + try testCanonical( + \\const T = struct { + \\ extern struct {}, + \\ extern union {}, + \\ extern enum {}, + \\}; + \\ + ); +} + +test "zig fmt: break followed by colon" { + try testCanonical( + \\const a = [if (cond) len else break:0]u8; + \\ + ); +} + +test "zig fmt: array init of labeled block" { + try testCanonical( + \\const a = blk: { + \\ break :blk T; + \\}{ .a = false }; + \\ + ); +} + test "recovery: top level" { try testError( \\test "" {inline} diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index c296b6f5330273b3b2c4ed62e67a4451aa72734a..cd74a66ce50037e05ea569e2469cb8822799d743 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -313,7 +313,8 @@ pub const Token = struct { return tag.lexeme() orelse switch (tag) { .invalid => "invalid token", .identifier => "an identifier", - .string_literal, .multiline_string_literal_line => "a string literal", + .string_literal => "a string literal", + .multiline_string_literal_line => "a multiline string literal", .char_literal => "a character literal", .eof => "EOF", .builtin => "a builtin function",