diff --git a/doc/langref/grammar.peg b/doc/langref/grammar.peg index a92fa2f9ce85bb28212c597ceed62280a50e92cf..819e391680d8ed393cb823e1cbd9781e54ff457b 100644 --- a/doc/langref/grammar.peg +++ b/doc/langref/grammar.peg @@ -39,9 +39,16 @@ Root <- ContainerMembers skip eof # *** Top level *** -ContainerMembers <- container_doc_comment? ContainerDeclaration* (ContainerField COMMA)* (ContainerField / ContainerDeclaration*) +ContainerMembers <- container_doc_comment? ContainerDecl* !ContainerDeclPrefix + (!ContainerDeclPrefix ContainerField COMMA)* + (!ContainerDeclPrefix ContainerField / ContainerDecl*) -ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl +ContainerDecl <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl + +ContainerDeclPrefix + <- KEYWORD_test + / KEYWORD_comptime LBRACE + / doc_comment? KEYWORD_pub? DeclPrefix TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block @@ -52,6 +59,11 @@ Decl / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl +DeclPrefix + <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? KEYWORD_fn + / KEYWORD_extern STRINGLITERALSINGLE? KEYWORD_fn + / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? (KEYWORD_const / KEYWORD_var) + FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? @@ -165,7 +177,7 @@ SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix PrimaryTypeExpr <- BUILTINIDENTIFIER FnCallArguments / CHAR_LITERAL - / ContainerDecl + / ContainerType / DOT IDENTIFIER / DOT InitList / ErrorSetDecl @@ -181,7 +193,7 @@ PrimaryTypeExpr / NUMBERLITERAL / STRINGLITERAL -ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto +ContainerType <- (KEYWORD_extern / KEYWORD_packed)? ContainerTypeAuto ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE @@ -387,10 +399,10 @@ ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET -# ContainerDecl specific -ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE +# ContainerType specific +ContainerTypeAuto <- ContainerTypeKind LBRACE ContainerMembers RBRACE -ContainerDeclType +ContainerTypeKind <- KEYWORD_struct (LPAREN Expr RPAREN)? / KEYWORD_opaque / KEYWORD_enum (LPAREN Expr RPAREN)? diff --git a/lib/std/zig/parser_fuzz.zig b/lib/std/zig/parser_fuzz.zig index cf05f3acbc5eae2bce06e877c749e4c189a619a1..f42099142b7548879d18319fabd7481b7dfa6307 100644 --- a/lib/std/zig/parser_fuzz.zig +++ b/lib/std/zig/parser_fuzz.zig @@ -73,6 +73,11 @@ test "return asterisk" { try checkAgainstOracle("test{return*!0;}"); } +// Found using AFL++ +test "fn container field" { + try checkAgainstOracle("fn()0"); +} + fn checkAgainstOracle(source: [:0]const u8) !void { var fba_buf: [1 << 18]u8 = undefined; var fba: std.heap.FixedBufferAllocator = .init(&fba_buf); diff --git a/lib/std/zig/parser_generated_oracle.zig b/lib/std/zig/parser_generated_oracle.zig index 3ecae3e31c8e8c065202516150a4d4d05462e976..6908f1fbe6daa8c698989e6e3c0a8d236f5ed2f9 100644 --- a/lib/std/zig/parser_generated_oracle.zig +++ b/lib/std/zig/parser_generated_oracle.zig @@ -25,22 +25,37 @@ const Parser = struct { return blk_0: { const pos_0 = p.i; if ((p.parsecontainer_doc_comment() or true) and blk_1: { - while (p.parseContainerDeclaration()) {} + while (p.parseContainerDecl()) {} break :blk_1 true; + } and blk_1: { + const pos_1 = p.i; + const match_1 = p.parseContainerDeclPrefix(); + p.i = pos_1; + break :blk_1 !match_1; } and blk_1: { while (blk_3: { const pos_3 = p.i; - if (p.parseContainerField() and p.parseCOMMA()) break :blk_3 true; + if (blk_4: { + const pos_4 = p.i; + const match_4 = p.parseContainerDeclPrefix(); + p.i = pos_4; + break :blk_4 !match_4; + } and p.parseContainerField() and p.parseCOMMA()) break :blk_3 true; p.i = pos_3; break :blk_3 false; }) {} break :blk_1 true; } and blk_2: { const pos_2 = p.i; - if (p.parseContainerField()) break :blk_2 true; + if (blk_3: { + const pos_3 = p.i; + const match_3 = p.parseContainerDeclPrefix(); + p.i = pos_3; + break :blk_3 !match_3; + } and p.parseContainerField()) break :blk_2 true; p.i = pos_2; if (blk_3: { - while (p.parseContainerDeclaration()) {} + while (p.parseContainerDecl()) {} break :blk_3 true; }) break :blk_2 true; p.i = pos_2; @@ -50,7 +65,7 @@ const Parser = struct { break :blk_0 false; }; } - pub fn parseContainerDeclaration(p: *Parser) bool { + pub fn parseContainerDecl(p: *Parser) bool { return blk_0: { const pos_0 = p.i; if (p.parseTestDecl()) break :blk_0 true; @@ -62,6 +77,18 @@ const Parser = struct { break :blk_0 false; }; } + pub fn parseContainerDeclPrefix(p: *Parser) bool { + return blk_0: { + const pos_0 = p.i; + if (p.parseKEYWORD_test()) break :blk_0 true; + p.i = pos_0; + if (p.parseKEYWORD_comptime() and p.parseLBRACE()) break :blk_0 true; + p.i = pos_0; + if ((p.parsedoc_comment() or true) and (p.parseKEYWORD_pub() or true) and p.parseDeclPrefix()) break :blk_0 true; + p.i = pos_0; + break :blk_0 false; + }; + } pub fn parseTestDecl(p: *Parser) bool { return blk_0: { const pos_0 = p.i; @@ -120,6 +147,41 @@ const Parser = struct { break :blk_0 false; }; } + pub fn parseDeclPrefix(p: *Parser) bool { + return blk_0: { + const pos_0 = p.i; + if ((blk_3: { + const pos_3 = p.i; + if (p.parseKEYWORD_export()) break :blk_3 true; + p.i = pos_3; + if (p.parseKEYWORD_inline()) break :blk_3 true; + p.i = pos_3; + if (p.parseKEYWORD_noinline()) break :blk_3 true; + p.i = pos_3; + break :blk_3 false; + } or true) and p.parseKEYWORD_fn()) break :blk_0 true; + p.i = pos_0; + if (p.parseKEYWORD_extern() and (p.parseSTRINGLITERALSINGLE() or true) and p.parseKEYWORD_fn()) break :blk_0 true; + p.i = pos_0; + if ((blk_3: { + const pos_3 = p.i; + if (p.parseKEYWORD_export()) break :blk_3 true; + p.i = pos_3; + if (p.parseKEYWORD_extern() and (p.parseSTRINGLITERALSINGLE() or true)) break :blk_3 true; + p.i = pos_3; + break :blk_3 false; + } or true) and (p.parseKEYWORD_threadlocal() or true) and blk_2: { + const pos_2 = p.i; + if (p.parseKEYWORD_const()) break :blk_2 true; + p.i = pos_2; + if (p.parseKEYWORD_var()) break :blk_2 true; + p.i = pos_2; + break :blk_2 false; + }) break :blk_0 true; + p.i = pos_0; + break :blk_0 false; + }; + } pub fn parseFnProto(p: *Parser) bool { return blk_0: { const pos_0 = p.i; @@ -904,7 +966,7 @@ const Parser = struct { p.i = pos_0; if (p.parseCHAR_LITERAL()) break :blk_0 true; p.i = pos_0; - if (p.parseContainerDecl()) break :blk_0 true; + if (p.parseContainerType()) break :blk_0 true; p.i = pos_0; if (p.parseDOT() and p.parseIDENTIFIER()) break :blk_0 true; p.i = pos_0; @@ -937,7 +999,7 @@ const Parser = struct { break :blk_0 false; }; } - pub fn parseContainerDecl(p: *Parser) bool { + pub fn parseContainerType(p: *Parser) bool { return blk_0: { const pos_0 = p.i; if ((blk_3: { @@ -947,7 +1009,7 @@ const Parser = struct { if (p.parseKEYWORD_packed()) break :blk_3 true; p.i = pos_3; break :blk_3 false; - } or true) and p.parseContainerDeclAuto()) break :blk_0 true; + } or true) and p.parseContainerTypeAuto()) break :blk_0 true; p.i = pos_0; break :blk_0 false; }; @@ -1828,15 +1890,15 @@ const Parser = struct { break :blk_0 false; }; } - pub fn parseContainerDeclAuto(p: *Parser) bool { + pub fn parseContainerTypeAuto(p: *Parser) bool { return blk_0: { const pos_0 = p.i; - if (p.parseContainerDeclType() and p.parseLBRACE() and p.parseContainerMembers() and p.parseRBRACE()) break :blk_0 true; + if (p.parseContainerTypeKind() and p.parseLBRACE() and p.parseContainerMembers() and p.parseRBRACE()) break :blk_0 true; p.i = pos_0; break :blk_0 false; }; } - pub fn parseContainerDeclType(p: *Parser) bool { + pub fn parseContainerTypeKind(p: *Parser) bool { return blk_0: { const pos_0 = p.i; if (p.parseKEYWORD_struct() and (blk_3: {