authorgravatar for manlio.perillo@gmail.comManlio Perillo <manlio.perillo@gmail.com> 2022-12-29 07:22:35+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-30 17:11:59+02:00
logf8f1c6ac06636d816e5dff205d6713a337df387d
tree567433e6e3321862260db5b610c33f87788b1f80
parent4b5fc5239c37fa3f49965188256a781c7b1277a3

parser: ensure the documented grammar matches grammar.y

Move the parsing of Root from the parse function to the Parser.parseRoot method. Add an empty line between each rule, for consistency with grammar.y. Ensure that normal doc-comments are always on the top, for consistency. Add extract-grammar.zig to the tools directory; it is used to extract the PEG grammar from parse.zig, so that it can be compared with grammar.y.

2 files changed, 174 insertions(+), 26 deletions(-)

lib/std/zig/parse.zig+74-26
...@@ -50,22 +50,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8) Allocator.Error!Ast {...@@ -50,22 +50,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8) Allocator.Error!Ast {
50 const estimated_node_count = (tokens.len + 2) / 2;50 const estimated_node_count = (tokens.len + 2) / 2;
51 try parser.nodes.ensureTotalCapacity(gpa, estimated_node_count);51 try parser.nodes.ensureTotalCapacity(gpa, estimated_node_count);
5252
53 // Root node must be index 0.53 try parser.parseRoot();
54 // Root <- skip ContainerMembers eof
55 parser.nodes.appendAssumeCapacity(.{
56 .tag = .root,
57 .main_token = 0,
58 .data = undefined,
59 });
60 const root_members = try parser.parseContainerMembers();
61 const root_decls = try root_members.toSpan(&parser);
62 if (parser.token_tags[parser.tok_i] != .eof) {
63 try parser.warnExpected(.eof);
64 }
65 parser.nodes.items(.data)[0] = .{
66 .lhs = root_decls.start,
67 .rhs = root_decls.end,
68 };
6954
70 // TODO experiment with compacting the MultiArrayList slices here55 // TODO experiment with compacting the MultiArrayList slices here
71 return Ast{56 return Ast{
...@@ -237,12 +222,33 @@ const Parser = struct {...@@ -237,12 +222,33 @@ const Parser = struct {
237 return error.ParseError;222 return error.ParseError;
238 }223 }
239224
225 /// Root <- skip container_doc_comment? ContainerMembers eof
226 fn parseRoot(p: *Parser) !void {
227 // Root node must be index 0.
228 p.nodes.appendAssumeCapacity(.{
229 .tag = .root,
230 .main_token = 0,
231 .data = undefined,
232 });
233 const root_members = try p.parseContainerMembers();
234 const root_decls = try root_members.toSpan(p);
235 if (p.token_tags[p.tok_i] != .eof) {
236 try p.warnExpected(.eof);
237 }
238 p.nodes.items(.data)[0] = .{
239 .lhs = root_decls.start,
240 .rhs = root_decls.end,
241 };
242 }
243
240 /// ContainerMembers <- ContainerDeclarations (ContainerField COMMA)* (ContainerField / ContainerDeclarations)244 /// ContainerMembers <- ContainerDeclarations (ContainerField COMMA)* (ContainerField / ContainerDeclarations)
245 ///
241 /// ContainerDeclarations246 /// ContainerDeclarations
242 /// <- TestDecl ContainerDeclarations247 /// <- TestDecl ContainerDeclarations
243 /// / ComptimeDecl ContainerDeclarations248 /// / ComptimeDecl ContainerDeclarations
244 /// / doc_comment? KEYWORD_pub? Decl ContainerDeclarations249 /// / doc_comment? KEYWORD_pub? Decl ContainerDeclarations
245 /// /250 /// /
251 ///
246 /// ComptimeDecl <- KEYWORD_comptime Block252 /// ComptimeDecl <- KEYWORD_comptime Block
247 fn parseContainerMembers(p: *Parser) !Members {253 fn parseContainerMembers(p: *Parser) !Members {
248 const scratch_top = p.scratch.items.len;254 const scratch_top = p.scratch.items.len;
...@@ -887,7 +893,9 @@ const Parser = struct {...@@ -887,7 +893,9 @@ const Parser = struct {
887 }893 }
888 }894 }
889895
890 /// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?896 /// ContainerField
897 /// <- doc_comment? KEYWORD_comptime? IDENTIFIER (COLON TypeExpr)? ByteAlign? (EQUAL Expr)?
898 /// / doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? !KEYWORD_fn TypeExpr ByteAlign? (EQUAL Expr)?
891 fn expectContainerField(p: *Parser) !Node.Index {899 fn expectContainerField(p: *Parser) !Node.Index {
892 var main_token = p.tok_i;900 var main_token = p.tok_i;
893 _ = p.eatToken(.keyword_comptime);901 _ = p.eatToken(.keyword_comptime);
...@@ -1173,6 +1181,7 @@ const Parser = struct {...@@ -1173,6 +1181,7 @@ const Parser = struct {
1173 }1181 }
11741182
1175 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload1183 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
1184 ///
1176 /// ForStatement1185 /// ForStatement
1177 /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?1186 /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?
1178 /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )1187 /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
...@@ -1234,6 +1243,7 @@ const Parser = struct {...@@ -1234,6 +1243,7 @@ const Parser = struct {
1234 }1243 }
12351244
1236 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?1245 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
1246 ///
1237 /// WhileStatement1247 /// WhileStatement
1238 /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?1248 /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
1239 /// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )1249 /// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
...@@ -1368,13 +1378,18 @@ const Parser = struct {...@@ -1368,13 +1378,18 @@ const Parser = struct {
1368 }1378 }
13691379
1370 /// AssignExpr <- Expr (AssignOp Expr)?1380 /// AssignExpr <- Expr (AssignOp Expr)?
1381 ///
1371 /// AssignOp1382 /// AssignOp
1372 /// <- ASTERISKEQUAL1383 /// <- ASTERISKEQUAL
1384 /// / ASTERISKPIPEEQUAL
1373 /// / SLASHEQUAL1385 /// / SLASHEQUAL
1374 /// / PERCENTEQUAL1386 /// / PERCENTEQUAL
1375 /// / PLUSEQUAL1387 /// / PLUSEQUAL
1388 /// / PLUSPIPEEQUAL
1376 /// / MINUSEQUAL1389 /// / MINUSEQUAL
1390 /// / MINUSPIPEEQUAL
1377 /// / LARROW2EQUAL1391 /// / LARROW2EQUAL
1392 /// / LARROW2PIPEEQUAL
1378 /// / RARROW2EQUAL1393 /// / RARROW2EQUAL
1379 /// / AMPERSANDEQUAL1394 /// / AMPERSANDEQUAL
1380 /// / CARETEQUAL1395 /// / CARETEQUAL
...@@ -1553,6 +1568,7 @@ const Parser = struct {...@@ -1553,6 +1568,7 @@ const Parser = struct {
1553 }1568 }
15541569
1555 /// PrefixExpr <- PrefixOp* PrimaryExpr1570 /// PrefixExpr <- PrefixOp* PrimaryExpr
1571 ///
1556 /// PrefixOp1572 /// PrefixOp
1557 /// <- EXCLAMATIONMARK1573 /// <- EXCLAMATIONMARK
1558 /// / MINUS1574 /// / MINUS
...@@ -1591,17 +1607,21 @@ const Parser = struct {...@@ -1591,17 +1607,21 @@ const Parser = struct {
1591 }1607 }
15921608
1593 /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr1609 /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
1610 ///
1594 /// PrefixTypeOp1611 /// PrefixTypeOp
1595 /// <- QUESTIONMARK1612 /// <- QUESTIONMARK
1596 /// / KEYWORD_anyframe MINUSRARROW1613 /// / KEYWORD_anyframe MINUSRARROW
1597 /// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*1614 /// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
1598 /// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*1615 /// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
1599 /// / ArrayTypeStart1616 /// / ArrayTypeStart
1617 ///
1600 /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET1618 /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
1619 ///
1601 /// PtrTypeStart1620 /// PtrTypeStart
1602 /// <- ASTERISK1621 /// <- ASTERISK
1603 /// / ASTERISK21622 /// / ASTERISK2
1604 /// / LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET1623 /// / LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
1624 ///
1605 /// ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET1625 /// ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET
1606 fn parseTypeExpr(p: *Parser) Error!Node.Index {1626 fn parseTypeExpr(p: *Parser) Error!Node.Index {
1607 switch (p.token_tags[p.tok_i]) {1627 switch (p.token_tags[p.tok_i]) {
...@@ -2068,6 +2088,7 @@ const Parser = struct {...@@ -2068,6 +2088,7 @@ const Parser = struct {
2068 }2088 }
20692089
2070 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload2090 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
2091 ///
2071 /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?2092 /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?
2072 fn parseForExpr(p: *Parser) !Node.Index {2093 fn parseForExpr(p: *Parser) !Node.Index {
2073 const for_token = p.eatToken(.keyword_for) orelse return null_node;2094 const for_token = p.eatToken(.keyword_for) orelse return null_node;
...@@ -2103,6 +2124,7 @@ const Parser = struct {...@@ -2103,6 +2124,7 @@ const Parser = struct {
2103 }2124 }
21042125
2105 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?2126 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2127 ///
2106 /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?2128 /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
2107 fn parseWhileExpr(p: *Parser) !Node.Index {2129 fn parseWhileExpr(p: *Parser) !Node.Index {
2108 const while_token = p.eatToken(.keyword_while) orelse return null_node;2130 const while_token = p.eatToken(.keyword_while) orelse return null_node;
...@@ -2154,6 +2176,7 @@ const Parser = struct {...@@ -2154,6 +2176,7 @@ const Parser = struct {
2154 }2176 }
21552177
2156 /// CurlySuffixExpr <- TypeExpr InitList?2178 /// CurlySuffixExpr <- TypeExpr InitList?
2179 ///
2157 /// InitList2180 /// InitList
2158 /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE2181 /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
2159 /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE2182 /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
...@@ -2272,7 +2295,9 @@ const Parser = struct {...@@ -2272,7 +2295,9 @@ const Parser = struct {
2272 /// SuffixExpr2295 /// SuffixExpr
2273 /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments2296 /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
2274 /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*2297 /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
2298 ///
2275 /// FnCallArguments <- LPAREN ExprList RPAREN2299 /// FnCallArguments <- LPAREN ExprList RPAREN
2300 ///
2276 /// ExprList <- (Expr COMMA)* Expr?2301 /// ExprList <- (Expr COMMA)* Expr?
2277 fn parseSuffixExpr(p: *Parser) !Node.Index {2302 fn parseSuffixExpr(p: *Parser) !Node.Index {
2278 if (p.eatToken(.keyword_async)) |_| {2303 if (p.eatToken(.keyword_async)) |_| {
...@@ -2410,18 +2435,26 @@ const Parser = struct {...@@ -2410,18 +2435,26 @@ const Parser = struct {
2410 /// / KEYWORD_unreachable2435 /// / KEYWORD_unreachable
2411 /// / STRINGLITERAL2436 /// / STRINGLITERAL
2412 /// / SwitchExpr2437 /// / SwitchExpr
2438 ///
2413 /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto2439 /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
2414 /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE2440 ///
2441 /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE
2442 ///
2415 /// InitList2443 /// InitList
2416 /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE2444 /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
2417 /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE2445 /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
2418 /// / LBRACE RBRACE2446 /// / LBRACE RBRACE
2447 ///
2419 /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE2448 /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
2449 ///
2420 /// GroupedExpr <- LPAREN Expr RPAREN2450 /// GroupedExpr <- LPAREN Expr RPAREN
2451 ///
2421 /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?2452 /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
2453 ///
2422 /// LabeledTypeExpr2454 /// LabeledTypeExpr
2423 /// <- BlockLabel Block2455 /// <- BlockLabel Block
2424 /// / BlockLabel? LoopTypeExpr2456 /// / BlockLabel? LoopTypeExpr
2457 ///
2425 /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)2458 /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
2426 fn parsePrimaryTypeExpr(p: *Parser) !Node.Index {2459 fn parsePrimaryTypeExpr(p: *Parser) !Node.Index {
2427 switch (p.token_tags[p.tok_i]) {2460 switch (p.token_tags[p.tok_i]) {
...@@ -2751,6 +2784,7 @@ const Parser = struct {...@@ -2751,6 +2784,7 @@ const Parser = struct {
2751 }2784 }
27522785
2753 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload2786 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
2787 ///
2754 /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?2788 /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?
2755 fn parseForTypeExpr(p: *Parser) !Node.Index {2789 fn parseForTypeExpr(p: *Parser) !Node.Index {
2756 const for_token = p.eatToken(.keyword_for) orelse return null_node;2790 const for_token = p.eatToken(.keyword_for) orelse return null_node;
...@@ -2786,6 +2820,7 @@ const Parser = struct {...@@ -2786,6 +2820,7 @@ const Parser = struct {
2786 }2820 }
27872821
2788 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?2822 /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
2823 ///
2789 /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?2824 /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
2790 fn parseWhileTypeExpr(p: *Parser) !Node.Index {2825 fn parseWhileTypeExpr(p: *Parser) !Node.Index {
2791 const while_token = p.eatToken(.keyword_while) orelse return null_node;2826 const while_token = p.eatToken(.keyword_while) orelse return null_node;
...@@ -2861,11 +2896,17 @@ const Parser = struct {...@@ -2861,11 +2896,17 @@ const Parser = struct {
2861 }2896 }
28622897
2863 /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN2898 /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
2899 ///
2864 /// AsmOutput <- COLON AsmOutputList AsmInput?2900 /// AsmOutput <- COLON AsmOutputList AsmInput?
2901 ///
2865 /// AsmInput <- COLON AsmInputList AsmClobbers?2902 /// AsmInput <- COLON AsmInputList AsmClobbers?
2903 ///
2866 /// AsmClobbers <- COLON StringList2904 /// AsmClobbers <- COLON StringList
2905 ///
2867 /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?2906 /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
2907 ///
2868 /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?2908 /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2909 ///
2869 /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?2910 /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2870 fn expectAsmExpr(p: *Parser) !Node.Index {2911 fn expectAsmExpr(p: *Parser) !Node.Index {
2871 const asm_token = p.assertToken(.keyword_asm);2912 const asm_token = p.assertToken(.keyword_asm);
...@@ -3069,15 +3110,17 @@ const Parser = struct {...@@ -3069,15 +3110,17 @@ const Parser = struct {
3069 return expr_node;3110 return expr_node;
3070 }3111 }
30713112
3072 /// ParamDecl
3073 /// <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
3074 /// / DOT3
3075 /// ParamType
3076 /// <- Keyword_anytype
3077 /// / TypeExpr
3078 /// This function can return null nodes and then still return nodes afterwards,3113 /// This function can return null nodes and then still return nodes afterwards,
3079 /// such as in the case of anytype and `...`. Caller must look for rparen to find3114 /// such as in the case of anytype and `...`. Caller must look for rparen to find
3080 /// out when there are no more param decls left.3115 /// out when there are no more param decls left.
3116 ///
3117 /// ParamDecl
3118 /// <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
3119 /// / DOT3
3120 ///
3121 /// ParamType
3122 /// <- KEYWORD_anytype
3123 /// / TypeExpr
3081 fn expectParamDecl(p: *Parser) !Node.Index {3124 fn expectParamDecl(p: *Parser) !Node.Index {
3082 _ = try p.eatDocComments();3125 _ = try p.eatDocComments();
3083 switch (p.token_tags[p.tok_i]) {3126 switch (p.token_tags[p.tok_i]) {
...@@ -3119,8 +3162,9 @@ const Parser = struct {...@@ -3119,8 +3162,9 @@ const Parser = struct {
3119 return identifier;3162 return identifier;
3120 }3163 }
31213164
3122 /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
3123 /// Returns the first identifier token, if any.3165 /// Returns the first identifier token, if any.
3166 ///
3167 /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
3124 fn parsePtrIndexPayload(p: *Parser) !TokenIndex {3168 fn parsePtrIndexPayload(p: *Parser) !TokenIndex {
3125 _ = p.eatToken(.pipe) orelse return @as(TokenIndex, 0);3169 _ = p.eatToken(.pipe) orelse return @as(TokenIndex, 0);
3126 _ = p.eatToken(.asterisk);3170 _ = p.eatToken(.asterisk);
...@@ -3133,6 +3177,7 @@ const Parser = struct {...@@ -3133,6 +3177,7 @@ const Parser = struct {
3133 }3177 }
31343178
3135 /// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr3179 /// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr
3180 ///
3136 /// SwitchCase3181 /// SwitchCase
3137 /// <- SwitchItem (COMMA SwitchItem)* COMMA?3182 /// <- SwitchItem (COMMA SwitchItem)* COMMA?
3138 /// / KEYWORD_else3183 /// / KEYWORD_else
...@@ -3385,6 +3430,7 @@ const Parser = struct {...@@ -3385,6 +3430,7 @@ const Parser = struct {
3385 }3430 }
33863431
3387 /// Caller must have already verified the first token.3432 /// Caller must have already verified the first token.
3433 ///
3388 /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE3434 /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE
3389 ///3435 ///
3390 /// ContainerDeclType3436 /// ContainerDeclType
...@@ -3556,6 +3602,7 @@ const Parser = struct {...@@ -3556,6 +3602,7 @@ const Parser = struct {
3556 }3602 }
35573603
3558 /// Holds temporary data until we are ready to construct the full ContainerDecl AST node.3604 /// Holds temporary data until we are ready to construct the full ContainerDecl AST node.
3605 ///
3559 /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN3606 /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
3560 fn parseByteAlign(p: *Parser) !Node.Index {3607 fn parseByteAlign(p: *Parser) !Node.Index {
3561 _ = p.eatToken(.keyword_align) orelse return null_node;3608 _ = p.eatToken(.keyword_align) orelse return null_node;
...@@ -3625,6 +3672,7 @@ const Parser = struct {...@@ -3625,6 +3672,7 @@ const Parser = struct {
3625 }3672 }
36263673
3627 /// FnCallArguments <- LPAREN ExprList RPAREN3674 /// FnCallArguments <- LPAREN ExprList RPAREN
3675 ///
3628 /// ExprList <- (Expr COMMA)* Expr?3676 /// ExprList <- (Expr COMMA)* Expr?
3629 fn parseBuiltinCall(p: *Parser) !Node.Index {3677 fn parseBuiltinCall(p: *Parser) !Node.Index {
3630 const builtin_token = p.assertToken(.builtin);3678 const builtin_token = p.assertToken(.builtin);
...@@ -3698,7 +3746,7 @@ const Parser = struct {...@@ -3698,7 +3746,7 @@ const Parser = struct {
3698 }3746 }
3699 }3747 }
37003748
3701 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?3749 /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
3702 fn parseIf(p: *Parser, comptime bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {3750 fn parseIf(p: *Parser, comptime bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {
3703 const if_token = p.eatToken(.keyword_if) orelse return null_node;3751 const if_token = p.eatToken(.keyword_if) orelse return null_node;
3704 _ = try p.expectToken(.l_paren);3752 _ = try p.expectToken(.l_paren);
tools/extract-grammar.zig created+100
...@@ -0,0 +1,100 @@
1//! Extract the "de facto" Zig Grammar from the parser in lib/std/zig/parse.zig.
2//!
3//! The generated file must be edited by hand, in order to remove normal doc-comments.
4
5const std = @import("std");
6const fs = std.fs;
7const heap = std.heap;
8const io = std.io;
9const mem = std.mem;
10const process = std.process;
11const zig = std.zig;
12
13const Buffer = struct {
14 const buf_size = 4096;
15
16 buf: [buf_size]u8 = undefined,
17 pos: usize = 0,
18
19 pub fn append(self: *Buffer, src: []const u8) !void {
20 if (self.pos + src.len > buf_size) {
21 return error.BufferOverflow;
22 }
23
24 mem.copy(u8, self.buf[self.pos..buf_size], src);
25 self.pos += src.len;
26 }
27
28 pub fn reset(self: *Buffer) void {
29 self.pos = 0;
30 }
31
32 pub fn slice(self: *Buffer) []const u8 {
33 return self.buf[0..self.pos];
34 }
35};
36
37/// There are many assumptions in the entire codebase that Zig source files can
38/// be byte-indexed with a u32 integer.
39const max_src_size = std.math.maxInt(u32);
40
41var stdout = io.getStdOut().writer();
42
43pub fn main() !void {
44 var arena = heap.ArenaAllocator.init(heap.page_allocator);
45 defer arena.deinit(); // NOTE(mperillo): Can be removed.
46
47 const allocator = arena.allocator();
48
49 var args_it = try process.argsWithAllocator(allocator);
50 _ = args_it.skip(); // it is safe to ignore
51
52 const path = args_it.next() orelse return error.SourceFileRequired;
53 const src = try read(path, allocator);
54
55 var tokenizer = zig.Tokenizer.init(src);
56 var buf: Buffer = Buffer{};
57 while (true) {
58 const token = tokenizer.next();
59 switch (token.tag) {
60 .eof => break,
61 .doc_comment => {
62 const line = blk: {
63 // Strip leading whitespace.
64 const len = token.loc.end - token.loc.start;
65 break :blk if (len == 3) src[token.loc.start + 3 .. token.loc.end] else src[token.loc.start + 4 .. token.loc.end];
66 };
67
68 try buf.append(line);
69 try buf.append("\n");
70 },
71 .keyword_fn => {
72 const doc = buf.slice();
73 buf.reset();
74
75 // Check if doc contains a PEG grammar block, so that normal
76 // doc-comments are ignored.
77 if (mem.indexOf(u8, doc, "<-") != null) {
78 // Separate each doc with an empty line. This in turn will
79 // ensure that rules are separate by an empty line.
80 try stdout.print("{s}\n", .{doc});
81 }
82 },
83 else => {},
84 }
85 }
86}
87
88fn read(path: []const u8, allocator: mem.Allocator) ![:0]const u8 {
89 var f = try fs.cwd().openFile(path, .{ .mode = .read_only });
90 defer f.close();
91
92 const st = try f.stat();
93 if (st.size > max_src_size) return error.FileTooBig;
94
95 const src = try allocator.allocSentinel(u8, @intCast(usize, st.size), 0);
96 const n = try f.readAll(src);
97 if (n != st.size) return error.UnexpectedEndOfFile;
98
99 return src;
100}