| author | |
| committer | |
| log | cf8120f58f0db251cf5b144ec644d0da465aec45 |
| tree | 7379e64047704b32a614511ffb1d0ac7e253a6a5 |
| parent | de7fdfecd81e74c115395256179c64cb480cb860 |
| parent | b2c3c33eef468634a2fc47b19bfb2e6f51a1a9b4 |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36094
Reviewed-by: Andrew Kelley <andrew@ziglang.org>26 files changed, 8686 insertions(+), 3767 deletions(-)
build.zig+29-2| ... | @@ -719,6 +719,30 @@ pub fn build(b: *std.Build) !void { | ... | @@ -719,6 +719,30 @@ pub fn build(b: *std.Build) !void { |
| 719 | check_mingw_run.addDirectoryArg(b.path("lib/libc/mingw")); | 719 | check_mingw_run.addDirectoryArg(b.path("lib/libc/mingw")); |
| 720 | check_mingw_step.dependOn(&check_mingw_run.step); | 720 | check_mingw_step.dependOn(&check_mingw_run.step); |
| 721 | 721 | ||
| 722 | { | ||
| 723 | const gen_oracle_exe = b.addExecutable(.{ | ||
| 724 | .name = "gen_parser_oracle", | ||
| 725 | .root_module = b.createModule(.{ | ||
| 726 | .root_source_file = b.path("tools/gen_parser_oracle.zig"), | ||
| 727 | .target = b.graph.host, | ||
| 728 | }), | ||
| 729 | }); | ||
| 730 | |||
| 731 | const gen_oracle_step = b.step("gen-parser-oracle", "Regenerate lib/std/zig/parser_generated_oracle.zig from doc/langref/grammar.peg"); | ||
| 732 | const gen_oracle_run = b.addRunArtifact(gen_oracle_exe); | ||
| 733 | gen_oracle_run.addFileArg(b.path("doc/langref/grammar.peg")); | ||
| 734 | gen_oracle_run.addFileArg(b.path("lib/std/zig/parser_generated_oracle.zig")); | ||
| 735 | gen_oracle_step.dependOn(&gen_oracle_run.step); | ||
| 736 | |||
| 737 | const check_oracle_step = b.step("check-parser-oracle", "Check if doc/langref/grammar.peg was modified without regenerating the oracle"); | ||
| 738 | const check_oracle_run = b.addRunArtifact(gen_oracle_exe); | ||
| 739 | check_oracle_run.addFileArg(b.path("doc/langref/grammar.peg")); | ||
| 740 | check_oracle_run.addFileArg(b.path("lib/std/zig/parser_generated_oracle.zig")); | ||
| 741 | check_oracle_run.addArg("--check"); | ||
| 742 | check_oracle_step.dependOn(&check_oracle_run.step); | ||
| 743 | test_step.dependOn(check_oracle_step); | ||
| 744 | } | ||
| 745 | |||
| 722 | const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases"); | 746 | const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases"); |
| 723 | try tests.addIncrementalTests(b, test_incremental_step, test_filters); | 747 | try tests.addIncrementalTests(b, test_incremental_step, test_filters); |
| 724 | if (!skip_test_incremental) test_step.dependOn(test_incremental_step); | 748 | if (!skip_test_incremental) test_step.dependOn(test_incremental_step); |
| ... | @@ -1569,8 +1593,9 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath { | ... | @@ -1569,8 +1593,9 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath { |
| 1569 | 1593 | ||
| 1570 | var it = dir.iterateAssumeFirstIteration(); | 1594 | var it = dir.iterateAssumeFirstIteration(); |
| 1571 | while (it.next(io) catch @panic("failed to read dir")) |entry| { | 1595 | while (it.next(io) catch @panic("failed to read dir")) |entry| { |
| 1572 | if (std.mem.startsWith(u8, entry.name, ".") or entry.kind != .file) | 1596 | if (entry.kind != .file) continue; |
| 1573 | continue; | 1597 | if (std.mem.startsWith(u8, entry.name, ".")) continue; |
| 1598 | if (!std.mem.endsWith(u8, entry.name, ".zig")) continue; | ||
| 1574 | 1599 | ||
| 1575 | const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)}); | 1600 | const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)}); |
| 1576 | const cmd = b.addRunArtifact(doctest_exe); | 1601 | const cmd = b.addRunArtifact(doctest_exe); |
| ... | @@ -1603,6 +1628,8 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath { | ... | @@ -1603,6 +1628,8 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath { |
| 1603 | const docgen_cmd = b.addRunArtifact(docgen_exe); | 1628 | const docgen_cmd = b.addRunArtifact(docgen_exe); |
| 1604 | docgen_cmd.addArgs(&.{"--code-dir"}); | 1629 | docgen_cmd.addArgs(&.{"--code-dir"}); |
| 1605 | docgen_cmd.addDirectoryArg(wf.getDirectory()); | 1630 | docgen_cmd.addDirectoryArg(wf.getDirectory()); |
| 1631 | docgen_cmd.addArgs(&.{"--grammar"}); | ||
| 1632 | docgen_cmd.addFileArg(b.path("doc/langref/grammar.peg")); | ||
| 1606 | 1633 | ||
| 1607 | docgen_cmd.addFileArg(b.path("doc/langref.html.in")); | 1634 | docgen_cmd.addFileArg(b.path("doc/langref.html.in")); |
| 1608 | return docgen_cmd.addOutputFileArg("langref.html"); | 1635 | return docgen_cmd.addOutputFileArg("langref.html"); |
doc/langref.html.in+1-591| ... | @@ -7798,597 +7798,7 @@ fn readU32Be() u32 {} | ... | @@ -7798,597 +7798,7 @@ fn readU32Be() u32 {} |
| 7798 | 7798 | ||
| 7799 | {#header_open|Appendix#} | 7799 | {#header_open|Appendix#} |
| 7800 | {#header_open|Grammar#} | 7800 | {#header_open|Grammar#} |
| 7801 | {#syntax_block|peg|grammar.peg#} | 7801 | {#grammar#} |
| 7802 | Root <- skip ContainerMembers eof | ||
| 7803 | |||
| 7804 | # *** Top level *** | ||
| 7805 | ContainerMembers <- container_doc_comment? ContainerDeclaration* (ContainerField COMMA)* (ContainerField / ContainerDeclaration*) | ||
| 7806 | |||
| 7807 | ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl | ||
| 7808 | |||
| 7809 | TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block | ||
| 7810 | |||
| 7811 | ComptimeDecl <- KEYWORD_comptime Block | ||
| 7812 | |||
| 7813 | Decl | ||
| 7814 | <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block) | ||
| 7815 | / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON | ||
| 7816 | / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl | ||
| 7817 | |||
| 7818 | FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix | ||
| 7819 | |||
| 7820 | VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? | ||
| 7821 | |||
| 7822 | GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON | ||
| 7823 | |||
| 7824 | ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)? | ||
| 7825 | |||
| 7826 | # *** Block Level *** | ||
| 7827 | BlockStatement | ||
| 7828 | <- Statement | ||
| 7829 | / KEYWORD_defer BlockExprStatement | ||
| 7830 | / KEYWORD_errdefer BlockExprStatement | ||
| 7831 | / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement | ||
| 7832 | |||
| 7833 | Statement | ||
| 7834 | <- ExprStatement | ||
| 7835 | / KEYWORD_suspend BlockExprStatement | ||
| 7836 | / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON | ||
| 7837 | |||
| 7838 | ExprStatement | ||
| 7839 | <- IfStatement | ||
| 7840 | / LabeledStatement | ||
| 7841 | / KEYWORD_nosuspend BlockExprStatement | ||
| 7842 | / KEYWORD_comptime BlockExpr | ||
| 7843 | |||
| 7844 | IfStatement | ||
| 7845 | <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? | ||
| 7846 | / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | ||
| 7847 | |||
| 7848 | LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr) | ||
| 7849 | |||
| 7850 | LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) | ||
| 7851 | |||
| 7852 | ForStatement | ||
| 7853 | <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else ) | ||
| 7854 | / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement ) | ||
| 7855 | |||
| 7856 | WhileStatement | ||
| 7857 | <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? | ||
| 7858 | / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | ||
| 7859 | |||
| 7860 | BlockExprStatement | ||
| 7861 | <- BlockExpr | ||
| 7862 | / !BlockExpr AssignExpr SEMICOLON | ||
| 7863 | |||
| 7864 | BlockExpr <- BlockLabel? Block | ||
| 7865 | |||
| 7866 | # An assignment or a destructure whose LHS are all lvalue expressions or variable declarations. | ||
| 7867 | VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON | ||
| 7868 | |||
| 7869 | # *** Expression Level *** | ||
| 7870 | |||
| 7871 | # An assignment or a destructure whose LHS are all lvalue expressions. | ||
| 7872 | AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)? | ||
| 7873 | |||
| 7874 | SingleAssignExpr <- Expr (AssignOp Expr)? | ||
| 7875 | |||
| 7876 | Expr <- BoolOrExpr | ||
| 7877 | |||
| 7878 | BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)* | ||
| 7879 | |||
| 7880 | BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)* | ||
| 7881 | |||
| 7882 | CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? | ||
| 7883 | |||
| 7884 | BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* | ||
| 7885 | |||
| 7886 | BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* | ||
| 7887 | |||
| 7888 | AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* | ||
| 7889 | |||
| 7890 | MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* | ||
| 7891 | |||
| 7892 | PrefixExpr <- PrefixOp* PrimaryExpr | ||
| 7893 | |||
| 7894 | PrimaryExpr | ||
| 7895 | <- AsmExpr | ||
| 7896 | / IfExpr | ||
| 7897 | / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) | ||
| 7898 | / KEYWORD_comptime Expr !ExprSuffix | ||
| 7899 | / KEYWORD_nosuspend Expr !ExprSuffix | ||
| 7900 | / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) | ||
| 7901 | / KEYWORD_resume Expr !ExprSuffix | ||
| 7902 | / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart) | ||
| 7903 | / BlockLabel? LoopExpr | ||
| 7904 | / Block | ||
| 7905 | / CurlySuffixExpr | ||
| 7906 | |||
| 7907 | IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix | ||
| 7908 | |||
| 7909 | Block <- LBRACE BlockStatement* RBRACE | ||
| 7910 | |||
| 7911 | LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) | ||
| 7912 | |||
| 7913 | ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix | ||
| 7914 | |||
| 7915 | WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix | ||
| 7916 | |||
| 7917 | CurlySuffixExpr <- TypeExpr InitList? | ||
| 7918 | |||
| 7919 | InitList | ||
| 7920 | <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | ||
| 7921 | / LBRACE Expr (COMMA Expr)* COMMA? RBRACE | ||
| 7922 | / LBRACE RBRACE | ||
| 7923 | |||
| 7924 | TypeExpr <- PrefixTypeOp* ErrorUnionExpr | ||
| 7925 | |||
| 7926 | ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? | ||
| 7927 | |||
| 7928 | SuffixExpr | ||
| 7929 | <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* | ||
| 7930 | |||
| 7931 | PrimaryTypeExpr | ||
| 7932 | <- BUILTINIDENTIFIER FnCallArguments | ||
| 7933 | / CHAR_LITERAL | ||
| 7934 | / ContainerDecl | ||
| 7935 | / DOT IDENTIFIER | ||
| 7936 | / DOT InitList | ||
| 7937 | / ErrorSetDecl | ||
| 7938 | / FLOAT | ||
| 7939 | / FnProto | ||
| 7940 | / GroupedExpr | ||
| 7941 | / LabeledTypeExpr | ||
| 7942 | / IDENTIFIER !(COLON LabelableExpr) | ||
| 7943 | / IfTypeExpr | ||
| 7944 | / INTEGER | ||
| 7945 | / KEYWORD_comptime TypeExpr !ExprSuffix | ||
| 7946 | / KEYWORD_error DOT IDENTIFIER | ||
| 7947 | / KEYWORD_anyframe | ||
| 7948 | / KEYWORD_unreachable | ||
| 7949 | / STRINGLITERAL | ||
| 7950 | |||
| 7951 | ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto | ||
| 7952 | |||
| 7953 | ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE | ||
| 7954 | |||
| 7955 | GroupedExpr <- LPAREN Expr RPAREN | ||
| 7956 | |||
| 7957 | IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix | ||
| 7958 | |||
| 7959 | LabeledTypeExpr | ||
| 7960 | <- BlockLabel Block | ||
| 7961 | / BlockLabel? LoopTypeExpr | ||
| 7962 | / BlockLabel? SwitchExpr | ||
| 7963 | |||
| 7964 | LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) | ||
| 7965 | |||
| 7966 | ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix | ||
| 7967 | |||
| 7968 | WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix | ||
| 7969 | |||
| 7970 | SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE | ||
| 7971 | |||
| 7972 | # *** Assembly *** | ||
| 7973 | AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN | ||
| 7974 | |||
| 7975 | AsmOutput <- COLON AsmOutputList AsmInput? | ||
| 7976 | |||
| 7977 | AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN | ||
| 7978 | |||
| 7979 | AsmInput <- COLON AsmInputList AsmClobbers? | ||
| 7980 | |||
| 7981 | AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN | ||
| 7982 | |||
| 7983 | AsmClobbers <- COLON Expr | ||
| 7984 | |||
| 7985 | # *** Helper grammar *** | ||
| 7986 | BreakLabel <- COLON IDENTIFIER | ||
| 7987 | |||
| 7988 | BlockLabel <- IDENTIFIER COLON | ||
| 7989 | |||
| 7990 | FieldInit <- DOT IDENTIFIER EQUAL Expr | ||
| 7991 | |||
| 7992 | WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN | ||
| 7993 | |||
| 7994 | LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN | ||
| 7995 | |||
| 7996 | AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN | ||
| 7997 | |||
| 7998 | # Fn specific | ||
| 7999 | CallConv <- KEYWORD_callconv LPAREN Expr RPAREN | ||
| 8000 | |||
| 8001 | ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime / !KEYWORD_comptime) (IDENTIFIER COLON / !(IDENTIFIER COLON)) ParamType | ||
| 8002 | |||
| 8003 | ParamType | ||
| 8004 | <- KEYWORD_anytype | ||
| 8005 | / TypeExpr | ||
| 8006 | |||
| 8007 | # Control flow prefixes | ||
| 8008 | IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? | ||
| 8009 | |||
| 8010 | WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? | ||
| 8011 | |||
| 8012 | ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload | ||
| 8013 | |||
| 8014 | # Payloads | ||
| 8015 | Payload <- PIPE IDENTIFIER PIPE | ||
| 8016 | |||
| 8017 | PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE | ||
| 8018 | |||
| 8019 | PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE | ||
| 8020 | |||
| 8021 | PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE | ||
| 8022 | |||
| 8023 | # Switch specific | ||
| 8024 | SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr | ||
| 8025 | |||
| 8026 | SwitchCase | ||
| 8027 | <- SwitchItem (COMMA SwitchItem)* COMMA? | ||
| 8028 | / KEYWORD_else | ||
| 8029 | |||
| 8030 | SwitchItem <- Expr (DOT3 Expr)? | ||
| 8031 | |||
| 8032 | # For specific | ||
| 8033 | ForArgumentsList <- ForItem (COMMA ForItem)* COMMA? | ||
| 8034 | |||
| 8035 | ForItem <- Expr (DOT2 Expr?)? | ||
| 8036 | |||
| 8037 | # Operators | ||
| 8038 | AssignOp | ||
| 8039 | <- ASTERISKEQUAL | ||
| 8040 | / ASTERISKPIPEEQUAL | ||
| 8041 | / SLASHEQUAL | ||
| 8042 | / PERCENTEQUAL | ||
| 8043 | / PLUSEQUAL | ||
| 8044 | / PLUSPIPEEQUAL | ||
| 8045 | / MINUSEQUAL | ||
| 8046 | / MINUSPIPEEQUAL | ||
| 8047 | / LARROW2EQUAL | ||
| 8048 | / LARROW2PIPEEQUAL | ||
| 8049 | / RARROW2EQUAL | ||
| 8050 | / AMPERSANDEQUAL | ||
| 8051 | / CARETEQUAL | ||
| 8052 | / PIPEEQUAL | ||
| 8053 | / ASTERISKPERCENTEQUAL | ||
| 8054 | / PLUSPERCENTEQUAL | ||
| 8055 | / MINUSPERCENTEQUAL | ||
| 8056 | / EQUAL | ||
| 8057 | |||
| 8058 | CompareOp | ||
| 8059 | <- EQUALEQUAL | ||
| 8060 | / EXCLAMATIONMARKEQUAL | ||
| 8061 | / LARROW | ||
| 8062 | / RARROW | ||
| 8063 | / LARROWEQUAL | ||
| 8064 | / RARROWEQUAL | ||
| 8065 | |||
| 8066 | BitwiseOp | ||
| 8067 | <- AMPERSAND | ||
| 8068 | / CARET | ||
| 8069 | / PIPE | ||
| 8070 | / KEYWORD_orelse | ||
| 8071 | / KEYWORD_catch Payload? | ||
| 8072 | |||
| 8073 | BitShiftOp | ||
| 8074 | <- LARROW2 | ||
| 8075 | / RARROW2 | ||
| 8076 | / LARROW2PIPE | ||
| 8077 | |||
| 8078 | AdditionOp | ||
| 8079 | <- PLUS | ||
| 8080 | / MINUS | ||
| 8081 | / PLUS2 | ||
| 8082 | / PLUSPERCENT | ||
| 8083 | / MINUSPERCENT | ||
| 8084 | / PLUSPIPE | ||
| 8085 | / MINUSPIPE | ||
| 8086 | |||
| 8087 | MultiplyOp | ||
| 8088 | <- PIPE2 | ||
| 8089 | / ASTERISK | ||
| 8090 | / SLASH | ||
| 8091 | / PERCENT | ||
| 8092 | / ASTERISKPERCENT | ||
| 8093 | / ASTERISKPIPE | ||
| 8094 | |||
| 8095 | PrefixOp | ||
| 8096 | <- EXCLAMATIONMARK | ||
| 8097 | / MINUS | ||
| 8098 | / TILDE | ||
| 8099 | / MINUSPERCENT | ||
| 8100 | / AMPERSAND | ||
| 8101 | / KEYWORD_try | ||
| 8102 | |||
| 8103 | PrefixTypeOp | ||
| 8104 | <- QUESTIONMARK | ||
| 8105 | / KEYWORD_anyframe MINUSRARROW | ||
| 8106 | / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? | ||
| 8107 | / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? | ||
| 8108 | / ArrayTypeStart | ||
| 8109 | |||
| 8110 | SuffixOp | ||
| 8111 | <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET | ||
| 8112 | / DOT IDENTIFIER | ||
| 8113 | / DOTASTERISK | ||
| 8114 | / DOTQUESTIONMARK | ||
| 8115 | |||
| 8116 | FnCallArguments <- LPAREN ExprList RPAREN | ||
| 8117 | |||
| 8118 | ExprSuffix | ||
| 8119 | <- KEYWORD_or | ||
| 8120 | / KEYWORD_and | ||
| 8121 | / CompareOp | ||
| 8122 | / BitwiseOp | ||
| 8123 | / BitShiftOp | ||
| 8124 | / AdditionOp | ||
| 8125 | / MultiplyOp | ||
| 8126 | / EXCLAMATIONMARK | ||
| 8127 | / SuffixOp | ||
| 8128 | / FnCallArguments | ||
| 8129 | |||
| 8130 | LabelableExpr | ||
| 8131 | <- Block | ||
| 8132 | / SwitchExpr | ||
| 8133 | / LoopExpr | ||
| 8134 | |||
| 8135 | # Ptr specific | ||
| 8136 | SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET | ||
| 8137 | |||
| 8138 | SinglePtrTypeStart <- ASTERISK | ||
| 8139 | |||
| 8140 | ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET | ||
| 8141 | |||
| 8142 | ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET | ||
| 8143 | |||
| 8144 | # ContainerDecl specific | ||
| 8145 | ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE | ||
| 8146 | |||
| 8147 | ContainerDeclType | ||
| 8148 | <- KEYWORD_struct (LPAREN Expr RPAREN)? | ||
| 8149 | / KEYWORD_opaque | ||
| 8150 | / KEYWORD_enum (LPAREN Expr RPAREN)? | ||
| 8151 | / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / !KEYWORD_enum Expr) RPAREN)? | ||
| 8152 | |||
| 8153 | # Alignment | ||
| 8154 | ByteAlign <- KEYWORD_align LPAREN Expr RPAREN | ||
| 8155 | |||
| 8156 | BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN | ||
| 8157 | |||
| 8158 | # Lists | ||
| 8159 | IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)? | ||
| 8160 | |||
| 8161 | SwitchProngList <- (SwitchProng COMMA)* SwitchProng? | ||
| 8162 | |||
| 8163 | AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? | ||
| 8164 | |||
| 8165 | AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? | ||
| 8166 | |||
| 8167 | ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)? | ||
| 8168 | |||
| 8169 | ExprList <- (Expr COMMA)* Expr? | ||
| 8170 | |||
| 8171 | # *** Tokens *** | ||
| 8172 | eof <- !. | ||
| 8173 | bin <- [01] | ||
| 8174 | bin_ <- '_'? bin | ||
| 8175 | oct <- [0-7] | ||
| 8176 | oct_ <- '_'? oct | ||
| 8177 | hex <- [0-9a-fA-F] | ||
| 8178 | hex_ <- '_'? hex | ||
| 8179 | dec <- [0-9] | ||
| 8180 | dec_ <- '_'? dec | ||
| 8181 | |||
| 8182 | bin_int <- bin bin_* | ||
| 8183 | oct_int <- oct oct_* | ||
| 8184 | dec_int <- dec dec_* | ||
| 8185 | hex_int <- hex hex_* | ||
| 8186 | |||
| 8187 | ox80_oxBF <- [\200-\277] | ||
| 8188 | oxF4 <- '\364' | ||
| 8189 | ox80_ox8F <- [\200-\217] | ||
| 8190 | oxF1_oxF3 <- [\361-\363] | ||
| 8191 | oxF0 <- '\360' | ||
| 8192 | ox90_0xBF <- [\220-\277] | ||
| 8193 | oxEE_oxEF <- [\356-\357] | ||
| 8194 | oxED <- '\355' | ||
| 8195 | ox80_ox9F <- [\200-\237] | ||
| 8196 | oxE1_oxEC <- [\341-\354] | ||
| 8197 | oxE0 <- '\340' | ||
| 8198 | oxA0_oxBF <- [\240-\277] | ||
| 8199 | oxC2_oxDF <- [\302-\337] | ||
| 8200 | |||
| 8201 | # From https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/ | ||
| 8202 | # First Byte Second Byte Third Byte Fourth Byte | ||
| 8203 | # [0x00,0x7F] | ||
| 8204 | # [0xC2,0xDF] [0x80,0xBF] | ||
| 8205 | # 0xE0 [0xA0,0xBF] [0x80,0xBF] | ||
| 8206 | # [0xE1,0xEC] [0x80,0xBF] [0x80,0xBF] | ||
| 8207 | # 0xED [0x80,0x9F] [0x80,0xBF] | ||
| 8208 | # [0xEE,0xEF] [0x80,0xBF] [0x80,0xBF] | ||
| 8209 | # 0xF0 [0x90,0xBF] [0x80,0xBF] [0x80,0xBF] | ||
| 8210 | # [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF] | ||
| 8211 | # 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF] | ||
| 8212 | |||
| 8213 | multibyte_utf8 <- | ||
| 8214 | oxF4 ox80_ox8F ox80_oxBF ox80_oxBF | ||
| 8215 | / oxF1_oxF3 ox80_oxBF ox80_oxBF ox80_oxBF | ||
| 8216 | / oxF0 ox90_0xBF ox80_oxBF ox80_oxBF | ||
| 8217 | / oxEE_oxEF ox80_oxBF ox80_oxBF | ||
| 8218 | / oxED ox80_ox9F ox80_oxBF | ||
| 8219 | / oxE1_oxEC ox80_oxBF ox80_oxBF | ||
| 8220 | / oxE0 oxA0_oxBF ox80_oxBF | ||
| 8221 | / oxC2_oxDF ox80_oxBF | ||
| 8222 | |||
| 8223 | non_control_ascii <- [\040-\176] | ||
| 8224 | non_control_utf8 <- [\040-\377] | ||
| 8225 | |||
| 8226 | char_escape | ||
| 8227 | <- "\\x" hex hex | ||
| 8228 | / "\\u{" hex+ "}" | ||
| 8229 | / "\\" [nr\\t'"] | ||
| 8230 | char_char | ||
| 8231 | <- multibyte_utf8 | ||
| 8232 | / char_escape | ||
| 8233 | / ![\\'\n] non_control_ascii | ||
| 8234 | |||
| 8235 | string_char | ||
| 8236 | <- multibyte_utf8 | ||
| 8237 | / char_escape | ||
| 8238 | / ![\\"\n] non_control_ascii | ||
| 8239 | |||
| 8240 | container_doc_comment <- ('//!' non_control_utf8* [ \n]* skip)+ | ||
| 8241 | doc_comment <- ('///' non_control_utf8* [ \n]* skip)+ | ||
| 8242 | line_comment <- '//' ![!/] non_control_utf8* / '////' non_control_utf8* | ||
| 8243 | line_string <- '\\\\' non_control_utf8* [ \n]* | ||
| 8244 | skip <- ([ \n] / line_comment)* | ||
| 8245 | |||
| 8246 | CHAR_LITERAL <- ['] char_char ['] skip | ||
| 8247 | FLOAT | ||
| 8248 | <- '0x' hex_int '.' hex_int ([pP] [-+]? dec_int)? skip | ||
| 8249 | / dec_int '.' dec_int ([eE] [-+]? dec_int)? skip | ||
| 8250 | / '0x' hex_int [pP] [-+]? dec_int skip | ||
| 8251 | / dec_int [eE] [-+]? dec_int skip | ||
| 8252 | INTEGER | ||
| 8253 | <- '0b' bin_int skip | ||
| 8254 | / '0o' oct_int skip | ||
| 8255 | / '0x' hex_int skip | ||
| 8256 | / dec_int skip | ||
| 8257 | STRINGLITERALSINGLE <- ["] string_char* ["] skip | ||
| 8258 | STRINGLITERAL | ||
| 8259 | <- STRINGLITERALSINGLE | ||
| 8260 | / (line_string skip)+ | ||
| 8261 | IDENTIFIER | ||
| 8262 | <- !keyword [A-Za-z_] [A-Za-z0-9_]* skip | ||
| 8263 | / '@' STRINGLITERALSINGLE | ||
| 8264 | BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip | ||
| 8265 | |||
| 8266 | |||
| 8267 | AMPERSAND <- '&' ![=] skip | ||
| 8268 | AMPERSANDEQUAL <- '&=' skip | ||
| 8269 | ASTERISK <- '*' ![%=|] skip | ||
| 8270 | ASTERISKEQUAL <- '*=' skip | ||
| 8271 | ASTERISKPERCENT <- '*%' ![=] skip | ||
| 8272 | ASTERISKPERCENTEQUAL <- '*%=' skip | ||
| 8273 | ASTERISKPIPE <- '*|' ![=] skip | ||
| 8274 | ASTERISKPIPEEQUAL <- '*|=' skip | ||
| 8275 | CARET <- '^' ![=] skip | ||
| 8276 | CARETEQUAL <- '^=' skip | ||
| 8277 | COLON <- ':' skip | ||
| 8278 | COMMA <- ',' skip | ||
| 8279 | DOT <- '.' ![*.?] skip | ||
| 8280 | DOT2 <- '..' ![.] skip | ||
| 8281 | DOT3 <- '...' skip | ||
| 8282 | DOTASTERISK <- '.*' skip | ||
| 8283 | DOTQUESTIONMARK <- '.?' skip | ||
| 8284 | EQUAL <- '=' ![>=] skip | ||
| 8285 | EQUALEQUAL <- '==' skip | ||
| 8286 | EQUALRARROW <- '=>' skip | ||
| 8287 | EXCLAMATIONMARK <- '!' ![=] skip | ||
| 8288 | EXCLAMATIONMARKEQUAL <- '!=' skip | ||
| 8289 | LARROW <- '<' ![<=] skip | ||
| 8290 | LARROW2 <- '<<' ![=|] skip | ||
| 8291 | LARROW2EQUAL <- '<<=' skip | ||
| 8292 | LARROW2PIPE <- '<<|' ![=] skip | ||
| 8293 | LARROW2PIPEEQUAL <- '<<|=' skip | ||
| 8294 | LARROWEQUAL <- '<=' skip | ||
| 8295 | LBRACE <- '{' skip | ||
| 8296 | LBRACKET <- '[' skip | ||
| 8297 | LPAREN <- '(' skip | ||
| 8298 | MINUS <- '-' ![%=>|] skip | ||
| 8299 | MINUSEQUAL <- '-=' skip | ||
| 8300 | MINUSPERCENT <- '-%' ![=] skip | ||
| 8301 | MINUSPERCENTEQUAL <- '-%=' skip | ||
| 8302 | MINUSPIPE <- '-|' ![=] skip | ||
| 8303 | MINUSPIPEEQUAL <- '-|=' skip | ||
| 8304 | MINUSRARROW <- '->' skip | ||
| 8305 | PERCENT <- '%' ![=] skip | ||
| 8306 | PERCENTEQUAL <- '%=' skip | ||
| 8307 | PIPE <- '|' ![|=] skip | ||
| 8308 | PIPE2 <- '||' skip | ||
| 8309 | PIPEEQUAL <- '|=' skip | ||
| 8310 | PLUS <- '+' ![%+=|] skip | ||
| 8311 | PLUS2 <- '++' skip | ||
| 8312 | PLUSEQUAL <- '+=' skip | ||
| 8313 | PLUSPERCENT <- '+%' ![=] skip | ||
| 8314 | PLUSPERCENTEQUAL <- '+%=' skip | ||
| 8315 | PLUSPIPE <- '+|' ![=] skip | ||
| 8316 | PLUSPIPEEQUAL <- '+|=' skip | ||
| 8317 | LETTERC <- 'c' skip | ||
| 8318 | QUESTIONMARK <- '?' skip | ||
| 8319 | RARROW <- '>' ![>=] skip | ||
| 8320 | RARROW2 <- '>>' ![=] skip | ||
| 8321 | RARROW2EQUAL <- '>>=' skip | ||
| 8322 | RARROWEQUAL <- '>=' skip | ||
| 8323 | RBRACE <- '}' skip | ||
| 8324 | RBRACKET <- ']' skip | ||
| 8325 | RPAREN <- ')' skip | ||
| 8326 | SEMICOLON <- ';' skip | ||
| 8327 | SLASH <- '/' ![=] skip | ||
| 8328 | SLASHEQUAL <- '/=' skip | ||
| 8329 | TILDE <- '~' skip | ||
| 8330 | |||
| 8331 | end_of_word <- ![a-zA-Z0-9_] skip | ||
| 8332 | KEYWORD_addrspace <- 'addrspace' end_of_word | ||
| 8333 | KEYWORD_align <- 'align' end_of_word | ||
| 8334 | KEYWORD_allowzero <- 'allowzero' end_of_word | ||
| 8335 | KEYWORD_and <- 'and' end_of_word | ||
| 8336 | KEYWORD_anyframe <- 'anyframe' end_of_word | ||
| 8337 | KEYWORD_anytype <- 'anytype' end_of_word | ||
| 8338 | KEYWORD_asm <- 'asm' end_of_word | ||
| 8339 | KEYWORD_break <- 'break' end_of_word | ||
| 8340 | KEYWORD_callconv <- 'callconv' end_of_word | ||
| 8341 | KEYWORD_catch <- 'catch' end_of_word | ||
| 8342 | KEYWORD_comptime <- 'comptime' end_of_word | ||
| 8343 | KEYWORD_const <- 'const' end_of_word | ||
| 8344 | KEYWORD_continue <- 'continue' end_of_word | ||
| 8345 | KEYWORD_defer <- 'defer' end_of_word | ||
| 8346 | KEYWORD_else <- 'else' end_of_word | ||
| 8347 | KEYWORD_enum <- 'enum' end_of_word | ||
| 8348 | KEYWORD_errdefer <- 'errdefer' end_of_word | ||
| 8349 | KEYWORD_error <- 'error' end_of_word | ||
| 8350 | KEYWORD_export <- 'export' end_of_word | ||
| 8351 | KEYWORD_extern <- 'extern' end_of_word | ||
| 8352 | KEYWORD_fn <- 'fn' end_of_word | ||
| 8353 | KEYWORD_for <- 'for' end_of_word | ||
| 8354 | KEYWORD_if <- 'if' end_of_word | ||
| 8355 | KEYWORD_inline <- 'inline' end_of_word | ||
| 8356 | KEYWORD_noalias <- 'noalias' end_of_word | ||
| 8357 | KEYWORD_nosuspend <- 'nosuspend' end_of_word | ||
| 8358 | KEYWORD_noinline <- 'noinline' end_of_word | ||
| 8359 | KEYWORD_opaque <- 'opaque' end_of_word | ||
| 8360 | KEYWORD_or <- 'or' end_of_word | ||
| 8361 | KEYWORD_orelse <- 'orelse' end_of_word | ||
| 8362 | KEYWORD_packed <- 'packed' end_of_word | ||
| 8363 | KEYWORD_pub <- 'pub' end_of_word | ||
| 8364 | KEYWORD_resume <- 'resume' end_of_word | ||
| 8365 | KEYWORD_return <- 'return' end_of_word | ||
| 8366 | KEYWORD_linksection <- 'linksection' end_of_word | ||
| 8367 | KEYWORD_struct <- 'struct' end_of_word | ||
| 8368 | KEYWORD_suspend <- 'suspend' end_of_word | ||
| 8369 | KEYWORD_switch <- 'switch' end_of_word | ||
| 8370 | KEYWORD_test <- 'test' end_of_word | ||
| 8371 | KEYWORD_threadlocal <- 'threadlocal' end_of_word | ||
| 8372 | KEYWORD_try <- 'try' end_of_word | ||
| 8373 | KEYWORD_union <- 'union' end_of_word | ||
| 8374 | KEYWORD_unreachable <- 'unreachable' end_of_word | ||
| 8375 | KEYWORD_var <- 'var' end_of_word | ||
| 8376 | KEYWORD_volatile <- 'volatile' end_of_word | ||
| 8377 | KEYWORD_while <- 'while' end_of_word | ||
| 8378 | |||
| 8379 | keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and | ||
| 8380 | / KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm | ||
| 8381 | / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch | ||
| 8382 | / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer | ||
| 8383 | / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export | ||
| 8384 | / KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if | ||
| 8385 | / KEYWORD_inline / KEYWORD_noalias / KEYWORD_nosuspend / KEYWORD_noinline | ||
| 8386 | / KEYWORD_opaque / KEYWORD_or / KEYWORD_orelse / KEYWORD_packed | ||
| 8387 | / KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection | ||
| 8388 | / KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch / KEYWORD_test | ||
| 8389 | / KEYWORD_threadlocal / KEYWORD_try / KEYWORD_union / KEYWORD_unreachable | ||
| 8390 | / KEYWORD_var / KEYWORD_volatile / KEYWORD_while | ||
| 8391 | {#end_syntax_block#} | ||
| 8392 | {#header_close#} | 7802 | {#header_close#} |
| 8393 | {#header_open|Zen#} | 7803 | {#header_open|Zen#} |
| 8394 | <ul> | 7804 | <ul> |
doc/langref/grammar.peg created+701| ... | @@ -0,0 +1,701 @@ | ||
| 1 | # This grammar is intended to be LL(k) at the token level. | ||
| 2 | # In other words, whenever the parser is required to make a choice it must be | ||
| 3 | # able to choose "correctly" with constant token lookahead. This means that the | ||
| 4 | # handwritten recursive descent parser for this grammar can be implemented with | ||
| 5 | # worst-case linear run time rather than worst-case exponential runtime. | ||
| 6 | # | ||
| 7 | # To ensure this property is upheld, care must be taken to avoid requiring | ||
| 8 | # unbounded token lookahead in the grammar. To illustrate this, consider the | ||
| 9 | # following examples requiring unbounded lookahead: | ||
| 10 | # | ||
| 11 | # This is rather subtle as it looks fine at first glance: | ||
| 12 | # | ||
| 13 | # SingleAssignExpr <- Expr (AssignOp Expr)? | ||
| 14 | # | ||
| 15 | # Consider the case where the AssignOp token matches but Expr after it does | ||
| 16 | # not match. The parser would attempt to parse the Expr after the AssignOp, | ||
| 17 | # fail, then backtrack and succeed the SingleAssignExpr rule matching only | ||
| 18 | # the first Expr. This is an example of unbounded lookahead. The rule must | ||
| 19 | # be rewritten so that if the AssignOp token is not followed by an Expr the | ||
| 20 | # whole SingleAssignExpr rule fails to match: | ||
| 21 | # | ||
| 22 | # SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp) | ||
| 23 | # | ||
| 24 | # The pattern is similar for e.g. the * operator. The following rule requires | ||
| 25 | # unbounded lookahead: | ||
| 26 | # | ||
| 27 | # BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* | ||
| 28 | # | ||
| 29 | # and can be fixed to require only bounded lookahead by adding a !OrOp: | ||
| 30 | # | ||
| 31 | # BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp | ||
| 32 | # | ||
| 33 | # Note also that the negative lookahead added with the ! operator must always be | ||
| 34 | # for a constant maximum number of tokens. | ||
| 35 | # | ||
| 36 | # See this paper for analysis of how LL(k) grammars relate to PEGs: | ||
| 37 | # https://arxiv.org/abs/1304.3177 | ||
| 38 | |||
| 39 | Root <- ContainerMembers skip eof | ||
| 40 | |||
| 41 | # *** Top level *** | ||
| 42 | ContainerMembers <- container_doc_comment? ContainerDecl* ContainerMembersRest | ||
| 43 | ContainerMembersRest | ||
| 44 | <- !ContainerDeclPrefix ContainerField (COMMA ContainerMembersRest)? | ||
| 45 | / ContainerDecl* | ||
| 46 | |||
| 47 | ContainerDecl <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl | ||
| 48 | |||
| 49 | ContainerDeclPrefix | ||
| 50 | <- KEYWORD_test | ||
| 51 | / KEYWORD_comptime LBRACE | ||
| 52 | / doc_comment? KEYWORD_pub? DeclPrefix | ||
| 53 | |||
| 54 | TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block | ||
| 55 | |||
| 56 | ComptimeDecl <- KEYWORD_comptime Block | ||
| 57 | |||
| 58 | Decl | ||
| 59 | <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block) | ||
| 60 | / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON | ||
| 61 | / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl | ||
| 62 | |||
| 63 | DeclPrefix | ||
| 64 | <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? KEYWORD_fn | ||
| 65 | / KEYWORD_extern STRINGLITERALSINGLE? KEYWORD_fn | ||
| 66 | / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? (KEYWORD_const / KEYWORD_var) | ||
| 67 | |||
| 68 | FnProto <- KEYWORD_fn IDENTIFIER? ParamDeclList ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr | ||
| 69 | |||
| 70 | VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? | ||
| 71 | |||
| 72 | GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON | ||
| 73 | |||
| 74 | ContainerField <- doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)? | ||
| 75 | |||
| 76 | # *** Block Level *** | ||
| 77 | BlockStatement | ||
| 78 | <- Statement | ||
| 79 | / KEYWORD_defer BlockExprStatement | ||
| 80 | / KEYWORD_errdefer BlockExprStatement | ||
| 81 | / !StatementPrefix KEYWORD_comptime? VarAssignStatement | ||
| 82 | |||
| 83 | Statement | ||
| 84 | <- IfStatement | ||
| 85 | / LabeledStatement | ||
| 86 | / KEYWORD_nosuspend BlockExprStatement | ||
| 87 | / KEYWORD_comptime BlockExpr | ||
| 88 | / KEYWORD_suspend BlockExprStatement | ||
| 89 | / !StatementPrefix KEYWORD_comptime? AssignExpr SEMICOLON | ||
| 90 | |||
| 91 | StatementPrefix | ||
| 92 | <- KEYWORD_if | ||
| 93 | / BlockLabel? (LBRACE / KEYWORD_inline? (KEYWORD_for / KEYWORD_while) / KEYWORD_switch) | ||
| 94 | / KEYWORD_nosuspend | ||
| 95 | / KEYWORD_comptime BlockExprPrefix | ||
| 96 | |||
| 97 | IfStatement | ||
| 98 | <- IfPrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else) | ||
| 99 | / IfPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement) | ||
| 100 | |||
| 101 | LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr) | ||
| 102 | |||
| 103 | LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) | ||
| 104 | |||
| 105 | ForStatement | ||
| 106 | <- ForPrefix BlockExpr (KEYWORD_else Statement / !KEYWORD_else) | ||
| 107 | / ForPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Statement) | ||
| 108 | |||
| 109 | WhileStatement | ||
| 110 | <- WhilePrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else) | ||
| 111 | / WhilePrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement) | ||
| 112 | |||
| 113 | BlockExprStatement | ||
| 114 | <- BlockExpr | ||
| 115 | / !BlockExprPrefix AssignExpr SEMICOLON | ||
| 116 | |||
| 117 | BlockExprPrefix <- BlockLabel? LBRACE | ||
| 118 | BlockExpr <- BlockLabel? Block | ||
| 119 | |||
| 120 | # An assignment or a destructure whose LHS are all lvalue expressions or variable declarations. | ||
| 121 | VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON | ||
| 122 | |||
| 123 | # *** Expression Level *** | ||
| 124 | |||
| 125 | # An assignment or a destructure whose LHS are all lvalue expressions. | ||
| 126 | AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA) | ||
| 127 | |||
| 128 | SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp) | ||
| 129 | |||
| 130 | Expr <- BoolOrExpr | ||
| 131 | |||
| 132 | BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp | ||
| 133 | |||
| 134 | BoolAndExpr <- CompareExpr (AndOp CompareExpr)* !AndOp | ||
| 135 | |||
| 136 | CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? !CompareOp | ||
| 137 | |||
| 138 | BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* !BitwiseOp | ||
| 139 | |||
| 140 | BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* !BitShiftOp | ||
| 141 | |||
| 142 | AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* !AdditionOp | ||
| 143 | |||
| 144 | MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* !MultiplyOp | ||
| 145 | |||
| 146 | PrefixExpr <- PrefixOp* !PrefixOp PrimaryExpr | ||
| 147 | |||
| 148 | PrimaryExpr | ||
| 149 | <- AsmExpr | ||
| 150 | / IfExpr | ||
| 151 | / KEYWORD_break BreakLabel? (Expr / !ExprPrefix) | ||
| 152 | / KEYWORD_comptime Expr | ||
| 153 | / KEYWORD_nosuspend Expr | ||
| 154 | / KEYWORD_continue BreakLabel? (Expr / !ExprPrefix) | ||
| 155 | / KEYWORD_resume Expr | ||
| 156 | / KEYWORD_return (Expr / !ExprPrefix) | ||
| 157 | / BlockLabel? LoopExpr | ||
| 158 | / Block | ||
| 159 | / CurlySuffixExpr | ||
| 160 | |||
| 161 | IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else) | ||
| 162 | |||
| 163 | Block <- LBRACE BlockStatement* RBRACE | ||
| 164 | |||
| 165 | LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) | ||
| 166 | |||
| 167 | ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) | ||
| 168 | |||
| 169 | WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? | ||
| 170 | |||
| 171 | CurlySuffixExpr <- TypeExpr (InitList / !LBRACE) | ||
| 172 | |||
| 173 | InitList | ||
| 174 | <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | ||
| 175 | / LBRACE Expr (COMMA Expr)* COMMA? RBRACE | ||
| 176 | / LBRACE RBRACE | ||
| 177 | |||
| 178 | TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr | ||
| 179 | |||
| 180 | ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK) | ||
| 181 | |||
| 182 | SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix | ||
| 183 | |||
| 184 | PrimaryTypeExpr | ||
| 185 | <- BUILTINIDENTIFIER FnCallArguments | ||
| 186 | / CHAR_LITERAL | ||
| 187 | / ContainerType | ||
| 188 | / DOT IDENTIFIER | ||
| 189 | / DOT InitList | ||
| 190 | / ErrorSetDecl | ||
| 191 | / FnProto | ||
| 192 | / GroupedExpr | ||
| 193 | / LabeledTypeExpr | ||
| 194 | / IDENTIFIER | ||
| 195 | / IfTypeExpr | ||
| 196 | / KEYWORD_comptime TypeExpr | ||
| 197 | / KEYWORD_error DOT IDENTIFIER | ||
| 198 | / KEYWORD_anyframe | ||
| 199 | / KEYWORD_unreachable | ||
| 200 | / NUMBERLITERAL | ||
| 201 | / STRINGLITERAL | ||
| 202 | |||
| 203 | ContainerType <- (KEYWORD_extern / KEYWORD_packed)? ContainerTypeAuto | ||
| 204 | |||
| 205 | ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE | ||
| 206 | |||
| 207 | GroupedExpr <- LPAREN Expr RPAREN | ||
| 208 | |||
| 209 | IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) | ||
| 210 | |||
| 211 | LabeledTypeExpr | ||
| 212 | <- BlockLabel Block | ||
| 213 | / BlockLabel? LoopTypeExpr | ||
| 214 | / BlockLabel? SwitchExpr | ||
| 215 | |||
| 216 | LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) | ||
| 217 | |||
| 218 | ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) | ||
| 219 | |||
| 220 | WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) | ||
| 221 | |||
| 222 | SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE | ||
| 223 | |||
| 224 | # *** Assembly *** | ||
| 225 | AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN | ||
| 226 | |||
| 227 | AsmOutput <- COLON AsmOutputList AsmInput? | ||
| 228 | |||
| 229 | AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN | ||
| 230 | |||
| 231 | AsmInput <- COLON AsmInputList AsmClobbers? | ||
| 232 | |||
| 233 | AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN | ||
| 234 | |||
| 235 | AsmClobbers <- COLON Expr | ||
| 236 | |||
| 237 | # *** Helper grammar *** | ||
| 238 | BreakLabel <- COLON IDENTIFIER | ||
| 239 | |||
| 240 | BlockLabel <- IDENTIFIER COLON | ||
| 241 | |||
| 242 | FieldInit <- DOT IDENTIFIER EQUAL Expr | ||
| 243 | |||
| 244 | WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN | ||
| 245 | |||
| 246 | LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN | ||
| 247 | |||
| 248 | AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN | ||
| 249 | |||
| 250 | # Fn specific | ||
| 251 | CallConv <- KEYWORD_callconv LPAREN Expr RPAREN | ||
| 252 | |||
| 253 | ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime?) (IDENTIFIER COLON)? ParamType | ||
| 254 | |||
| 255 | ParamType | ||
| 256 | <- KEYWORD_anytype | ||
| 257 | / TypeExpr | ||
| 258 | |||
| 259 | # Control flow prefixes | ||
| 260 | IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? | ||
| 261 | |||
| 262 | WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? | ||
| 263 | |||
| 264 | ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload | ||
| 265 | |||
| 266 | # Payloads | ||
| 267 | Payload <- PIPE IDENTIFIER PIPE | ||
| 268 | |||
| 269 | PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE | ||
| 270 | |||
| 271 | PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE | ||
| 272 | |||
| 273 | PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE | ||
| 274 | |||
| 275 | # Switch specific | ||
| 276 | SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr | ||
| 277 | |||
| 278 | SwitchCase | ||
| 279 | <- SwitchItem (COMMA SwitchItem)* COMMA? | ||
| 280 | / KEYWORD_else | ||
| 281 | |||
| 282 | SwitchItem <- Expr (DOT3 Expr)? | ||
| 283 | |||
| 284 | # For specific | ||
| 285 | ForArgumentsList <- ForItem (COMMA ForItem)* COMMA? | ||
| 286 | |||
| 287 | ForItem <- Expr (DOT2 (Expr / !ExprPrefix) / !DOT2) | ||
| 288 | |||
| 289 | # Operators | ||
| 290 | AssignOp | ||
| 291 | <- ASTERISKEQUAL | ||
| 292 | / ASTERISKPIPEEQUAL | ||
| 293 | / SLASHEQUAL | ||
| 294 | / PERCENTEQUAL | ||
| 295 | / PLUSEQUAL | ||
| 296 | / PLUSPIPEEQUAL | ||
| 297 | / MINUSEQUAL | ||
| 298 | / MINUSPIPEEQUAL | ||
| 299 | / LARROW2EQUAL | ||
| 300 | / LARROW2PIPEEQUAL | ||
| 301 | / RARROW2EQUAL | ||
| 302 | / AMPERSANDEQUAL | ||
| 303 | / CARETEQUAL | ||
| 304 | / PIPEEQUAL | ||
| 305 | / ASTERISKPERCENTEQUAL | ||
| 306 | / PLUSPERCENTEQUAL | ||
| 307 | / MINUSPERCENTEQUAL | ||
| 308 | / EQUAL | ||
| 309 | |||
| 310 | OrOp <- pre_op_white KEYWORD_or post_op_white | ||
| 311 | / !pre_op_white KEYWORD_or !post_op_white | ||
| 312 | |||
| 313 | AndOp <- pre_op_white KEYWORD_and post_op_white | ||
| 314 | / !pre_op_white KEYWORD_and !post_op_white | ||
| 315 | |||
| 316 | CompareOp <- pre_op_white CompareOpTok post_op_white | ||
| 317 | / !pre_op_white CompareOpTok !post_op_white | ||
| 318 | CompareOpTok | ||
| 319 | <- EQUALEQUAL | ||
| 320 | / EXCLAMATIONMARKEQUAL | ||
| 321 | / LARROW | ||
| 322 | / RARROW | ||
| 323 | / LARROWEQUAL | ||
| 324 | / RARROWEQUAL | ||
| 325 | |||
| 326 | BitwiseOp <- pre_op_white BitwiseOpTok post_op_white | ||
| 327 | / !pre_op_white BitwiseOpTok !post_op_white | ||
| 328 | / pre_op_white KEYWORD_catch post_op_white Payload? | ||
| 329 | / !pre_op_white KEYWORD_catch !post_op_white Payload? | ||
| 330 | BitwiseOpTok | ||
| 331 | <- AMPERSAND ![&] | ||
| 332 | / CARET | ||
| 333 | / PIPE | ||
| 334 | / KEYWORD_orelse | ||
| 335 | |||
| 336 | BitShiftOp <- pre_op_white BitShiftOpTok post_op_white | ||
| 337 | / !pre_op_white BitShiftOpTok !post_op_white | ||
| 338 | BitShiftOpTok | ||
| 339 | <- LARROW2 | ||
| 340 | / RARROW2 | ||
| 341 | / LARROW2PIPE | ||
| 342 | |||
| 343 | AdditionOp <- pre_op_white AdditionOpTok post_op_white | ||
| 344 | / !pre_op_white AdditionOpTok !post_op_white | ||
| 345 | AdditionOpTok | ||
| 346 | <- PLUS | ||
| 347 | / MINUS | ||
| 348 | / PLUS2 | ||
| 349 | / PLUSPERCENT | ||
| 350 | / MINUSPERCENT | ||
| 351 | / PLUSPIPE | ||
| 352 | / MINUSPIPE | ||
| 353 | |||
| 354 | MultiplyOp <- pre_op_white MultiplyOpTok post_op_white | ||
| 355 | / !pre_op_white MultiplyOpTok !post_op_white | ||
| 356 | MultiplyOpTok | ||
| 357 | <- PIPE2 | ||
| 358 | / ASTERISK | ||
| 359 | / SLASH | ||
| 360 | / PERCENT | ||
| 361 | / ASTERISKPERCENT | ||
| 362 | / ASTERISKPIPE | ||
| 363 | |||
| 364 | PrefixOp | ||
| 365 | <- EXCLAMATIONMARK | ||
| 366 | / MINUS | ||
| 367 | / TILDE | ||
| 368 | / MINUSPERCENT | ||
| 369 | / AMPERSAND | ||
| 370 | / KEYWORD_try | ||
| 371 | |||
| 372 | PrefixTypeOp | ||
| 373 | <- QUESTIONMARK | ||
| 374 | / KEYWORD_anyframe MINUSRARROW | ||
| 375 | / (ManyPtrTypeStart / SliceTypeStart) PtrMods | ||
| 376 | / SinglePtrTypeStart SinglePtrMods | ||
| 377 | / ArrayTypeStart | ||
| 378 | |||
| 379 | # Forbid more than one align or addrspace pointer modifier since these | ||
| 380 | # modifiers contain sub-expressions. This allows for a simpler AST data layout. | ||
| 381 | # Allow duplicate single-token modifiers (allowzero/const/volatile) in the grammar | ||
| 382 | # to avoid the combinatorial explosion of grammar rules necessary to forbid duplicates | ||
| 383 | # while permitting arbitrary order. A compile error for duplicates single-token modifiers | ||
| 384 | # is emitted during "AstGen" after parsing is complete. | ||
| 385 | PtrMods | ||
| 386 | <- PtrMod* !KEYWORD_addrspace ByteAlign? PtrMod* AddrSpace? PtrMod* | ||
| 387 | / PtrMod* !KEYWORD_align AddrSpace? PtrMod* ByteAlign? PtrMod* | ||
| 388 | |||
| 389 | SinglePtrMods | ||
| 390 | <- PtrMod* !KEYWORD_addrspace BitAlign? PtrMod* AddrSpace? PtrMod* | ||
| 391 | / PtrMod* !KEYWORD_align AddrSpace? PtrMod* BitAlign? PtrMod* | ||
| 392 | |||
| 393 | PtrMod | ||
| 394 | <- KEYWORD_allowzero | ||
| 395 | / KEYWORD_const | ||
| 396 | / KEYWORD_volatile | ||
| 397 | |||
| 398 | PrefixTypeOpPrefix | ||
| 399 | <- QUESTIONMARK | ||
| 400 | / KEYWORD_anyframe MINUSRARROW | ||
| 401 | / LBRACKET | ||
| 402 | / ASTERISK | ||
| 403 | |||
| 404 | SuffixOp | ||
| 405 | <- LBRACKET Expr (DOT2 (Expr / !ExprPrefix) (COLON Expr)?)? RBRACKET | ||
| 406 | / DOT IDENTIFIER | ||
| 407 | / DOTASTERISK | ||
| 408 | / DOT QUESTIONMARK | ||
| 409 | / FnCallArguments | ||
| 410 | |||
| 411 | SuffixOpPrefix | ||
| 412 | <- LBRACKET | ||
| 413 | / DOT IDENTIFIER | ||
| 414 | / DOTASTERISK | ||
| 415 | / DOT QUESTIONMARK | ||
| 416 | / LPAREN | ||
| 417 | |||
| 418 | FnCallArguments <- LPAREN ExprList RPAREN | ||
| 419 | |||
| 420 | # Ptr specific | ||
| 421 | SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET | ||
| 422 | |||
| 423 | SinglePtrTypeStart <- ASTERISK | ||
| 424 | |||
| 425 | ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET | ||
| 426 | |||
| 427 | ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET | ||
| 428 | |||
| 429 | # ContainerType specific | ||
| 430 | ContainerTypeAuto <- ContainerTypeKind LBRACE ContainerMembers RBRACE | ||
| 431 | |||
| 432 | ContainerTypeKind | ||
| 433 | <- KEYWORD_struct (LPAREN Expr RPAREN)? | ||
| 434 | / KEYWORD_opaque | ||
| 435 | / KEYWORD_enum (LPAREN Expr RPAREN)? | ||
| 436 | / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? | ||
| 437 | |||
| 438 | # Alignment | ||
| 439 | ByteAlign <- KEYWORD_align LPAREN Expr RPAREN | ||
| 440 | |||
| 441 | BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN | ||
| 442 | |||
| 443 | # Lists | ||
| 444 | IdentifierList <- (doc_comment? IDENTIFIER (COMMA IdentifierList)?)? | ||
| 445 | |||
| 446 | SwitchProngList <- (SwitchProng (COMMA SwitchProngList)?)? | ||
| 447 | |||
| 448 | AsmOutputList <- (AsmOutputItem (COMMA AsmOutputList)?)? | ||
| 449 | |||
| 450 | AsmInputList <- (AsmInputItem (COMMA AsmInputList)?)? | ||
| 451 | |||
| 452 | ParamDeclList <- LPAREN ParamDeclListRest | ||
| 453 | ParamDeclListRest | ||
| 454 | <- RPAREN | ||
| 455 | / DOT3 COMMA? RPAREN | ||
| 456 | / ParamDecl (COMMA ParamDeclListRest / RPAREN) | ||
| 457 | |||
| 458 | ExprList <- Expr (COMMA ExprList)? / !ExprPrefix | ||
| 459 | |||
| 460 | ExprPrefix <- ASTERISK | ||
| 461 | |||
| 462 | # *** Tokens *** | ||
| 463 | |||
| 464 | # https://en.wikipedia.org/wiki/Byte_order_mark | ||
| 465 | byte_order_mark <- '\357\273\277' | ||
| 466 | |||
| 467 | # Unfortunately, there is not a standard way to match the start of the file in PEG. | ||
| 468 | # This rule definition is compatible with the original peg(1) tool but is not | ||
| 469 | # portable. It is however trivial to implement an equivalent rule in hand written | ||
| 470 | # parsers and other PEG tooling should have similar mechanisms. | ||
| 471 | sof <- &{ (yy->__pos == 0) } byte_order_mark? | ||
| 472 | eof <- !. | ||
| 473 | |||
| 474 | ox80_oxBF <- [\200-\277] | ||
| 475 | oxF4 <- '\364' | ||
| 476 | ox80_ox8F <- [\200-\217] | ||
| 477 | oxF1_oxF3 <- [\361-\363] | ||
| 478 | oxF0 <- '\360' | ||
| 479 | ox90_0xBF <- [\220-\277] | ||
| 480 | oxEE_oxEF <- [\356-\357] | ||
| 481 | oxED <- '\355' | ||
| 482 | ox80_ox9F <- [\200-\237] | ||
| 483 | oxE1_oxEC <- [\341-\354] | ||
| 484 | oxE0 <- '\340' | ||
| 485 | oxA0_oxBF <- [\240-\277] | ||
| 486 | oxC2_oxDF <- [\302-\337] | ||
| 487 | |||
| 488 | # From https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/ | ||
| 489 | # First Byte Second Byte Third Byte Fourth Byte | ||
| 490 | # [0x00,0x7F] | ||
| 491 | # [0xC2,0xDF] [0x80,0xBF] | ||
| 492 | # 0xE0 [0xA0,0xBF] [0x80,0xBF] | ||
| 493 | # [0xE1,0xEC] [0x80,0xBF] [0x80,0xBF] | ||
| 494 | # 0xED [0x80,0x9F] [0x80,0xBF] | ||
| 495 | # [0xEE,0xEF] [0x80,0xBF] [0x80,0xBF] | ||
| 496 | # 0xF0 [0x90,0xBF] [0x80,0xBF] [0x80,0xBF] | ||
| 497 | # [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF] | ||
| 498 | # 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF] | ||
| 499 | |||
| 500 | multibyte_utf8 <- | ||
| 501 | oxF4 ox80_ox8F ox80_oxBF ox80_oxBF | ||
| 502 | / oxF1_oxF3 ox80_oxBF ox80_oxBF ox80_oxBF | ||
| 503 | / oxF0 ox90_0xBF ox80_oxBF ox80_oxBF | ||
| 504 | / oxEE_oxEF ox80_oxBF ox80_oxBF | ||
| 505 | / oxED ox80_ox9F ox80_oxBF | ||
| 506 | / oxE1_oxEC ox80_oxBF ox80_oxBF | ||
| 507 | / oxE0 oxA0_oxBF ox80_oxBF | ||
| 508 | / oxC2_oxDF ox80_oxBF | ||
| 509 | |||
| 510 | # Exclude \177 which is DEL | ||
| 511 | non_control_ascii <- [\040-\176] | ||
| 512 | non_control_utf8 <- [\040-\176\200-\377] | ||
| 513 | |||
| 514 | # XXX: the Zig tokenizer doesn't yet perform UTF-8 validation | ||
| 515 | # When the tokenizer is fixed, switch back to these definitions | ||
| 516 | # that forbid invalid UTF-8: | ||
| 517 | # | ||
| 518 | # char_char | ||
| 519 | # <- multibyte_utf8 | ||
| 520 | # / "\\\\" | ||
| 521 | # / "\\'" | ||
| 522 | # / !['] non_control_ascii | ||
| 523 | # string_char | ||
| 524 | # <- multibyte_utf8 | ||
| 525 | # / '\\\\' | ||
| 526 | # / '\\"' | ||
| 527 | # / !["] non_control_ascii | ||
| 528 | |||
| 529 | char_char | ||
| 530 | <- "\\\\" | ||
| 531 | / "\\'" | ||
| 532 | / !['] non_control_utf8 | ||
| 533 | |||
| 534 | string_char | ||
| 535 | <- '\\\\' | ||
| 536 | / '\\"' | ||
| 537 | / !["] non_control_utf8 | ||
| 538 | |||
| 539 | |||
| 540 | container_doc_comment <- (skip '//!' non_control_utf8* newline)+ | ||
| 541 | # We forbid same-line doc comments to disambiguate the mapping to e.g. struct | ||
| 542 | # fields for documentation generation tooling. | ||
| 543 | doc_comment <- (sof / skip_require_newline) (skip '///' non_control_utf8* newline)+ | ||
| 544 | line_comment | ||
| 545 | <- '//' ![!/] non_control_utf8* newline | ||
| 546 | / '////' non_control_utf8* newline | ||
| 547 | line_string <- '\\\\' non_control_utf8* newline | ||
| 548 | |||
| 549 | # This uses a positive lookahead rather than consuming input to make e.g. | ||
| 550 | # the newline terminating a multiline string literal or doc comment visible | ||
| 551 | # to the pre_op_white non-terminal. | ||
| 552 | newline <- &("\n" / "\r\n" / eof) | ||
| 553 | skip <- sof? ([ \n\t\r] / line_comment)* | ||
| 554 | skip_require_newline <- [ \t\r]* ([\n] / line_comment) skip | ||
| 555 | pre_op_white <- ([ \n\t\r] / line_comment)+ | ||
| 556 | post_op_white <- [ \n\t\r] skip | ||
| 557 | |||
| 558 | CHAR_LITERAL <- skip ['] char_char* ['] | ||
| 559 | |||
| 560 | digit <- [_0-9A-DF-OQ-Za-df-oq-z] | ||
| 561 | digit_int <- digit / [eEpP] | ||
| 562 | digit_float <- digit / [eEpP] [-+]? | ||
| 563 | NUMBERLITERAL | ||
| 564 | <- skip [0-9] digit_int* '.' digit_float+ | ||
| 565 | / skip [0-9] digit_float* | ||
| 566 | |||
| 567 | |||
| 568 | string <- ["] string_char* ["] | ||
| 569 | STRINGLITERALSINGLE <- skip string | ||
| 570 | STRINGLITERAL | ||
| 571 | <- skip string | ||
| 572 | / (skip line_string)+ | ||
| 573 | IDENTIFIER | ||
| 574 | <- skip !keyword [A-Za-z_] [A-Za-z0-9_]* | ||
| 575 | / skip '@' string | ||
| 576 | BUILTINIDENTIFIER <- skip '@'[A-Za-z_][A-Za-z0-9_]* | ||
| 577 | |||
| 578 | |||
| 579 | AMPERSAND <- skip '&' ![=] | ||
| 580 | AMPERSANDEQUAL <- skip '&=' | ||
| 581 | ASTERISK <- skip '*' ![%=|] | ||
| 582 | ASTERISKEQUAL <- skip '*=' | ||
| 583 | ASTERISKPERCENT <- skip '*%' ![=] | ||
| 584 | ASTERISKPERCENTEQUAL <- skip '*%=' | ||
| 585 | ASTERISKPIPE <- skip '*|' ![=] | ||
| 586 | ASTERISKPIPEEQUAL <- skip '*|=' | ||
| 587 | CARET <- skip '^' ![=] | ||
| 588 | CARETEQUAL <- skip '^=' | ||
| 589 | COLON <- skip ':' | ||
| 590 | COMMA <- skip ',' | ||
| 591 | DOT <- skip '.' ![*.] | ||
| 592 | DOT2 <- skip '..' ![.] | ||
| 593 | DOT3 <- skip '...' | ||
| 594 | DOTASTERISK <- skip '.*' | ||
| 595 | EQUAL <- skip '=' ![>=] | ||
| 596 | EQUALEQUAL <- skip '==' | ||
| 597 | EQUALRARROW <- skip '=>' | ||
| 598 | EXCLAMATIONMARK <- skip '!' ![=] | ||
| 599 | EXCLAMATIONMARKEQUAL <- skip '!=' | ||
| 600 | LARROW <- skip '<' ![<=] | ||
| 601 | LARROW2 <- skip '<<' ![=|] | ||
| 602 | LARROW2EQUAL <- skip '<<=' | ||
| 603 | LARROW2PIPE <- skip '<<|' ![=] | ||
| 604 | LARROW2PIPEEQUAL <- skip '<<|=' | ||
| 605 | LARROWEQUAL <- skip '<=' | ||
| 606 | LBRACE <- skip '{' | ||
| 607 | LBRACKET <- skip '[' | ||
| 608 | LPAREN <- skip '(' | ||
| 609 | MINUS <- skip '-' ![%=>|] | ||
| 610 | MINUSEQUAL <- skip '-=' | ||
| 611 | MINUSPERCENT <- skip '-%' ![=] | ||
| 612 | MINUSPERCENTEQUAL <- skip '-%=' | ||
| 613 | MINUSPIPE <- skip '-|' ![=] | ||
| 614 | MINUSPIPEEQUAL <- skip '-|=' | ||
| 615 | MINUSRARROW <- skip '->' | ||
| 616 | PERCENT <- skip '%' ![=] | ||
| 617 | PERCENTEQUAL <- skip '%=' | ||
| 618 | PIPE <- skip '|' ![|=] | ||
| 619 | PIPE2 <- skip '||' | ||
| 620 | PIPEEQUAL <- skip '|=' | ||
| 621 | PLUS <- skip '+' ![%+=|] | ||
| 622 | PLUS2 <- skip '++' | ||
| 623 | PLUSEQUAL <- skip '+=' | ||
| 624 | PLUSPERCENT <- skip '+%' ![=] | ||
| 625 | PLUSPERCENTEQUAL <- skip '+%=' | ||
| 626 | PLUSPIPE <- skip '+|' ![=] | ||
| 627 | PLUSPIPEEQUAL <- skip '+|=' | ||
| 628 | LETTERC <- skip 'c' | ||
| 629 | QUESTIONMARK <- skip '?' | ||
| 630 | RARROW <- skip '>' ![>=] | ||
| 631 | RARROW2 <- skip '>>' ![=] | ||
| 632 | RARROW2EQUAL <- skip '>>=' | ||
| 633 | RARROWEQUAL <- skip '>=' | ||
| 634 | RBRACE <- skip '}' | ||
| 635 | RBRACKET <- skip ']' | ||
| 636 | RPAREN <- skip ')' | ||
| 637 | SEMICOLON <- skip ';' | ||
| 638 | SLASH <- skip '/' ![=/] | ||
| 639 | SLASHEQUAL <- skip '/=' | ||
| 640 | TILDE <- skip '~' | ||
| 641 | |||
| 642 | end_of_word <- ![a-zA-Z0-9_] | ||
| 643 | KEYWORD_addrspace <- skip 'addrspace' end_of_word | ||
| 644 | KEYWORD_align <- skip 'align' end_of_word | ||
| 645 | KEYWORD_allowzero <- skip 'allowzero' end_of_word | ||
| 646 | KEYWORD_and <- skip 'and' end_of_word | ||
| 647 | KEYWORD_anyframe <- skip 'anyframe' end_of_word | ||
| 648 | KEYWORD_anytype <- skip 'anytype' end_of_word | ||
| 649 | KEYWORD_asm <- skip 'asm' end_of_word | ||
| 650 | KEYWORD_break <- skip 'break' end_of_word | ||
| 651 | KEYWORD_callconv <- skip 'callconv' end_of_word | ||
| 652 | KEYWORD_catch <- skip 'catch' end_of_word | ||
| 653 | KEYWORD_comptime <- skip 'comptime' end_of_word | ||
| 654 | KEYWORD_const <- skip 'const' end_of_word | ||
| 655 | KEYWORD_continue <- skip 'continue' end_of_word | ||
| 656 | KEYWORD_defer <- skip 'defer' end_of_word | ||
| 657 | KEYWORD_else <- skip 'else' end_of_word | ||
| 658 | KEYWORD_enum <- skip 'enum' end_of_word | ||
| 659 | KEYWORD_errdefer <- skip 'errdefer' end_of_word | ||
| 660 | KEYWORD_error <- skip 'error' end_of_word | ||
| 661 | KEYWORD_export <- skip 'export' end_of_word | ||
| 662 | KEYWORD_extern <- skip 'extern' end_of_word | ||
| 663 | KEYWORD_fn <- skip 'fn' end_of_word | ||
| 664 | KEYWORD_for <- skip 'for' end_of_word | ||
| 665 | KEYWORD_if <- skip 'if' end_of_word | ||
| 666 | KEYWORD_inline <- skip 'inline' end_of_word | ||
| 667 | KEYWORD_noalias <- skip 'noalias' end_of_word | ||
| 668 | KEYWORD_nosuspend <- skip 'nosuspend' end_of_word | ||
| 669 | KEYWORD_noinline <- skip 'noinline' end_of_word | ||
| 670 | KEYWORD_opaque <- skip 'opaque' end_of_word | ||
| 671 | KEYWORD_or <- skip 'or' end_of_word | ||
| 672 | KEYWORD_orelse <- skip 'orelse' end_of_word | ||
| 673 | KEYWORD_packed <- skip 'packed' end_of_word | ||
| 674 | KEYWORD_pub <- skip 'pub' end_of_word | ||
| 675 | KEYWORD_resume <- skip 'resume' end_of_word | ||
| 676 | KEYWORD_return <- skip 'return' end_of_word | ||
| 677 | KEYWORD_linksection <- skip 'linksection' end_of_word | ||
| 678 | KEYWORD_struct <- skip 'struct' end_of_word | ||
| 679 | KEYWORD_suspend <- skip 'suspend' end_of_word | ||
| 680 | KEYWORD_switch <- skip 'switch' end_of_word | ||
| 681 | KEYWORD_test <- skip 'test' end_of_word | ||
| 682 | KEYWORD_threadlocal <- skip 'threadlocal' end_of_word | ||
| 683 | KEYWORD_try <- skip 'try' end_of_word | ||
| 684 | KEYWORD_union <- skip 'union' end_of_word | ||
| 685 | KEYWORD_unreachable <- skip 'unreachable' end_of_word | ||
| 686 | KEYWORD_var <- skip 'var' end_of_word | ||
| 687 | KEYWORD_volatile <- skip 'volatile' end_of_word | ||
| 688 | KEYWORD_while <- skip 'while' end_of_word | ||
| 689 | |||
| 690 | keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and | ||
| 691 | / KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm | ||
| 692 | / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch | ||
| 693 | / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer | ||
| 694 | / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export | ||
| 695 | / KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if | ||
| 696 | / KEYWORD_inline / KEYWORD_noalias / KEYWORD_nosuspend / KEYWORD_noinline | ||
| 697 | / KEYWORD_opaque / KEYWORD_or / KEYWORD_orelse / KEYWORD_packed | ||
| 698 | / KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection | ||
| 699 | / KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch / KEYWORD_test | ||
| 700 | / KEYWORD_threadlocal / KEYWORD_try / KEYWORD_union / KEYWORD_unreachable | ||
| 701 | / KEYWORD_var / KEYWORD_volatile / KEYWORD_while | ||
lib/compiler/Maker.zig+1-1| ... | @@ -3536,7 +3536,7 @@ fn loadManifest( | ... | @@ -3536,7 +3536,7 @@ fn loadManifest( |
| 3536 | else => |e| fatal("unable to load {s}: {t}", .{ Package.Manifest.basename, e }), | 3536 | else => |e| fatal("unable to load {s}: {t}", .{ Package.Manifest.basename, e }), |
| 3537 | }; | 3537 | }; |
| 3538 | }; | 3538 | }; |
| 3539 | var ast = try std.zig.Ast.parse(gpa, manifest_bytes, .zon); | 3539 | var ast = try std.zig.Ast.parse(gpa, manifest_bytes, .zon, .{}); |
| 3540 | errdefer ast.deinit(gpa); | 3540 | errdefer ast.deinit(gpa); |
| 3541 | 3541 | ||
| 3542 | if (ast.errors.len > 0) { | 3542 | if (ast.errors.len > 0) { |
lib/compiler/Maker/Package/Manifest.zig+4-4| ... | @@ -597,7 +597,7 @@ pub fn load( | ... | @@ -597,7 +597,7 @@ pub fn load( |
| 597 | 0, | 597 | 0, |
| 598 | ); | 598 | ); |
| 599 | 599 | ||
| 600 | ast.* = try std.zig.Ast.parse(arena, manifest_bytes, .zon); | 600 | ast.* = try std.zig.Ast.parse(arena, manifest_bytes, .zon, .{}); |
| 601 | 601 | ||
| 602 | if (ast.errors.len > 0) { | 602 | if (ast.errors.len > 0) { |
| 603 | const file_path = try manifest_path.joinString(arena, ""); | 603 | const file_path = try manifest_path.joinString(arena, ""); |
| ... | @@ -636,7 +636,7 @@ test "basic" { | ... | @@ -636,7 +636,7 @@ test "basic" { |
| 636 | \\} | 636 | \\} |
| 637 | ; | 637 | ; |
| 638 | 638 | ||
| 639 | var ast = try Ast.parse(gpa, example, .zon); | 639 | var ast = try Ast.parse(gpa, example, .zon, .{}); |
| 640 | defer ast.deinit(gpa); | 640 | defer ast.deinit(gpa); |
| 641 | 641 | ||
| 642 | try testing.expect(ast.errors.len == 0); | 642 | try testing.expect(ast.errors.len == 0); |
| ... | @@ -682,7 +682,7 @@ test "minimum_zig_version" { | ... | @@ -682,7 +682,7 @@ test "minimum_zig_version" { |
| 682 | \\} | 682 | \\} |
| 683 | ; | 683 | ; |
| 684 | 684 | ||
| 685 | var ast = try Ast.parse(gpa, example, .zon); | 685 | var ast = try Ast.parse(gpa, example, .zon, .{}); |
| 686 | defer ast.deinit(gpa); | 686 | defer ast.deinit(gpa); |
| 687 | 687 | ||
| 688 | try testing.expect(ast.errors.len == 0); | 688 | try testing.expect(ast.errors.len == 0); |
| ... | @@ -717,7 +717,7 @@ test "minimum_zig_version - invalid version" { | ... | @@ -717,7 +717,7 @@ test "minimum_zig_version - invalid version" { |
| 717 | \\} | 717 | \\} |
| 718 | ; | 718 | ; |
| 719 | 719 | ||
| 720 | var ast = try Ast.parse(gpa, example, .zon); | 720 | var ast = try Ast.parse(gpa, example, .zon, .{}); |
| 721 | defer ast.deinit(gpa); | 721 | defer ast.deinit(gpa); |
| 722 | 722 | ||
| 723 | try testing.expect(ast.errors.len == 0); | 723 | try testing.expect(ast.errors.len == 0); |
lib/compiler/reduce.zig+2-2| ... | @@ -188,7 +188,7 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -188,7 +188,7 @@ pub fn main(init: std.process.Init) !void { |
| 188 | try astgen_input.writer.writeAll(rendered.written()); | 188 | try astgen_input.writer.writeAll(rendered.written()); |
| 189 | try astgen_input.writer.writeByte(0); | 189 | try astgen_input.writer.writeByte(0); |
| 190 | const source_with_null = astgen_input.written()[0..(astgen_input.written().len - 1) :0]; | 190 | const source_with_null = astgen_input.written()[0..(astgen_input.written().len - 1) :0]; |
| 191 | var astgen_tree = try Ast.parse(gpa, source_with_null, .zig); | 191 | var astgen_tree = try Ast.parse(gpa, source_with_null, .zig, .{}); |
| 192 | defer astgen_tree.deinit(gpa); | 192 | defer astgen_tree.deinit(gpa); |
| 193 | if (astgen_tree.errors.len != 0) { | 193 | if (astgen_tree.errors.len != 0) { |
| 194 | @panic("syntax errors occurred"); | 194 | @panic("syntax errors occurred"); |
| ... | @@ -407,7 +407,7 @@ fn parse(gpa: Allocator, io: Io, file_path: []const u8) !Ast { | ... | @@ -407,7 +407,7 @@ fn parse(gpa: Allocator, io: Io, file_path: []const u8) !Ast { |
| 407 | }; | 407 | }; |
| 408 | errdefer gpa.free(source_code); | 408 | errdefer gpa.free(source_code); |
| 409 | 409 | ||
| 410 | var tree = try Ast.parse(gpa, source_code, .zig); | 410 | var tree = try Ast.parse(gpa, source_code, .zig, .{}); |
| 411 | errdefer tree.deinit(gpa); | 411 | errdefer tree.deinit(gpa); |
| 412 | 412 | ||
| 413 | if (tree.errors.len != 0) { | 413 | if (tree.errors.len != 0) { |
lib/docs/wasm/Walk.zig+3-3| ... | @@ -428,7 +428,7 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast { | ... | @@ -428,7 +428,7 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast { |
| 428 | break :s source[0 .. source.len - 1 :0]; | 428 | break :s source[0 .. source.len - 1 :0]; |
| 429 | }; | 429 | }; |
| 430 | 430 | ||
| 431 | var ast = try Ast.parse(gpa, adjusted_source, .zig); | 431 | var ast = try Ast.parse(gpa, adjusted_source, .zig, .{}); |
| 432 | if (ast.errors.len > 0) { | 432 | if (ast.errors.len > 0) { |
| 433 | defer ast.deinit(gpa); | 433 | defer ast.deinit(gpa); |
| 434 | 434 | ||
| ... | @@ -446,7 +446,7 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast { | ... | @@ -446,7 +446,7 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast { |
| 446 | file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.written(), | 446 | file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.written(), |
| 447 | }); | 447 | }); |
| 448 | } | 448 | } |
| 449 | return Ast.parse(gpa, "", .zig); | 449 | return Ast.parse(gpa, "", .zig, .{}); |
| 450 | } | 450 | } |
| 451 | return ast; | 451 | return ast; |
| 452 | } | 452 | } |
| ... | @@ -1085,7 +1085,7 @@ pub fn isPrimitiveNonType(name: []const u8) bool { | ... | @@ -1085,7 +1085,7 @@ pub fn isPrimitiveNonType(name: []const u8) bool { |
| 1085 | // | 1085 | // |
| 1086 | // // example test command: | 1086 | // // example test command: |
| 1087 | // // zig test --dep input.zig -Mroot=src/Walk.zig -Minput.zig=/home/andy/dev/zig/lib/std/fs/File/zig | 1087 | // // zig test --dep input.zig -Mroot=src/Walk.zig -Minput.zig=/home/andy/dev/zig/lib/std/fs/File/zig |
| 1088 | // var ast = try Ast.parse(gpa, @embedFile("input.zig"), .zig); | 1088 | // var ast = try Ast.parse(gpa, @embedFile("input.zig"), .zig, .{}); |
| 1089 | // defer ast.deinit(gpa); | 1089 | // defer ast.deinit(gpa); |
| 1090 | // | 1090 | // |
| 1091 | // var w: Walk = .{ | 1091 | // var w: Walk = .{ |
lib/std/zig.zig+3-2| ... | @@ -29,7 +29,6 @@ pub const primitives = @import("zig/primitives.zig"); | ... | @@ -29,7 +29,6 @@ pub const primitives = @import("zig/primitives.zig"); |
| 29 | pub const isPrimitive = primitives.isPrimitive; | 29 | pub const isPrimitive = primitives.isPrimitive; |
| 30 | pub const Ast = @import("zig/Ast.zig"); | 30 | pub const Ast = @import("zig/Ast.zig"); |
| 31 | pub const AstGen = @import("zig/AstGen.zig"); | 31 | pub const AstGen = @import("zig/AstGen.zig"); |
| 32 | pub const AstSmith = @import("zig/AstSmith.zig"); | ||
| 33 | pub const Zir = @import("zig/Zir.zig"); | 32 | pub const Zir = @import("zig/Zir.zig"); |
| 34 | pub const Zoir = @import("zig/Zoir.zig"); | 33 | pub const Zoir = @import("zig/Zoir.zig"); |
| 35 | pub const ZonGen = @import("zig/ZonGen.zig"); | 34 | pub const ZonGen = @import("zig/ZonGen.zig"); |
| ... | @@ -43,6 +42,8 @@ pub const PkgConfig = @import("zig/PkgConfig.zig"); | ... | @@ -43,6 +42,8 @@ pub const PkgConfig = @import("zig/PkgConfig.zig"); |
| 43 | pub const target = @import("zig/target.zig"); | 42 | pub const target = @import("zig/target.zig"); |
| 44 | pub const llvm = @import("zig/llvm.zig"); | 43 | pub const llvm = @import("zig/llvm.zig"); |
| 45 | 44 | ||
| 45 | pub const parser_generated_oracle = @import("zig/parser_generated_oracle.zig"); | ||
| 46 | |||
| 46 | // Character literal parsing | 47 | // Character literal parsing |
| 47 | pub const ParsedCharLiteral = string_literal.ParsedCharLiteral; | 48 | pub const ParsedCharLiteral = string_literal.ParsedCharLiteral; |
| 48 | pub const parseCharLiteral = string_literal.parseCharLiteral; | 49 | pub const parseCharLiteral = string_literal.parseCharLiteral; |
| ... | @@ -1863,7 +1864,6 @@ fn readStreamAlloc(gpa: Allocator, io: Io, file: Io.File, limit: Io.Limit) ![]u8 | ... | @@ -1863,7 +1864,6 @@ fn readStreamAlloc(gpa: Allocator, io: Io, file: Io.File, limit: Io.Limit) ![]u8 |
| 1863 | test { | 1864 | test { |
| 1864 | _ = Ast; | 1865 | _ = Ast; |
| 1865 | _ = AstRlAnnotate; | 1866 | _ = AstRlAnnotate; |
| 1866 | _ = AstSmith; | ||
| 1867 | _ = BuiltinFn; | 1867 | _ = BuiltinFn; |
| 1868 | _ = Client; | 1868 | _ = Client; |
| 1869 | _ = ErrorBundle; | 1869 | _ = ErrorBundle; |
| ... | @@ -1879,4 +1879,5 @@ test { | ... | @@ -1879,4 +1879,5 @@ test { |
| 1879 | _ = target; | 1879 | _ = target; |
| 1880 | _ = c_translation; | 1880 | _ = c_translation; |
| 1881 | _ = llvm; | 1881 | _ = llvm; |
| 1882 | _ = @import("zig/parser_fuzz.zig"); | ||
| 1882 | } | 1883 | } |
lib/std/zig/Ast.zig+27-25| ... | @@ -139,10 +139,13 @@ pub fn deinit(tree: *Ast, gpa: Allocator) void { | ... | @@ -139,10 +139,13 @@ pub fn deinit(tree: *Ast, gpa: Allocator) void { |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | pub const Mode = enum { zig, zon }; | 141 | pub const Mode = enum { zig, zon }; |
| 142 | pub const ParseOptions = struct { | ||
| 143 | recover: bool = true, | ||
| 144 | }; | ||
| 142 | 145 | ||
| 143 | /// Result should be freed with tree.deinit() when there are | 146 | /// Result should be freed with tree.deinit() when there are |
| 144 | /// no more references to any of the tokens or nodes. | 147 | /// no more references to any of the tokens or nodes. |
| 145 | pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!Ast { | 148 | pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode, options: ParseOptions) Allocator.Error!Ast { |
| 146 | var tokens = Ast.TokenList{}; | 149 | var tokens = Ast.TokenList{}; |
| 147 | defer tokens.deinit(gpa); | 150 | defer tokens.deinit(gpa); |
| 148 | 151 | ||
| ... | @@ -162,7 +165,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A | ... | @@ -162,7 +165,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A |
| 162 | 165 | ||
| 163 | var tokens_slice = tokens.toOwnedSlice(); | 166 | var tokens_slice = tokens.toOwnedSlice(); |
| 164 | errdefer tokens_slice.deinit(gpa); | 167 | errdefer tokens_slice.deinit(gpa); |
| 165 | return parseTokens(gpa, source, tokens_slice, mode); | 168 | return parseTokens(gpa, source, tokens_slice, mode, options); |
| 166 | } | 169 | } |
| 167 | 170 | ||
| 168 | pub fn parseTokens( | 171 | pub fn parseTokens( |
| ... | @@ -170,6 +173,7 @@ pub fn parseTokens( | ... | @@ -170,6 +173,7 @@ pub fn parseTokens( |
| 170 | source: [:0]const u8, | 173 | source: [:0]const u8, |
| 171 | tokens: Ast.TokenList.Slice, | 174 | tokens: Ast.TokenList.Slice, |
| 172 | mode: Mode, | 175 | mode: Mode, |
| 176 | options: ParseOptions, | ||
| 173 | ) Allocator.Error!Ast { | 177 | ) Allocator.Error!Ast { |
| 174 | var parser: Parse = .{ | 178 | var parser: Parse = .{ |
| 175 | .source = source, | 179 | .source = source, |
| ... | @@ -180,6 +184,7 @@ pub fn parseTokens( | ... | @@ -180,6 +184,7 @@ pub fn parseTokens( |
| 180 | .extra_data = .empty, | 184 | .extra_data = .empty, |
| 181 | .scratch = .empty, | 185 | .scratch = .empty, |
| 182 | .tok_i = 0, | 186 | .tok_i = 0, |
| 187 | .recover = options.recover, | ||
| 183 | }; | 188 | }; |
| 184 | defer parser.errors.deinit(gpa); | 189 | defer parser.errors.deinit(gpa); |
| 185 | defer parser.nodes.deinit(gpa); | 190 | defer parser.nodes.deinit(gpa); |
| ... | @@ -465,15 +470,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void | ... | @@ -465,15 +470,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void |
| 465 | .extra_align_qualifier => { | 470 | .extra_align_qualifier => { |
| 466 | return w.writeAll("extra align qualifier"); | 471 | return w.writeAll("extra align qualifier"); |
| 467 | }, | 472 | }, |
| 468 | .extra_allowzero_qualifier => { | ||
| 469 | return w.writeAll("extra allowzero qualifier"); | ||
| 470 | }, | ||
| 471 | .extra_const_qualifier => { | ||
| 472 | return w.writeAll("extra const qualifier"); | ||
| 473 | }, | ||
| 474 | .extra_volatile_qualifier => { | ||
| 475 | return w.writeAll("extra volatile qualifier"); | ||
| 476 | }, | ||
| 477 | .ptr_mod_on_array_child_type => { | 473 | .ptr_mod_on_array_child_type => { |
| 478 | return w.print("pointer modifier '{s}' not allowed on array child type", .{ | 474 | return w.print("pointer modifier '{s}' not allowed on array child type", .{ |
| 479 | tree.tokenTag(parse_error.token).symbol(), | 475 | tree.tokenTag(parse_error.token).symbol(), |
| ... | @@ -559,12 +555,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void | ... | @@ -559,12 +555,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void |
| 559 | .var_const_decl => { | 555 | .var_const_decl => { |
| 560 | return w.writeAll("use 'var' or 'const' to declare variable"); | 556 | return w.writeAll("use 'var' or 'const' to declare variable"); |
| 561 | }, | 557 | }, |
| 562 | .extra_for_capture => { | ||
| 563 | return w.writeAll("extra capture in for loop"); | ||
| 564 | }, | ||
| 565 | .for_input_not_captured => { | ||
| 566 | return w.writeAll("for input is not captured"); | ||
| 567 | }, | ||
| 568 | 558 | ||
| 569 | .invalid_byte => { | 559 | .invalid_byte => { |
| 570 | const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..]; | 560 | const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..]; |
| ... | @@ -2116,6 +2106,7 @@ fn fullPtrTypeComponents(tree: Ast, info: full.PtrType.Components) full.PtrType | ... | @@ -2116,6 +2106,7 @@ fn fullPtrTypeComponents(tree: Ast, info: full.PtrType.Components) full.PtrType |
| 2116 | .allowzero_token = null, | 2106 | .allowzero_token = null, |
| 2117 | .const_token = null, | 2107 | .const_token = null, |
| 2118 | .volatile_token = null, | 2108 | .volatile_token = null, |
| 2109 | .duplicate_token = null, | ||
| 2119 | .ast = info, | 2110 | .ast = info, |
| 2120 | }; | 2111 | }; |
| 2121 | // We need to be careful that we don't iterate over any sub-expressions | 2112 | // We need to be careful that we don't iterate over any sub-expressions |
| ... | @@ -2131,9 +2122,24 @@ fn fullPtrTypeComponents(tree: Ast, info: full.PtrType.Components) full.PtrType | ... | @@ -2131,9 +2122,24 @@ fn fullPtrTypeComponents(tree: Ast, info: full.PtrType.Components) full.PtrType |
| 2131 | const end = tree.firstToken(info.child_type); | 2122 | const end = tree.firstToken(info.child_type); |
| 2132 | while (i < end) : (i += 1) { | 2123 | while (i < end) : (i += 1) { |
| 2133 | switch (tree.tokenTag(i)) { | 2124 | switch (tree.tokenTag(i)) { |
| 2134 | .keyword_allowzero => result.allowzero_token = i, | 2125 | .keyword_allowzero => { |
| 2135 | .keyword_const => result.const_token = i, | 2126 | if (result.allowzero_token != null) { |
| 2136 | .keyword_volatile => result.volatile_token = i, | 2127 | result.duplicate_token = i; |
| 2128 | } | ||
| 2129 | result.allowzero_token = i; | ||
| 2130 | }, | ||
| 2131 | .keyword_const => { | ||
| 2132 | if (result.const_token != null) { | ||
| 2133 | result.duplicate_token = i; | ||
| 2134 | } | ||
| 2135 | result.const_token = i; | ||
| 2136 | }, | ||
| 2137 | .keyword_volatile => { | ||
| 2138 | if (result.volatile_token != null) { | ||
| 2139 | result.duplicate_token = i; | ||
| 2140 | } | ||
| 2141 | result.volatile_token = i; | ||
| 2142 | }, | ||
| 2137 | .keyword_align => { | 2143 | .keyword_align => { |
| 2138 | if (info.bit_range_end.unwrap()) |bit_range_end| { | 2144 | if (info.bit_range_end.unwrap()) |bit_range_end| { |
| 2139 | assert(info.bit_range_start != .none); | 2145 | assert(info.bit_range_start != .none); |
| ... | @@ -2730,6 +2736,7 @@ pub const full = struct { | ... | @@ -2730,6 +2736,7 @@ pub const full = struct { |
| 2730 | allowzero_token: ?TokenIndex, | 2736 | allowzero_token: ?TokenIndex, |
| 2731 | const_token: ?TokenIndex, | 2737 | const_token: ?TokenIndex, |
| 2732 | volatile_token: ?TokenIndex, | 2738 | volatile_token: ?TokenIndex, |
| 2739 | duplicate_token: ?TokenIndex, | ||
| 2733 | ast: Components, | 2740 | ast: Components, |
| 2734 | 2741 | ||
| 2735 | pub const Components = struct { | 2742 | pub const Components = struct { |
| ... | @@ -2863,9 +2870,6 @@ pub const Error = struct { | ... | @@ -2863,9 +2870,6 @@ pub const Error = struct { |
| 2863 | extern_fn_body, | 2870 | extern_fn_body, |
| 2864 | extra_addrspace_qualifier, | 2871 | extra_addrspace_qualifier, |
| 2865 | extra_align_qualifier, | 2872 | extra_align_qualifier, |
| 2866 | extra_allowzero_qualifier, | ||
| 2867 | extra_const_qualifier, | ||
| 2868 | extra_volatile_qualifier, | ||
| 2869 | ptr_mod_on_array_child_type, | 2873 | ptr_mod_on_array_child_type, |
| 2870 | invalid_bit_range, | 2874 | invalid_bit_range, |
| 2871 | same_line_doc_comment, | 2875 | same_line_doc_comment, |
| ... | @@ -2889,8 +2893,6 @@ pub const Error = struct { | ... | @@ -2889,8 +2893,6 @@ pub const Error = struct { |
| 2889 | expected_var_const, | 2893 | expected_var_const, |
| 2890 | wrong_equal_var_decl, | 2894 | wrong_equal_var_decl, |
| 2891 | var_const_decl, | 2895 | var_const_decl, |
| 2892 | extra_for_capture, | ||
| 2893 | for_input_not_captured, | ||
| 2894 | 2896 | ||
| 2895 | zig_style_container, | 2897 | zig_style_container, |
| 2896 | previous_field, | 2898 | previous_field, |
lib/std/zig/AstGen.zig+10| ... | @@ -3746,6 +3746,9 @@ fn ptrType( | ... | @@ -3746,6 +3746,9 @@ fn ptrType( |
| 3746 | if (ptr_info.size == .c and ptr_info.allowzero_token != null) { | 3746 | if (ptr_info.size == .c and ptr_info.allowzero_token != null) { |
| 3747 | return gz.astgen.failTok(ptr_info.allowzero_token.?, "C pointers always allow address zero", .{}); | 3747 | return gz.astgen.failTok(ptr_info.allowzero_token.?, "C pointers always allow address zero", .{}); |
| 3748 | } | 3748 | } |
| 3749 | if (ptr_info.duplicate_token) |duplicate| { | ||
| 3750 | return gz.astgen.failTok(duplicate, "Extra pointer qualifier", .{}); | ||
| 3751 | } | ||
| 3749 | 3752 | ||
| 3750 | const source_offset = gz.astgen.source_offset; | 3753 | const source_offset = gz.astgen.source_offset; |
| 3751 | const source_line = gz.astgen.source_line; | 3754 | const source_line = gz.astgen.source_line; |
| ... | @@ -6709,6 +6712,9 @@ fn forExpr( | ... | @@ -6709,6 +6712,9 @@ fn forExpr( |
| 6709 | for (for_full.ast.inputs, indexables, lens) |input, *indexable_ref, *len_refs| { | 6712 | for (for_full.ast.inputs, indexables, lens) |input, *indexable_ref, *len_refs| { |
| 6710 | const capture_is_ref = tree.tokenTag(capture_token) == .asterisk; | 6713 | const capture_is_ref = tree.tokenTag(capture_token) == .asterisk; |
| 6711 | const ident_tok = capture_token + @intFromBool(capture_is_ref); | 6714 | const ident_tok = capture_token + @intFromBool(capture_is_ref); |
| 6715 | if (tree.tokenTag(ident_tok) != .identifier) { | ||
| 6716 | return astgen.failNode(input, "for input is not captured", .{}); | ||
| 6717 | } | ||
| 6712 | const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_"); | 6718 | const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_"); |
| 6713 | 6719 | ||
| 6714 | if (is_discard and capture_is_ref) { | 6720 | if (is_discard and capture_is_ref) { |
| ... | @@ -6751,6 +6757,10 @@ fn forExpr( | ... | @@ -6751,6 +6757,10 @@ fn forExpr( |
| 6751 | len_refs.* = .{ indexable, .none }; | 6757 | len_refs.* = .{ indexable, .none }; |
| 6752 | } | 6758 | } |
| 6753 | } | 6759 | } |
| 6760 | // There may or may not be a trailing comma after the final capture | ||
| 6761 | if (tree.tokenTag(capture_token) != .pipe and tree.tokenTag(capture_token - 1) != .pipe) { | ||
| 6762 | return astgen.failTok(capture_token, "extra capture in for loop", .{}); | ||
| 6763 | } | ||
| 6754 | } | 6764 | } |
| 6755 | 6765 | ||
| 6756 | if (!any_len_checks) { | 6766 | if (!any_len_checks) { |
lib/std/zig/AstSmith.zig deleted-2595| ... | @@ -1,2595 +0,0 @@ | ||
| 1 | //! Generates a valid AST and corresponding source. | ||
| 2 | //! | ||
| 3 | //! This is based directly off grammer.peg | ||
| 4 | |||
| 5 | const std = @import("../std.zig"); | ||
| 6 | const assert = std.debug.assert; | ||
| 7 | const Token = std.zig.Token; | ||
| 8 | const Smith = std.testing.Smith; | ||
| 9 | const Weight = Smith.Weight; | ||
| 10 | const AstSmith = @This(); | ||
| 11 | |||
| 12 | smith: *Smith, | ||
| 13 | |||
| 14 | source_buf: [16384]u8, | ||
| 15 | source_len: usize, | ||
| 16 | |||
| 17 | token_tag_buf: [2048]Token.Tag, | ||
| 18 | token_start_buf: [2048]std.zig.Ast.ByteOffset, | ||
| 19 | tokens_len: usize, | ||
| 20 | |||
| 21 | not_token: ?Token.Tag, | ||
| 22 | not_token_comptime: bool, | ||
| 23 | /// ExprSuffix | ||
| 24 | /// <- KEYWORD_or | ||
| 25 | /// / KEYWORD_and | ||
| 26 | /// / CompareOp | ||
| 27 | /// / BitwiseOp | ||
| 28 | /// / BitShiftOp | ||
| 29 | /// / AdditionOp | ||
| 30 | /// / MultiplyOp | ||
| 31 | /// / EXCLAMATIONMARK | ||
| 32 | /// / SuffixOp | ||
| 33 | /// / FnCallArguments | ||
| 34 | not_expr_suffix: bool, | ||
| 35 | /// LabelableExpr | ||
| 36 | /// <- Block | ||
| 37 | /// / SwitchExpr | ||
| 38 | /// / LoopExpr | ||
| 39 | not_labelable_expr: ?enum { colon, expr }, | ||
| 40 | not_label: bool, | ||
| 41 | not_break_label: bool, | ||
| 42 | not_block_expr: bool, | ||
| 43 | not_expr_statement: bool, | ||
| 44 | |||
| 45 | prev_ids_buf: [256]struct { start: u16, len: u16 }, | ||
| 46 | /// This may be larger than `prev_ids` in which case, | ||
| 47 | /// x % prev_ids.len = next index | ||
| 48 | /// @min(x, prev_ids) = length | ||
| 49 | prev_ids_len: usize, | ||
| 50 | |||
| 51 | /// `generate` must be called on the returned value before any other methods | ||
| 52 | pub fn init(smith: *Smith) AstSmith { | ||
| 53 | return .{ | ||
| 54 | .smith = smith, | ||
| 55 | |||
| 56 | .source_buf = undefined, | ||
| 57 | .source_len = 0, | ||
| 58 | |||
| 59 | .token_tag_buf = undefined, | ||
| 60 | .token_start_buf = undefined, | ||
| 61 | .tokens_len = 0, | ||
| 62 | |||
| 63 | .not_token = null, | ||
| 64 | .not_token_comptime = false, | ||
| 65 | .not_expr_suffix = false, | ||
| 66 | .not_labelable_expr = null, | ||
| 67 | .not_label = false, | ||
| 68 | .not_break_label = false, | ||
| 69 | .not_block_expr = false, | ||
| 70 | .not_expr_statement = false, | ||
| 71 | |||
| 72 | .prev_ids_buf = undefined, | ||
| 73 | .prev_ids_len = 0, | ||
| 74 | }; | ||
| 75 | } | ||
| 76 | |||
| 77 | pub fn source(t: *AstSmith) [:0]u8 { | ||
| 78 | return t.source_buf[0..t.source_len :0]; | ||
| 79 | } | ||
| 80 | |||
| 81 | /// The Slice is not backed by a MultiArrayList, so calling deinit or toMultiArrayList is illegal. | ||
| 82 | pub fn tokens(t: *AstSmith) std.zig.Ast.TokenList.Slice { | ||
| 83 | var slice: std.zig.Ast.TokenList.Slice = .{ | ||
| 84 | .ptrs = undefined, | ||
| 85 | .len = t.tokens_len, | ||
| 86 | .capacity = t.tokens_len, | ||
| 87 | }; | ||
| 88 | comptime assert(slice.ptrs.len == 2); | ||
| 89 | slice.ptrs[@intFromEnum(std.zig.Ast.TokenList.Field.tag)] = @ptrCast(&t.token_tag_buf); | ||
| 90 | slice.ptrs[@intFromEnum(std.zig.Ast.TokenList.Field.start)] = @ptrCast(&t.token_start_buf); | ||
| 91 | return slice; | ||
| 92 | } | ||
| 93 | |||
| 94 | pub const Error = error{ OutOfMemory, SkipZigTest }; | ||
| 95 | const SourceError = error{SkipZigTest}; | ||
| 96 | |||
| 97 | pub fn generate(a: *AstSmith, gpa: std.mem.Allocator) Error!std.zig.Ast { | ||
| 98 | try a.generateSource(); | ||
| 99 | const ast = try std.zig.Ast.parseTokens(gpa, a.source(), a.tokens(), .zig); | ||
| 100 | assert(ast.errors.len == 0); | ||
| 101 | return ast; | ||
| 102 | } | ||
| 103 | |||
| 104 | pub fn generateSource(a: *AstSmith) SourceError!void { | ||
| 105 | try a.pegRoot(); | ||
| 106 | try a.ensureSourceCapacity(1); | ||
| 107 | a.source_buf[a.source_len] = 0; | ||
| 108 | try a.addTokenTag(.eof); | ||
| 109 | } | ||
| 110 | |||
| 111 | /// For choices which can introduce a variable number of expressions, this should be used to reduce | ||
| 112 | /// unbounded recursion. | ||
| 113 | // | ||
| 114 | // `inline` to propogate caller's return address | ||
| 115 | inline fn smithListItemBool(a: *AstSmith) bool { | ||
| 116 | return a.smith.boolWeighted(63, 1); | ||
| 117 | } | ||
| 118 | |||
| 119 | /// For choices which can introduce a variable number of expressions, this should be used to reduce | ||
| 120 | /// unbounded recursion. | ||
| 121 | // | ||
| 122 | // `inline` to propogate caller's return address | ||
| 123 | inline fn smithListItemEos(a: *AstSmith) bool { | ||
| 124 | return a.smith.eosWeightedSimple(1, 63); | ||
| 125 | } | ||
| 126 | |||
| 127 | fn sourceCapacity(a: *AstSmith) []u8 { | ||
| 128 | return a.source_buf[a.source_len..]; | ||
| 129 | } | ||
| 130 | |||
| 131 | fn sourceCapacityLen(a: *AstSmith) usize { | ||
| 132 | return a.source_buf.len - a.source_len; | ||
| 133 | } | ||
| 134 | |||
| 135 | fn ensureSourceCapacity(a: *AstSmith, n: usize) SourceError!void { | ||
| 136 | if (a.sourceCapacityLen() < n) return error.SkipZigTest; | ||
| 137 | } | ||
| 138 | |||
| 139 | fn addSourceByte(a: *AstSmith, byte: u8) SourceError!void { | ||
| 140 | try a.ensureSourceCapacity(1); | ||
| 141 | a.addSourceByteAssumeCapacity(byte); | ||
| 142 | } | ||
| 143 | |||
| 144 | fn addSourceByteAssumeCapacity(a: *AstSmith, byte: u8) void { | ||
| 145 | a.sourceCapacity()[0] = byte; | ||
| 146 | a.source_len += 1; | ||
| 147 | } | ||
| 148 | |||
| 149 | fn addSource(a: *AstSmith, bytes: []const u8) SourceError!void { | ||
| 150 | try a.ensureSourceCapacity(bytes.len); | ||
| 151 | a.addSourceAssumeCapacity(bytes); | ||
| 152 | } | ||
| 153 | |||
| 154 | fn addSourceAssumeCapacity(a: *AstSmith, bytes: []const u8) void { | ||
| 155 | @memcpy(a.sourceCapacity()[0..bytes.len], bytes); | ||
| 156 | a.source_len += bytes.len; | ||
| 157 | } | ||
| 158 | |||
| 159 | fn addSourceAsSlice(a: *AstSmith, len: usize) SourceError![]u8 { | ||
| 160 | try a.ensureSourceCapacity(len); | ||
| 161 | return a.addSourceAsSliceAssumeCapacity(len); | ||
| 162 | } | ||
| 163 | |||
| 164 | fn addSourceAsSliceAssumeCapacity(a: *AstSmith, len: usize) []u8 { | ||
| 165 | const slice = a.sourceCapacity()[0..len]; | ||
| 166 | a.source_len += len; | ||
| 167 | return slice; | ||
| 168 | } | ||
| 169 | |||
| 170 | fn tokenCapacityLen(a: *AstSmith) usize { | ||
| 171 | return a.token_tag_buf.len - a.tokens_len; | ||
| 172 | } | ||
| 173 | |||
| 174 | fn ensureTokenCapacity(a: *AstSmith, n: usize) SourceError!void { | ||
| 175 | if (a.tokenCapacityLen() < n) return error.SkipZigTest; | ||
| 176 | } | ||
| 177 | |||
| 178 | fn isAlphanumeric(c: u8) bool { | ||
| 179 | return switch (c) { | ||
| 180 | '_', 'a'...'z', 'A'...'Z', '0'...'9' => true, | ||
| 181 | else => false, | ||
| 182 | }; | ||
| 183 | } | ||
| 184 | |||
| 185 | /// For tokens starting with alphanumerics, this ensures | ||
| 186 | /// previous tokens followed by end_of_word aren't altered. | ||
| 187 | /// | ||
| 188 | /// end_of_word <- ![a-zA-Z0-9_] skip | ||
| 189 | fn preservePegEndOfWord(a: *AstSmith) SourceError!void { | ||
| 190 | if (a.source_len > 0 and isAlphanumeric(a.source_buf[a.source_len - 1])) { | ||
| 191 | try a.addSourceByte(' '); | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | /// Assumes the token has not been written yet | ||
| 196 | fn addTokenTag(a: *AstSmith, tag: Token.Tag) SourceError!void { | ||
| 197 | assert(tag != a.not_token); | ||
| 198 | a.not_token = null; | ||
| 199 | |||
| 200 | if (a.not_token_comptime) assert(tag != .keyword_comptime); | ||
| 201 | a.not_token_comptime = false; | ||
| 202 | |||
| 203 | if (a.not_label and tag == .identifier) { | ||
| 204 | a.not_token = .colon; | ||
| 205 | } | ||
| 206 | a.not_label = false; | ||
| 207 | |||
| 208 | if (a.not_break_label and tag == .colon) { | ||
| 209 | a.not_token = .identifier; | ||
| 210 | } | ||
| 211 | a.not_break_label = false; | ||
| 212 | |||
| 213 | if (a.not_labelable_expr) |part| switch (part) { | ||
| 214 | .colon => a.not_labelable_expr = if (tag == .colon) .expr else null, | ||
| 215 | .expr => switch (tag) { | ||
| 216 | .l_brace => unreachable, | ||
| 217 | .keyword_inline => {}, | ||
| 218 | .keyword_for => unreachable, | ||
| 219 | .keyword_while => unreachable, | ||
| 220 | .keyword_switch => unreachable, | ||
| 221 | else => a.not_labelable_expr = null, | ||
| 222 | }, | ||
| 223 | }; | ||
| 224 | |||
| 225 | a.not_expr_suffix = false; | ||
| 226 | a.not_block_expr = false; | ||
| 227 | a.not_expr_statement = false; | ||
| 228 | |||
| 229 | try a.ensureTokenCapacity(1); | ||
| 230 | a.token_tag_buf[a.tokens_len] = tag; | ||
| 231 | a.token_start_buf[a.tokens_len] = @intCast(a.source_len); | ||
| 232 | a.tokens_len += 1; | ||
| 233 | } | ||
| 234 | |||
| 235 | /// Asserts the token has a lexeme (those without have corresponding methods) | ||
| 236 | fn pegToken(a: *AstSmith, tag: Token.Tag) SourceError!void { | ||
| 237 | const lexeme = tag.lexeme().?; | ||
| 238 | |||
| 239 | switch (lexeme[0]) { | ||
| 240 | '_', 'a'...'z', 'A'...'Z', '0'...'9' => try a.preservePegEndOfWord(), | ||
| 241 | '.' => if (a.tokens_len > 0 and switch (a.source_buf[a.source_len - 1]) { | ||
| 242 | '.' => true, | ||
| 243 | '0'...'9', 'a'...'z', 'A'...'Z' => a.token_tag_buf[a.tokens_len - 1] == .number_literal, | ||
| 244 | else => false, | ||
| 245 | }) { | ||
| 246 | try a.addSourceByte(' '); | ||
| 247 | }, | ||
| 248 | '+', '-' => if (a.tokens_len > 0 and a.token_tag_buf[a.tokens_len - 1] == .number_literal and | ||
| 249 | switch (a.source_buf[a.source_len - 1]) { | ||
| 250 | 'e', 'E', 'p', 'P' => true, | ||
| 251 | else => false, | ||
| 252 | }) | ||
| 253 | { | ||
| 254 | // Would otherwise be tokenized as the sign of a float's exponent | ||
| 255 | // | ||
| 256 | // e.g. "0xFE" ++ "+" ++ "2" (number_literal, plus, number_literal) | ||
| 257 | try a.addSourceByte(' '); | ||
| 258 | }, | ||
| 259 | else => {}, | ||
| 260 | } | ||
| 261 | |||
| 262 | if (isAlphanumeric(lexeme[0])) try a.preservePegEndOfWord(); | ||
| 263 | |||
| 264 | try a.addTokenTag(tag); | ||
| 265 | try a.addSource(lexeme); | ||
| 266 | try a.pegSkip(); | ||
| 267 | } | ||
| 268 | |||
| 269 | /// Asserts `a.source_len != 0` | ||
| 270 | fn pegTokenWhitespaceAround(a: *AstSmith, tag: Token.Tag) SourceError!void { | ||
| 271 | switch (a.source_buf[a.source_len - 1]) { | ||
| 272 | ' ', '\n' => {}, | ||
| 273 | else => try a.addSourceByte(' '), | ||
| 274 | } | ||
| 275 | try a.addTokenTag(tag); | ||
| 276 | try a.addSource(tag.lexeme().?); | ||
| 277 | switch (a.smith.value(enum { space, line_break, cr_line_break })) { | ||
| 278 | // This is not the same as 'skip' since comments are not whitespace | ||
| 279 | .space => try a.addSourceByte(' '), | ||
| 280 | .line_break => try a.addSourceByte('\n'), | ||
| 281 | .cr_line_break => try a.addSource("\r\n"), | ||
| 282 | } | ||
| 283 | try a.pegSkip(); | ||
| 284 | } | ||
| 285 | |||
| 286 | /// Root <- skip ContainerMembers eof | ||
| 287 | fn pegRoot(a: *AstSmith) SourceError!void { | ||
| 288 | try a.pegSkip(); | ||
| 289 | try a.pegContainerMembers(); | ||
| 290 | } | ||
| 291 | |||
| 292 | /// ContainerMembers <- container_doc_comment? ContainerDeclaration* (ContainerField COMMA)* | ||
| 293 | /// (ContainerField / ContainerDeclaration*) | ||
| 294 | fn pegContainerMembers(a: *AstSmith) SourceError!void { | ||
| 295 | if (a.smith.boolWeighted(63, 1)) { | ||
| 296 | try a.pegContainerDocComment(); | ||
| 297 | } | ||
| 298 | while (!a.smithListItemEos()) { | ||
| 299 | try a.pegContainerDeclaration(); | ||
| 300 | } | ||
| 301 | while (!a.smithListItemEos()) { | ||
| 302 | try a.pegContainerField(); | ||
| 303 | try a.pegToken(.comma); | ||
| 304 | } | ||
| 305 | if (a.smithListItemBool()) { | ||
| 306 | if (a.smith.value(bool)) { | ||
| 307 | try a.pegContainerField(); | ||
| 308 | } else while (true) { | ||
| 309 | try a.pegContainerDeclaration(); | ||
| 310 | if (a.smithListItemEos()) break; | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | /// ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl | ||
| 316 | fn pegContainerDeclaration(a: *AstSmith) SourceError!void { | ||
| 317 | switch (a.smith.value(enum { TestDecl, ComptimeDecl, Decl })) { | ||
| 318 | .TestDecl => try a.pegTestDecl(), | ||
| 319 | .ComptimeDecl => try a.pegComptimeDecl(), | ||
| 320 | .Decl => { | ||
| 321 | try a.pegMaybeDocComment(); | ||
| 322 | if (a.smith.value(bool)) { | ||
| 323 | try a.pegToken(.keyword_pub); | ||
| 324 | } | ||
| 325 | try a.pegDecl(); | ||
| 326 | }, | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | /// KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block | ||
| 331 | fn pegTestDecl(a: *AstSmith) SourceError!void { | ||
| 332 | try a.pegToken(.keyword_test); | ||
| 333 | switch (a.smith.value(enum { none, string, id })) { | ||
| 334 | .none => {}, | ||
| 335 | .string => try a.pegStringLiteralSingle(), | ||
| 336 | .id => try a.pegIdentifier(), | ||
| 337 | } | ||
| 338 | try a.pegBlock(); | ||
| 339 | } | ||
| 340 | |||
| 341 | /// ComptimeDecl <- KEYWORD_comptime Block | ||
| 342 | fn pegComptimeDecl(a: *AstSmith) SourceError!void { | ||
| 343 | try a.pegToken(.keyword_comptime); | ||
| 344 | try a.pegBlock(); | ||
| 345 | } | ||
| 346 | |||
| 347 | /// Decl | ||
| 348 | /// <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block) | ||
| 349 | /// / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON | ||
| 350 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? | ||
| 351 | /// GlobalVarDecl | ||
| 352 | fn pegDecl(a: *AstSmith) SourceError!void { | ||
| 353 | const Modifier = enum(u8) { | ||
| 354 | none, | ||
| 355 | @"export", | ||
| 356 | @"extern", | ||
| 357 | extern_library, | ||
| 358 | @"inline", | ||
| 359 | @"noinline", | ||
| 360 | }; | ||
| 361 | const is_fn = a.smith.value(bool); | ||
| 362 | const fn_modifiers = Smith.baselineWeights(Modifier); | ||
| 363 | const var_modifiers: []const Weight = &.{.rangeAtMost(Modifier, .none, .extern_library, 1)}; | ||
| 364 | const modifier = a.smith.valueWeighted(Modifier, if (is_fn) fn_modifiers else var_modifiers); | ||
| 365 | |||
| 366 | switch (modifier) { | ||
| 367 | .none => {}, | ||
| 368 | .@"export" => try a.pegToken(.keyword_export), | ||
| 369 | .@"extern" => try a.pegToken(.keyword_extern), | ||
| 370 | .extern_library => { | ||
| 371 | try a.pegToken(.keyword_extern); | ||
| 372 | try a.pegStringLiteralSingle(); | ||
| 373 | }, | ||
| 374 | .@"inline" => try a.pegToken(.keyword_inline), | ||
| 375 | .@"noinline" => try a.pegToken(.keyword_noinline), | ||
| 376 | } | ||
| 377 | |||
| 378 | if (is_fn) { | ||
| 379 | try a.pegFnProto(); | ||
| 380 | if (modifier == .@"extern" or modifier == .extern_library or a.smith.value(bool)) { | ||
| 381 | try a.pegToken(.semicolon); | ||
| 382 | } else { | ||
| 383 | try a.pegBlock(); | ||
| 384 | } | ||
| 385 | } else { | ||
| 386 | if (a.smith.value(bool)) try a.pegToken(.keyword_threadlocal); | ||
| 387 | try a.pegGlobalVarDecl(); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? | ||
| 392 | /// LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix | ||
| 393 | fn pegFnProto(a: *AstSmith) SourceError!void { | ||
| 394 | try a.pegToken(.keyword_fn); | ||
| 395 | if (a.smith.value(bool)) { | ||
| 396 | try a.pegIdentifier(); | ||
| 397 | } | ||
| 398 | try a.pegToken(.l_paren); | ||
| 399 | try a.pegParamDeclList(); | ||
| 400 | try a.pegToken(.r_paren); | ||
| 401 | if (a.smith.value(bool)) { | ||
| 402 | try a.pegByteAlign(); | ||
| 403 | } | ||
| 404 | if (a.smith.value(bool)) { | ||
| 405 | try a.pegAddrSpace(); | ||
| 406 | } | ||
| 407 | if (a.smith.value(bool)) { | ||
| 408 | try a.pegLinkSection(); | ||
| 409 | } | ||
| 410 | if (a.smith.value(bool)) { | ||
| 411 | try a.pegCallConv(); | ||
| 412 | } | ||
| 413 | if (a.smith.value(bool)) { | ||
| 414 | try a.pegToken(.bang); | ||
| 415 | } | ||
| 416 | try a.pegTypeExpr(); | ||
| 417 | a.not_expr_suffix = true; | ||
| 418 | } | ||
| 419 | |||
| 420 | /// VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? | ||
| 421 | /// AddrSpace? LinkSection? | ||
| 422 | fn pegVarDeclProto(a: *AstSmith) SourceError!void { | ||
| 423 | try a.pegToken(if (a.smith.value(bool)) .keyword_var else .keyword_const); | ||
| 424 | try a.pegIdentifier(); | ||
| 425 | |||
| 426 | if (a.smith.value(bool)) { | ||
| 427 | try a.pegToken(.colon); | ||
| 428 | try a.pegTypeExpr(); | ||
| 429 | } | ||
| 430 | |||
| 431 | if (a.smith.value(bool)) { | ||
| 432 | try a.pegByteAlign(); | ||
| 433 | } | ||
| 434 | |||
| 435 | if (a.smith.value(bool)) { | ||
| 436 | try a.pegAddrSpace(); | ||
| 437 | } | ||
| 438 | |||
| 439 | if (a.smith.value(bool)) { | ||
| 440 | try a.pegLinkSection(); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | /// GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON | ||
| 445 | fn pegGlobalVarDecl(a: *AstSmith) SourceError!void { | ||
| 446 | try a.pegVarDeclProto(); | ||
| 447 | if (a.smithListItemBool()) { | ||
| 448 | try a.pegToken(.equal); | ||
| 449 | try a.pegExpr(); | ||
| 450 | } | ||
| 451 | try a.pegToken(.semicolon); | ||
| 452 | } | ||
| 453 | |||
| 454 | /// ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn | ||
| 455 | /// (IDENTIFIER COLON !(IDENTIFIER COLON)) TypeExpr ByteAlign? (EQUAL Expr)? | ||
| 456 | fn pegContainerField(a: *AstSmith) SourceError!void { | ||
| 457 | try a.pegMaybeDocComment(); | ||
| 458 | if (a.smith.value(bool)) { | ||
| 459 | try a.pegToken(.keyword_comptime); | ||
| 460 | } | ||
| 461 | if (a.smith.value(bool)) { | ||
| 462 | try a.pegIdentifier(); | ||
| 463 | try a.pegToken(.colon); | ||
| 464 | } else { | ||
| 465 | a.not_token = .keyword_fn; | ||
| 466 | a.not_token_comptime = true; | ||
| 467 | a.not_label = true; | ||
| 468 | } | ||
| 469 | try a.pegTypeExpr(); | ||
| 470 | if (a.smith.value(bool)) { | ||
| 471 | try a.pegByteAlign(); | ||
| 472 | } | ||
| 473 | if (a.smith.value(bool)) { | ||
| 474 | try a.pegToken(.equal); | ||
| 475 | try a.pegExpr(); | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | /// BlockStatement | ||
| 480 | /// <- Statement | ||
| 481 | /// / KEYWORD_defer BlockExprStatement | ||
| 482 | /// / KEYWORD_errdefer BlockExprStatement | ||
| 483 | /// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement | ||
| 484 | fn pegBlockStatement(a: *AstSmith) SourceError!void { | ||
| 485 | const Kind = enum { | ||
| 486 | statement, | ||
| 487 | defer_statement, | ||
| 488 | errdefer_statement, | ||
| 489 | var_assign, | ||
| 490 | comptime_var_assign, | ||
| 491 | }; | ||
| 492 | const weights = Smith.baselineWeights(Kind) ++ &[1]Weight{.value(Kind, .statement, 4)}; | ||
| 493 | switch (a.smith.valueWeighted(Kind, weights)) { | ||
| 494 | .statement => try a.pegStatement(), | ||
| 495 | .defer_statement, .errdefer_statement => |kind| { | ||
| 496 | try a.pegToken(switch (kind) { | ||
| 497 | .defer_statement => .keyword_defer, | ||
| 498 | .errdefer_statement => .keyword_errdefer, | ||
| 499 | else => unreachable, | ||
| 500 | }); | ||
| 501 | try a.pegBlockExprStatement(); | ||
| 502 | }, | ||
| 503 | .var_assign, .comptime_var_assign => |kind| { | ||
| 504 | a.not_expr_statement = true; | ||
| 505 | if (kind == .comptime_var_assign) { | ||
| 506 | try a.pegToken(.keyword_comptime); | ||
| 507 | a.not_block_expr = true; | ||
| 508 | } | ||
| 509 | try a.pegVarAssignStatement(); | ||
| 510 | }, | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 514 | /// Statement | ||
| 515 | /// <- ExprStatement | ||
| 516 | /// / KEYWORD_suspend BlockExprStatement | ||
| 517 | /// / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON | ||
| 518 | /// | ||
| 519 | /// ExprStatement | ||
| 520 | /// <- IfStatement | ||
| 521 | /// / LabeledStatement | ||
| 522 | /// / KEYWORD_nosuspend BlockExprStatement | ||
| 523 | /// / KEYWORD_comptime BlockExpr | ||
| 524 | fn pegStatement(a: *AstSmith) SourceError!void { | ||
| 525 | switch (a.smith.value(enum { | ||
| 526 | if_statement, | ||
| 527 | labeled_statement, | ||
| 528 | comptime_block_expr, | ||
| 529 | |||
| 530 | nosuspend_statement, | ||
| 531 | suspend_statement, | ||
| 532 | assign_expr, | ||
| 533 | comptime_assign_expr, | ||
| 534 | })) { | ||
| 535 | .if_statement => try a.pegIfStatement(), | ||
| 536 | .labeled_statement => try a.pegLabeledStatement(), | ||
| 537 | .comptime_block_expr => { | ||
| 538 | try a.pegToken(.keyword_comptime); | ||
| 539 | try a.pegBlockExpr(); | ||
| 540 | }, | ||
| 541 | |||
| 542 | .nosuspend_statement, | ||
| 543 | .suspend_statement, | ||
| 544 | => |kind| { | ||
| 545 | try a.pegToken(switch (kind) { | ||
| 546 | .nosuspend_statement => .keyword_nosuspend, | ||
| 547 | .suspend_statement => .keyword_suspend, | ||
| 548 | else => unreachable, | ||
| 549 | }); | ||
| 550 | try a.pegBlockExprStatement(); | ||
| 551 | }, | ||
| 552 | .assign_expr, .comptime_assign_expr => |kind| { | ||
| 553 | a.not_expr_statement = true; | ||
| 554 | if (kind == .comptime_assign_expr) { | ||
| 555 | try a.pegToken(.keyword_comptime); | ||
| 556 | a.not_block_expr = true; | ||
| 557 | } | ||
| 558 | try a.pegAssignExpr(); | ||
| 559 | try a.pegToken(.semicolon); | ||
| 560 | }, | ||
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | /// IfStatement | ||
| 565 | /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? | ||
| 566 | /// / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | ||
| 567 | fn pegIfStatement(a: *AstSmith) SourceError!void { | ||
| 568 | try a.pegIfPrefix(); | ||
| 569 | const is_assign = a.smith.value(bool); | ||
| 570 | if (!is_assign) { | ||
| 571 | try a.pegBlockExpr(); | ||
| 572 | } else { | ||
| 573 | a.not_block_expr = true; | ||
| 574 | try a.pegAssignExpr(); | ||
| 575 | } | ||
| 576 | if (a.not_token != .keyword_else and a.smithListItemBool()) { | ||
| 577 | try a.pegToken(.keyword_else); | ||
| 578 | if (a.smith.value(bool)) { | ||
| 579 | try a.pegPayload(); | ||
| 580 | } | ||
| 581 | try a.pegStatement(); | ||
| 582 | } else if (is_assign) { | ||
| 583 | try a.pegToken(.semicolon); | ||
| 584 | } else { | ||
| 585 | a.not_token = .keyword_else; | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 589 | /// LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr) | ||
| 590 | fn pegLabeledStatement(a: *AstSmith) SourceError!void { | ||
| 591 | if (a.smith.value(bool)) { | ||
| 592 | try a.pegBlockLabel(); | ||
| 593 | } | ||
| 594 | switch (a.smith.value(enum { block, loop_statement, switch_expr })) { | ||
| 595 | .block => try a.pegBlock(), | ||
| 596 | .loop_statement => try a.pegLoopStatement(), | ||
| 597 | .switch_expr => try a.pegSwitchExpr(), | ||
| 598 | } | ||
| 599 | } | ||
| 600 | |||
| 601 | /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) | ||
| 602 | fn pegLoopStatement(a: *AstSmith) SourceError!void { | ||
| 603 | if (a.smith.value(bool)) { | ||
| 604 | try a.pegToken(.keyword_inline); | ||
| 605 | } | ||
| 606 | if (a.smith.value(bool)) { | ||
| 607 | try a.pegForStatement(); | ||
| 608 | } else { | ||
| 609 | try a.pegWhileStatement(); | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | /// ForStatement | ||
| 614 | /// <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else ) | ||
| 615 | /// / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement ) | ||
| 616 | fn pegForStatement(a: *AstSmith) SourceError!void { | ||
| 617 | try a.pegForPrefix(); | ||
| 618 | const is_assign = a.smith.value(bool); | ||
| 619 | if (!is_assign) { | ||
| 620 | try a.pegBlockExpr(); | ||
| 621 | } else { | ||
| 622 | a.not_block_expr = true; | ||
| 623 | try a.pegAssignExpr(); | ||
| 624 | } | ||
| 625 | if (a.not_token != .keyword_else and a.smithListItemBool()) { | ||
| 626 | try a.pegToken(.keyword_else); | ||
| 627 | try a.pegStatement(); | ||
| 628 | } else if (is_assign) { | ||
| 629 | try a.pegToken(.semicolon); | ||
| 630 | } else { | ||
| 631 | a.not_token = .keyword_else; | ||
| 632 | } | ||
| 633 | } | ||
| 634 | |||
| 635 | /// WhileStatement | ||
| 636 | /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? | ||
| 637 | /// / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | ||
| 638 | fn pegWhileStatement(a: *AstSmith) SourceError!void { | ||
| 639 | try a.pegWhilePrefix(); | ||
| 640 | const is_assign = a.smith.value(bool); | ||
| 641 | if (!is_assign) { | ||
| 642 | try a.pegBlockExpr(); | ||
| 643 | } else { | ||
| 644 | a.not_block_expr = true; | ||
| 645 | try a.pegAssignExpr(); | ||
| 646 | } | ||
| 647 | if (a.not_token != .keyword_else and a.smithListItemBool()) { | ||
| 648 | try a.pegToken(.keyword_else); | ||
| 649 | if (a.smith.value(bool)) { | ||
| 650 | try a.pegPayload(); | ||
| 651 | } | ||
| 652 | try a.pegStatement(); | ||
| 653 | } else if (is_assign) { | ||
| 654 | try a.pegToken(.semicolon); | ||
| 655 | } else { | ||
| 656 | a.not_token = .keyword_else; | ||
| 657 | } | ||
| 658 | } | ||
| 659 | |||
| 660 | /// BlockExprStatement | ||
| 661 | /// <- BlockExpr | ||
| 662 | /// / !BlockExpr AssignExpr SEMICOLON | ||
| 663 | fn pegBlockExprStatement(a: *AstSmith) SourceError!void { | ||
| 664 | if (a.smith.value(bool)) { | ||
| 665 | try a.pegBlockExpr(); | ||
| 666 | } else { | ||
| 667 | a.not_block_expr = true; | ||
| 668 | try a.pegAssignExpr(); | ||
| 669 | try a.pegToken(.semicolon); | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | /// BlockExpr <- BlockLabel? Block | ||
| 674 | fn pegBlockExpr(a: *AstSmith) SourceError!void { | ||
| 675 | if (a.smith.value(bool)) { | ||
| 676 | try a.pegBlockLabel(); | ||
| 677 | } | ||
| 678 | try a.pegBlock(); | ||
| 679 | } | ||
| 680 | |||
| 681 | /// VarAssignStatement <- (Expr / VarDeclProto) (COMMA (Expr / VarDeclProto))* EQUAL Expr SEMICOLON | ||
| 682 | fn pegVarAssignStatement(a: *AstSmith) SourceError!void { | ||
| 683 | while (true) { | ||
| 684 | if (a.smith.value(bool)) { | ||
| 685 | try a.pegVarDeclProto(); | ||
| 686 | } else { | ||
| 687 | try a.pegExpr(); | ||
| 688 | } | ||
| 689 | |||
| 690 | if (a.smithListItemEos()) { | ||
| 691 | break; | ||
| 692 | } else { | ||
| 693 | try a.pegToken(.comma); | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | try a.pegToken(.equal); | ||
| 698 | try a.pegExpr(); | ||
| 699 | try a.pegToken(.semicolon); | ||
| 700 | } | ||
| 701 | |||
| 702 | /// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)? | ||
| 703 | fn pegAssignExpr(a: *AstSmith) SourceError!void { | ||
| 704 | try a.pegExpr(); | ||
| 705 | if (a.smith.value(bool)) { | ||
| 706 | if (!a.smithListItemBool()) { | ||
| 707 | try a.pegAssignOp(); | ||
| 708 | } else { | ||
| 709 | while (true) { | ||
| 710 | try a.pegToken(.comma); | ||
| 711 | try a.pegExpr(); | ||
| 712 | if (a.smithListItemEos()) break; | ||
| 713 | } | ||
| 714 | try a.pegToken(.equal); | ||
| 715 | } | ||
| 716 | try a.pegExpr(); | ||
| 717 | } | ||
| 718 | } | ||
| 719 | |||
| 720 | /// SingleAssignExpr <- Expr (AssignOp Expr)? | ||
| 721 | fn pegSingleAssignExpr(a: *AstSmith) SourceError!void { | ||
| 722 | try a.pegExpr(); | ||
| 723 | if (a.smith.value(bool)) { | ||
| 724 | try a.pegAssignOp(); | ||
| 725 | try a.pegExpr(); | ||
| 726 | } | ||
| 727 | } | ||
| 728 | |||
| 729 | /// Expr <- BoolOrExpr | ||
| 730 | const pegExpr = pegBoolOrExpr; | ||
| 731 | |||
| 732 | /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)* | ||
| 733 | fn pegBoolOrExpr(a: *AstSmith) SourceError!void { | ||
| 734 | try a.pegBoolAndExpr(); | ||
| 735 | while (!a.not_expr_suffix and !a.smithListItemEos()) { | ||
| 736 | try a.pegTokenWhitespaceAround(.keyword_or); | ||
| 737 | try a.pegBoolAndExpr(); | ||
| 738 | } | ||
| 739 | } | ||
| 740 | |||
| 741 | /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)* | ||
| 742 | fn pegBoolAndExpr(a: *AstSmith) SourceError!void { | ||
| 743 | try a.pegCompareExpr(); | ||
| 744 | while (!a.not_expr_suffix and !a.smithListItemEos()) { | ||
| 745 | try a.pegTokenWhitespaceAround(.keyword_and); | ||
| 746 | try a.pegCompareExpr(); | ||
| 747 | } | ||
| 748 | } | ||
| 749 | |||
| 750 | /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? | ||
| 751 | fn pegCompareExpr(a: *AstSmith) SourceError!void { | ||
| 752 | try a.pegBitwiseExpr(); | ||
| 753 | if (!a.not_expr_suffix and a.smithListItemBool()) { | ||
| 754 | try a.pegCompareOp(); | ||
| 755 | try a.pegBitwiseExpr(); | ||
| 756 | } | ||
| 757 | } | ||
| 758 | |||
| 759 | /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* | ||
| 760 | fn pegBitwiseExpr(a: *AstSmith) SourceError!void { | ||
| 761 | try a.pegBitShiftExpr(); | ||
| 762 | while (!a.not_expr_suffix and !a.smithListItemEos()) { | ||
| 763 | try a.pegBitwiseOp(); | ||
| 764 | try a.pegBitShiftExpr(); | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* | ||
| 769 | fn pegBitShiftExpr(a: *AstSmith) SourceError!void { | ||
| 770 | try a.pegAdditionExpr(); | ||
| 771 | while (!a.not_expr_suffix and !a.smithListItemEos()) { | ||
| 772 | try a.pegBitShiftOp(); | ||
| 773 | try a.pegAdditionExpr(); | ||
| 774 | } | ||
| 775 | } | ||
| 776 | |||
| 777 | /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* | ||
| 778 | fn pegAdditionExpr(a: *AstSmith) SourceError!void { | ||
| 779 | try a.pegMultiplyExpr(); | ||
| 780 | while (!a.not_expr_suffix and !a.smithListItemEos()) { | ||
| 781 | try a.pegAdditionOp(); | ||
| 782 | try a.pegMultiplyExpr(); | ||
| 783 | } | ||
| 784 | } | ||
| 785 | |||
| 786 | /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* | ||
| 787 | fn pegMultiplyExpr(a: *AstSmith) SourceError!void { | ||
| 788 | try a.pegPrefixExpr(); | ||
| 789 | while (!a.not_expr_suffix and !a.smithListItemEos()) { | ||
| 790 | try a.pegMultiplyOp(); | ||
| 791 | try a.pegPrefixExpr(); | ||
| 792 | } | ||
| 793 | } | ||
| 794 | |||
| 795 | /// PrefixExpr <- PrefixOp* PrimaryExpr | ||
| 796 | fn pegPrefixExpr(a: *AstSmith) SourceError!void { | ||
| 797 | while (!a.smithListItemEos()) { | ||
| 798 | try a.pegPrefixOp(); | ||
| 799 | } | ||
| 800 | try a.pegPrimaryExpr(); | ||
| 801 | } | ||
| 802 | |||
| 803 | /// PrimaryExpr | ||
| 804 | /// <- AsmExpr | ||
| 805 | /// / IfExpr | ||
| 806 | /// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) | ||
| 807 | /// / KEYWORD_comptime Expr !ExprSuffix | ||
| 808 | /// / KEYWORD_nosuspend Expr !ExprSuffix | ||
| 809 | /// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) | ||
| 810 | /// / KEYWORD_resume Expr !ExprSuffix | ||
| 811 | /// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart) | ||
| 812 | /// / BlockLabel? LoopExpr | ||
| 813 | /// / Block | ||
| 814 | /// / CurlySuffixExpr | ||
| 815 | fn pegPrimaryExpr(a: *AstSmith) SourceError!void { | ||
| 816 | const Kind = enum(u8) { | ||
| 817 | curly_suffix_expr, | ||
| 818 | @"return", | ||
| 819 | @"continue", | ||
| 820 | @"break", | ||
| 821 | block, | ||
| 822 | asm_expr, | ||
| 823 | // Always contain more expressions | ||
| 824 | if_expr, | ||
| 825 | loop_expr, | ||
| 826 | @"resume", | ||
| 827 | @"comptime", | ||
| 828 | @"nosuspend", | ||
| 829 | }; | ||
| 830 | |||
| 831 | switch (a.smith.valueWeighted(Kind, &.{ | ||
| 832 | .value(Kind, .curly_suffix_expr, 75), | ||
| 833 | .rangeAtMost(Kind, .@"return", .asm_expr, 4), | ||
| 834 | .rangeAtMost(Kind, .if_expr, .@"nosuspend", 1), | ||
| 835 | })) { | ||
| 836 | .curly_suffix_expr => try a.pegCurlySuffixExpr(), | ||
| 837 | |||
| 838 | .block => if (a.not_labelable_expr != .expr and !a.not_block_expr and !a.not_expr_statement) { | ||
| 839 | try a.pegBlock(); | ||
| 840 | } else { | ||
| 841 | // Group | ||
| 842 | try a.pegToken(.l_paren); | ||
| 843 | try a.pegBlock(); | ||
| 844 | try a.pegToken(.r_paren); | ||
| 845 | }, | ||
| 846 | .asm_expr => try a.pegAsmExpr(), | ||
| 847 | .if_expr => if (!a.not_expr_statement) { | ||
| 848 | try a.pegIfExpr(); | ||
| 849 | } else { | ||
| 850 | // Group | ||
| 851 | try a.pegToken(.l_paren); | ||
| 852 | try a.pegIfExpr(); | ||
| 853 | try a.pegToken(.r_paren); | ||
| 854 | }, | ||
| 855 | .loop_expr => { | ||
| 856 | const group = a.not_labelable_expr == .expr or a.not_expr_statement; | ||
| 857 | if (group) try a.pegToken(.l_paren); | ||
| 858 | if (!a.not_label and a.not_token != .identifier and a.smith.value(bool)) { | ||
| 859 | try a.pegBlockLabel(); | ||
| 860 | } | ||
| 861 | try a.pegLoopExpr(); | ||
| 862 | if (group) try a.pegToken(.r_paren); | ||
| 863 | }, | ||
| 864 | |||
| 865 | .@"return", | ||
| 866 | .@"comptime", | ||
| 867 | .@"nosuspend", | ||
| 868 | .@"resume", | ||
| 869 | .@"break", | ||
| 870 | .@"continue", | ||
| 871 | => |t| { | ||
| 872 | const group = a.not_expr_statement and (t == .@"nosuspend" or t == .@"comptime"); | ||
| 873 | if (group) try a.pegToken(.l_paren); | ||
| 874 | |||
| 875 | const kw: Token.Tag, const label, const expr = switch (t) { | ||
| 876 | .@"return" => .{ .keyword_return, false, a.smithListItemBool() }, | ||
| 877 | .@"comptime" => .{ .keyword_comptime, false, true }, | ||
| 878 | .@"nosuspend" => .{ .keyword_nosuspend, false, true }, | ||
| 879 | .@"resume" => .{ .keyword_resume, false, true }, | ||
| 880 | .@"break" => .{ .keyword_break, a.smith.value(bool), a.smithListItemBool() }, | ||
| 881 | .@"continue" => .{ .keyword_continue, a.smith.value(bool), a.smithListItemBool() }, | ||
| 882 | else => unreachable, | ||
| 883 | }; | ||
| 884 | try a.pegToken(kw); | ||
| 885 | if (label) { | ||
| 886 | try a.pegBreakLabel(); | ||
| 887 | } else { | ||
| 888 | a.not_break_label = true; | ||
| 889 | } | ||
| 890 | if (expr) { | ||
| 891 | try a.pegExpr(); | ||
| 892 | a.not_expr_suffix = true; | ||
| 893 | } else { | ||
| 894 | a.not_token = .asterisk; | ||
| 895 | } | ||
| 896 | |||
| 897 | if (group) try a.pegToken(.r_paren); | ||
| 898 | }, | ||
| 899 | } | ||
| 900 | } | ||
| 901 | |||
| 902 | /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix | ||
| 903 | fn pegIfExpr(a: *AstSmith) SourceError!void { | ||
| 904 | try a.pegIfPrefix(); | ||
| 905 | try a.pegExpr(); | ||
| 906 | const Else = enum { none, @"else", else_payload }; | ||
| 907 | switch (if (a.not_token != .keyword_else) a.smith.value(Else) else .none) { | ||
| 908 | .none => a.not_token = .keyword_else, | ||
| 909 | .@"else" => { | ||
| 910 | try a.pegToken(.keyword_else); | ||
| 911 | try a.pegExpr(); | ||
| 912 | }, | ||
| 913 | .else_payload => { | ||
| 914 | try a.pegToken(.keyword_else); | ||
| 915 | try a.pegPayload(); | ||
| 916 | try a.pegExpr(); | ||
| 917 | }, | ||
| 918 | } | ||
| 919 | a.not_expr_suffix = true; | ||
| 920 | } | ||
| 921 | |||
| 922 | /// Block <- LBRACE Statement* RBRACE | ||
| 923 | fn pegBlock(a: *AstSmith) SourceError!void { | ||
| 924 | try a.pegToken(.l_brace); | ||
| 925 | while (!a.smithListItemEos()) { | ||
| 926 | try a.pegBlockStatement(); | ||
| 927 | } | ||
| 928 | try a.pegToken(.r_brace); | ||
| 929 | } | ||
| 930 | |||
| 931 | /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) | ||
| 932 | fn pegLoopExpr(a: *AstSmith) SourceError!void { | ||
| 933 | if (a.smith.value(bool)) { | ||
| 934 | try a.pegToken(.keyword_inline); | ||
| 935 | } | ||
| 936 | |||
| 937 | if (a.smith.value(bool)) { | ||
| 938 | try a.pegForExpr(); | ||
| 939 | } else { | ||
| 940 | try a.pegWhileExpr(); | ||
| 941 | } | ||
| 942 | } | ||
| 943 | |||
| 944 | /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix | ||
| 945 | fn pegForExpr(a: *AstSmith) SourceError!void { | ||
| 946 | try a.pegForPrefix(); | ||
| 947 | try a.pegExpr(); | ||
| 948 | if (a.not_token != .keyword_else and a.smith.value(bool)) { | ||
| 949 | try a.pegToken(.keyword_else); | ||
| 950 | try a.pegExpr(); | ||
| 951 | } else { | ||
| 952 | a.not_token = .keyword_else; | ||
| 953 | } | ||
| 954 | a.not_expr_suffix = true; | ||
| 955 | } | ||
| 956 | |||
| 957 | /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix | ||
| 958 | fn pegWhileExpr(a: *AstSmith) SourceError!void { | ||
| 959 | try a.pegWhilePrefix(); | ||
| 960 | try a.pegExpr(); | ||
| 961 | const Else = enum { none, @"else", else_payload }; | ||
| 962 | switch (if (a.not_token != .keyword_else) a.smith.value(Else) else .none) { | ||
| 963 | .none => a.not_token = .keyword_else, | ||
| 964 | .@"else" => { | ||
| 965 | try a.pegToken(.keyword_else); | ||
| 966 | try a.pegExpr(); | ||
| 967 | }, | ||
| 968 | .else_payload => { | ||
| 969 | try a.pegToken(.keyword_else); | ||
| 970 | try a.pegPayload(); | ||
| 971 | try a.pegExpr(); | ||
| 972 | }, | ||
| 973 | } | ||
| 974 | a.not_expr_suffix = true; | ||
| 975 | } | ||
| 976 | |||
| 977 | /// CurlySuffixExpr <- TypeExpr InitList? | ||
| 978 | fn pegCurlySuffixExpr(a: *AstSmith) SourceError!void { | ||
| 979 | try a.pegTypeExpr(); | ||
| 980 | if (!a.not_expr_suffix and a.smith.value(bool)) { | ||
| 981 | try a.pegInitList(); | ||
| 982 | } | ||
| 983 | } | ||
| 984 | |||
| 985 | /// InitList | ||
| 986 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | ||
| 987 | /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE | ||
| 988 | /// / LBRACE RBRACE | ||
| 989 | fn pegInitList(a: *AstSmith) SourceError!void { | ||
| 990 | try a.pegToken(.l_brace); | ||
| 991 | if (a.smithListItemBool()) { | ||
| 992 | if (a.smith.value(bool)) { | ||
| 993 | try a.pegFieldInit(); | ||
| 994 | while (!a.smithListItemEos()) { | ||
| 995 | try a.pegToken(.comma); | ||
| 996 | try a.pegFieldInit(); | ||
| 997 | } | ||
| 998 | } else { | ||
| 999 | try a.pegExpr(); | ||
| 1000 | while (!a.smithListItemEos()) { | ||
| 1001 | try a.pegToken(.comma); | ||
| 1002 | try a.pegExpr(); | ||
| 1003 | } | ||
| 1004 | } | ||
| 1005 | if (a.smith.value(bool)) { | ||
| 1006 | try a.pegToken(.comma); | ||
| 1007 | } | ||
| 1008 | } | ||
| 1009 | try a.pegToken(.r_brace); | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | /// PrefixTypeOp* ErrorUnionExpr | ||
| 1013 | fn pegTypeExpr(a: *AstSmith) SourceError!void { | ||
| 1014 | while (!a.smithListItemEos()) { | ||
| 1015 | try a.pegPrefixTypeOp(); | ||
| 1016 | } | ||
| 1017 | try a.pegErrorUnionExpr(); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? | ||
| 1021 | fn pegErrorUnionExpr(a: *AstSmith) SourceError!void { | ||
| 1022 | try a.pegSuffixExpr(); | ||
| 1023 | if (!a.not_expr_suffix and a.smithListItemBool()) { | ||
| 1024 | try a.pegToken(.bang); | ||
| 1025 | try a.pegTypeExpr(); | ||
| 1026 | } | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | /// SuffixExpr | ||
| 1030 | /// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* | ||
| 1031 | fn pegSuffixExpr(a: *AstSmith) SourceError!void { | ||
| 1032 | try a.pegPrimaryTypeExpr(); | ||
| 1033 | while (!a.not_expr_suffix and !a.smithListItemEos()) { | ||
| 1034 | if (a.smith.value(bool)) { | ||
| 1035 | try a.pegSuffixOp(); | ||
| 1036 | } else { | ||
| 1037 | try a.pegFnCallArguments(); | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | /// PrimaryTypeExpr | ||
| 1043 | /// <- BUILTINIDENTIFIER FnCallArguments | ||
| 1044 | /// / CHAR_LITERAL | ||
| 1045 | /// / ContainerDecl | ||
| 1046 | /// / DOT IDENTIFIER | ||
| 1047 | /// / DOT InitList | ||
| 1048 | /// / ErrorSetDecl | ||
| 1049 | /// / FLOAT | ||
| 1050 | /// / FnProto | ||
| 1051 | /// / GroupedExpr | ||
| 1052 | /// / LabeledTypeExpr | ||
| 1053 | /// / IDENTIFIER !(COLON LabelableExpr) | ||
| 1054 | /// / IfTypeExpr | ||
| 1055 | /// / INTEGER | ||
| 1056 | /// / KEYWORD_comptime TypeExpr !ExprSuffix | ||
| 1057 | /// / KEYWORD_error DOT IDENTIFIER | ||
| 1058 | /// / KEYWORD_anyframe | ||
| 1059 | /// / KEYWORD_unreachable | ||
| 1060 | /// / STRINGLITERAL | ||
| 1061 | fn pegPrimaryTypeExpr(a: *AstSmith) SourceError!void { | ||
| 1062 | const Kind = enum(u8) { | ||
| 1063 | identifier, | ||
| 1064 | float, | ||
| 1065 | integer, | ||
| 1066 | char_literal, | ||
| 1067 | string_literal, | ||
| 1068 | enum_literal, | ||
| 1069 | error_literal, | ||
| 1070 | unreachable_type, | ||
| 1071 | anyframe_type, | ||
| 1072 | |||
| 1073 | // Containing zero or more expressions | ||
| 1074 | builtin_call, | ||
| 1075 | array_literal, | ||
| 1076 | container_decl, | ||
| 1077 | fn_proto, | ||
| 1078 | error_set, | ||
| 1079 | |||
| 1080 | // Containing one or more epressions | ||
| 1081 | grouped, | ||
| 1082 | labeled_type_expr, | ||
| 1083 | if_type_expr, | ||
| 1084 | comptime_expr, | ||
| 1085 | }; | ||
| 1086 | |||
| 1087 | switch (a.smith.valueWeighted(Kind, &.{ | ||
| 1088 | .rangeAtMost(Kind, .identifier, .anyframe_type, 5), | ||
| 1089 | .rangeAtMost(Kind, .builtin_call, .error_set, 2), | ||
| 1090 | .rangeAtMost(Kind, .grouped, .comptime_expr, 1), | ||
| 1091 | })) { | ||
| 1092 | .identifier => if (a.not_token != .identifier) { | ||
| 1093 | try a.pegIdentifier(); | ||
| 1094 | a.not_labelable_expr = .colon; | ||
| 1095 | } else { | ||
| 1096 | // Group | ||
| 1097 | try a.pegToken(.l_paren); | ||
| 1098 | try a.pegIdentifier(); | ||
| 1099 | try a.pegToken(.r_paren); | ||
| 1100 | }, | ||
| 1101 | .float => try a.pegFloat(), | ||
| 1102 | .integer => try a.pegInteger(), | ||
| 1103 | .char_literal => try a.pegCharLiteral(), | ||
| 1104 | .string_literal => try a.pegStringLiteral(), | ||
| 1105 | .enum_literal => { | ||
| 1106 | try a.pegToken(.period); | ||
| 1107 | try a.pegIdentifier(); | ||
| 1108 | }, | ||
| 1109 | .error_literal => { | ||
| 1110 | try a.pegToken(.keyword_error); | ||
| 1111 | try a.pegToken(.period); | ||
| 1112 | try a.pegIdentifier(); | ||
| 1113 | }, | ||
| 1114 | .unreachable_type => try a.pegToken(.keyword_unreachable), | ||
| 1115 | .anyframe_type => try a.pegToken(.keyword_anyframe), | ||
| 1116 | |||
| 1117 | .builtin_call => { | ||
| 1118 | try a.pegBuiltinIdentifier(); | ||
| 1119 | try a.pegFnCallArguments(); | ||
| 1120 | }, | ||
| 1121 | .array_literal => { | ||
| 1122 | try a.pegToken(.period); | ||
| 1123 | try a.pegInitList(); | ||
| 1124 | }, | ||
| 1125 | .container_decl => try a.pegContainerDecl(), | ||
| 1126 | .fn_proto => if (a.not_token != .keyword_fn) { | ||
| 1127 | try a.pegFnProto(); | ||
| 1128 | } else { | ||
| 1129 | // Group | ||
| 1130 | try a.pegToken(.l_paren); | ||
| 1131 | try a.pegFnProto(); | ||
| 1132 | try a.pegToken(.r_paren); | ||
| 1133 | }, | ||
| 1134 | .error_set => try a.pegErrorSetDecl(), | ||
| 1135 | |||
| 1136 | .grouped => try a.pegGroupedExpr(), | ||
| 1137 | .labeled_type_expr => try a.pegLabeledTypeExpr(), | ||
| 1138 | .if_type_expr => if (!a.not_expr_statement) { | ||
| 1139 | try a.pegIfTypeExpr(); | ||
| 1140 | } else { | ||
| 1141 | // Group | ||
| 1142 | try a.pegToken(.l_paren); | ||
| 1143 | try a.pegIfTypeExpr(); | ||
| 1144 | try a.pegToken(.r_paren); | ||
| 1145 | }, | ||
| 1146 | .comptime_expr => if (!a.not_token_comptime and !a.not_expr_statement) { | ||
| 1147 | try a.pegToken(.keyword_comptime); | ||
| 1148 | try a.pegTypeExpr(); | ||
| 1149 | } else { | ||
| 1150 | // Group | ||
| 1151 | try a.pegToken(.l_paren); | ||
| 1152 | try a.pegToken(.keyword_comptime); | ||
| 1153 | try a.pegTypeExpr(); | ||
| 1154 | try a.pegToken(.r_paren); | ||
| 1155 | }, | ||
| 1156 | } | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto | ||
| 1160 | fn pegContainerDecl(a: *AstSmith) SourceError!void { | ||
| 1161 | switch (a.smith.value(enum { auto, @"extern", @"packed" })) { | ||
| 1162 | .auto => {}, | ||
| 1163 | .@"extern" => try a.pegToken(.keyword_extern), | ||
| 1164 | .@"packed" => try a.pegToken(.keyword_packed), | ||
| 1165 | } | ||
| 1166 | try a.pegContainerDeclAuto(); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE | ||
| 1170 | fn pegErrorSetDecl(a: *AstSmith) SourceError!void { | ||
| 1171 | try a.pegToken(.keyword_error); | ||
| 1172 | try a.pegToken(.l_brace); | ||
| 1173 | try a.pegIdentifierList(); | ||
| 1174 | try a.pegToken(.r_brace); | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | /// GroupedExpr <- LPAREN Expr RPAREN | ||
| 1178 | fn pegGroupedExpr(a: *AstSmith) SourceError!void { | ||
| 1179 | try a.pegToken(.l_paren); | ||
| 1180 | try a.pegExpr(); | ||
| 1181 | try a.pegToken(.r_paren); | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix | ||
| 1185 | fn pegIfTypeExpr(a: *AstSmith) SourceError!void { | ||
| 1186 | try a.pegIfPrefix(); | ||
| 1187 | try a.pegTypeExpr(); | ||
| 1188 | const Else = enum { none, @"else", else_payload }; | ||
| 1189 | switch (if (a.not_token != .keyword_else) a.smith.value(Else) else .none) { | ||
| 1190 | .none => a.not_token = .keyword_else, | ||
| 1191 | .@"else" => { | ||
| 1192 | try a.pegToken(.keyword_else); | ||
| 1193 | try a.pegTypeExpr(); | ||
| 1194 | }, | ||
| 1195 | .else_payload => { | ||
| 1196 | try a.pegToken(.keyword_else); | ||
| 1197 | try a.pegPayload(); | ||
| 1198 | try a.pegTypeExpr(); | ||
| 1199 | }, | ||
| 1200 | } | ||
| 1201 | a.not_expr_suffix = true; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | /// LabeledTypeExpr | ||
| 1205 | /// <- BlockLabel Block | ||
| 1206 | /// / BlockLabel? LoopTypeExpr | ||
| 1207 | /// / BlockLabel? SwitchExpr | ||
| 1208 | fn pegLabeledTypeExpr(a: *AstSmith) SourceError!void { | ||
| 1209 | const kind = a.smith.value(enum { block, loop, @"switch" }); | ||
| 1210 | const not_any = a.not_labelable_expr == .expr or a.not_expr_statement; | ||
| 1211 | const no_label = a.not_label or a.not_token == .identifier; | ||
| 1212 | const no_block = no_label or a.not_block_expr; | ||
| 1213 | const group = not_any or (kind == .block and no_block); | ||
| 1214 | if (group) try a.pegToken(.l_paren); | ||
| 1215 | |||
| 1216 | switch (kind) { | ||
| 1217 | .block => { | ||
| 1218 | try a.pegBlockLabel(); | ||
| 1219 | try a.pegBlock(); | ||
| 1220 | }, | ||
| 1221 | .loop => { | ||
| 1222 | if (!no_label and a.smith.value(bool)) { | ||
| 1223 | try a.pegBlockLabel(); | ||
| 1224 | } | ||
| 1225 | try a.pegLoopTypeExpr(); | ||
| 1226 | }, | ||
| 1227 | .@"switch" => { | ||
| 1228 | if (!no_label and a.smith.value(bool)) { | ||
| 1229 | try a.pegBlockLabel(); | ||
| 1230 | } | ||
| 1231 | try a.pegSwitchExpr(); | ||
| 1232 | }, | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | if (group) try a.pegToken(.r_paren); | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) | ||
| 1239 | fn pegLoopTypeExpr(a: *AstSmith) SourceError!void { | ||
| 1240 | if (a.smith.value(bool)) { | ||
| 1241 | try a.pegToken(.keyword_inline); | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | if (a.smith.value(bool)) { | ||
| 1245 | try a.pegForTypeExpr(); | ||
| 1246 | } else { | ||
| 1247 | try a.pegWhileTypeExpr(); | ||
| 1248 | } | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix | ||
| 1252 | fn pegForTypeExpr(a: *AstSmith) SourceError!void { | ||
| 1253 | try a.pegForPrefix(); | ||
| 1254 | try a.pegTypeExpr(); | ||
| 1255 | if (a.not_token != .keyword_else and a.smith.value(bool)) { | ||
| 1256 | try a.pegToken(.keyword_else); | ||
| 1257 | try a.pegTypeExpr(); | ||
| 1258 | } else { | ||
| 1259 | a.not_token = .keyword_else; | ||
| 1260 | } | ||
| 1261 | a.not_expr_suffix = true; | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix | ||
| 1265 | fn pegWhileTypeExpr(a: *AstSmith) SourceError!void { | ||
| 1266 | try a.pegWhilePrefix(); | ||
| 1267 | try a.pegTypeExpr(); | ||
| 1268 | const Else = enum { none, @"else", else_payload }; | ||
| 1269 | switch (if (a.not_token != .keyword_else) a.smith.value(Else) else .none) { | ||
| 1270 | .none => a.not_token = .keyword_else, | ||
| 1271 | .@"else" => { | ||
| 1272 | try a.pegToken(.keyword_else); | ||
| 1273 | try a.pegTypeExpr(); | ||
| 1274 | }, | ||
| 1275 | .else_payload => { | ||
| 1276 | try a.pegToken(.keyword_else); | ||
| 1277 | try a.pegPayload(); | ||
| 1278 | try a.pegTypeExpr(); | ||
| 1279 | }, | ||
| 1280 | } | ||
| 1281 | a.not_expr_suffix = true; | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE | ||
| 1285 | fn pegSwitchExpr(a: *AstSmith) SourceError!void { | ||
| 1286 | try a.pegToken(.keyword_switch); | ||
| 1287 | try a.pegToken(.l_paren); | ||
| 1288 | try a.pegExpr(); | ||
| 1289 | try a.pegToken(.r_paren); | ||
| 1290 | |||
| 1291 | try a.pegToken(.l_brace); | ||
| 1292 | try a.pegSwitchProngList(); | ||
| 1293 | try a.pegToken(.r_brace); | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN | ||
| 1297 | fn pegAsmExpr(a: *AstSmith) SourceError!void { | ||
| 1298 | try a.pegToken(.keyword_asm); | ||
| 1299 | if (a.smith.value(bool)) { | ||
| 1300 | try a.pegToken(.keyword_volatile); | ||
| 1301 | } | ||
| 1302 | try a.pegToken(.l_paren); | ||
| 1303 | try a.pegExpr(); | ||
| 1304 | if (a.smith.value(bool)) { | ||
| 1305 | try a.pegAsmOutput(); | ||
| 1306 | } | ||
| 1307 | try a.pegToken(.r_paren); | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | /// AsmOutput <- COLON AsmOutputList AsmInput? | ||
| 1311 | fn pegAsmOutput(a: *AstSmith) SourceError!void { | ||
| 1312 | try a.pegToken(.colon); | ||
| 1313 | try a.pegAsmOutputList(); | ||
| 1314 | if (a.smith.value(bool)) { | ||
| 1315 | try a.pegAsmInput(); | ||
| 1316 | } | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN | ||
| 1320 | fn pegAsmOutputItem(a: *AstSmith) SourceError!void { | ||
| 1321 | try a.pegToken(.l_bracket); | ||
| 1322 | try a.pegIdentifier(); | ||
| 1323 | try a.pegToken(.r_bracket); | ||
| 1324 | try a.pegStringLiteralSingle(); | ||
| 1325 | try a.pegToken(.l_paren); | ||
| 1326 | if (a.smith.value(bool)) { | ||
| 1327 | try a.pegToken(.arrow); | ||
| 1328 | try a.pegTypeExpr(); | ||
| 1329 | } else { | ||
| 1330 | try a.pegIdentifier(); | ||
| 1331 | } | ||
| 1332 | try a.pegToken(.r_paren); | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | /// AsmInput <- COLON AsmInputList AsmClobbers? | ||
| 1336 | fn pegAsmInput(a: *AstSmith) SourceError!void { | ||
| 1337 | try a.pegToken(.colon); | ||
| 1338 | try a.pegAsmInputList(); | ||
| 1339 | if (a.smith.value(bool)) { | ||
| 1340 | try a.pegAsmClobbers(); | ||
| 1341 | } | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN | ||
| 1345 | fn pegAsmInputItem(a: *AstSmith) SourceError!void { | ||
| 1346 | try a.pegToken(.l_bracket); | ||
| 1347 | try a.pegIdentifier(); | ||
| 1348 | try a.pegToken(.r_bracket); | ||
| 1349 | try a.pegStringLiteralSingle(); | ||
| 1350 | try a.pegToken(.l_paren); | ||
| 1351 | try a.pegExpr(); | ||
| 1352 | try a.pegToken(.r_paren); | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | /// AsmClobbers <- COLON Expr | ||
| 1356 | fn pegAsmClobbers(a: *AstSmith) SourceError!void { | ||
| 1357 | try a.pegToken(.colon); | ||
| 1358 | try a.pegExpr(); | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | /// BreakLabel <- COLON IDENTIFIER | ||
| 1362 | fn pegBreakLabel(a: *AstSmith) SourceError!void { | ||
| 1363 | try a.pegToken(.colon); | ||
| 1364 | try a.pegIdentifier(); | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | /// BlockLabel <- IDENTIFIER COLON | ||
| 1368 | fn pegBlockLabel(a: *AstSmith) SourceError!void { | ||
| 1369 | try a.pegIdentifier(); | ||
| 1370 | try a.pegToken(.colon); | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | /// FieldInit <- DOT IDENTIFIER EQUAL Expr | ||
| 1374 | fn pegFieldInit(a: *AstSmith) SourceError!void { | ||
| 1375 | try a.pegToken(.period); | ||
| 1376 | try a.pegIdentifier(); | ||
| 1377 | try a.pegToken(.equal); | ||
| 1378 | try a.pegExpr(); | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN | ||
| 1382 | fn pegWhileContinueExpr(a: *AstSmith) SourceError!void { | ||
| 1383 | try a.pegToken(.colon); | ||
| 1384 | try a.pegToken(.l_paren); | ||
| 1385 | try a.pegAssignExpr(); | ||
| 1386 | try a.pegToken(.r_paren); | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN | ||
| 1390 | fn pegLinkSection(a: *AstSmith) SourceError!void { | ||
| 1391 | try a.pegToken(.keyword_linksection); | ||
| 1392 | try a.pegToken(.l_paren); | ||
| 1393 | try a.pegExpr(); | ||
| 1394 | try a.pegToken(.r_paren); | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | /// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN | ||
| 1398 | fn pegAddrSpace(a: *AstSmith) SourceError!void { | ||
| 1399 | try a.pegToken(.keyword_addrspace); | ||
| 1400 | try a.pegToken(.l_paren); | ||
| 1401 | try a.pegExpr(); | ||
| 1402 | try a.pegToken(.r_paren); | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN | ||
| 1406 | fn pegCallConv(a: *AstSmith) SourceError!void { | ||
| 1407 | try a.pegToken(.keyword_callconv); | ||
| 1408 | try a.pegToken(.l_paren); | ||
| 1409 | try a.pegExpr(); | ||
| 1410 | try a.pegToken(.r_paren); | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | /// ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)? | ||
| 1414 | /// ((IDENTIFIER COLON) / !KEYWORD_comptime !(IDENTIFIER COLON)) | ||
| 1415 | /// ParamType | ||
| 1416 | fn pegParamDecl(a: *AstSmith) SourceError!void { | ||
| 1417 | try a.pegMaybeDocComment(); | ||
| 1418 | const modifier = a.smith.value(enum { none, @"noalias", @"comptime" }); | ||
| 1419 | switch (modifier) { | ||
| 1420 | .none => a.not_token_comptime = true, | ||
| 1421 | .@"noalias" => try a.pegToken(.keyword_noalias), | ||
| 1422 | .@"comptime" => try a.pegToken(.keyword_comptime), | ||
| 1423 | } | ||
| 1424 | if (a.smith.value(bool)) { | ||
| 1425 | try a.pegIdentifier(); | ||
| 1426 | try a.pegToken(.colon); | ||
| 1427 | } else { | ||
| 1428 | a.not_label = true; | ||
| 1429 | } | ||
| 1430 | try a.pegParamType(); | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | /// ParamType | ||
| 1434 | /// <- KEYWORD_anytype | ||
| 1435 | /// / TypeExpr | ||
| 1436 | fn pegParamType(a: *AstSmith) SourceError!void { | ||
| 1437 | if (a.smith.value(bool)) { | ||
| 1438 | try a.pegToken(.keyword_anytype); | ||
| 1439 | } else { | ||
| 1440 | try a.pegTypeExpr(); | ||
| 1441 | } | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? | ||
| 1445 | fn pegIfPrefix(a: *AstSmith) SourceError!void { | ||
| 1446 | try a.pegToken(.keyword_if); | ||
| 1447 | try a.pegToken(.l_paren); | ||
| 1448 | try a.pegExpr(); | ||
| 1449 | try a.pegToken(.r_paren); | ||
| 1450 | try a.pegPtrPayload(); | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? | ||
| 1454 | fn pegWhilePrefix(a: *AstSmith) SourceError!void { | ||
| 1455 | try a.pegToken(.keyword_while); | ||
| 1456 | try a.pegToken(.l_paren); | ||
| 1457 | try a.pegExpr(); | ||
| 1458 | try a.pegToken(.r_paren); | ||
| 1459 | |||
| 1460 | if (a.smith.value(bool)) { | ||
| 1461 | try a.pegPtrPayload(); | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | if (a.smith.value(bool)) { | ||
| 1465 | try a.pegWhileContinueExpr(); | ||
| 1466 | } | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | /// ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload | ||
| 1470 | /// | ||
| 1471 | /// An additional requirement checked in the Parser is that the number of | ||
| 1472 | /// arguments and payload elements are the same. | ||
| 1473 | fn pegForPrefix(a: *AstSmith) SourceError!void { | ||
| 1474 | try a.pegToken(.keyword_for); | ||
| 1475 | try a.pegToken(.l_paren); | ||
| 1476 | const n = try a.pegForArgumentsList(); | ||
| 1477 | try a.pegToken(.r_paren); | ||
| 1478 | try a.pegPtrListPayload(n); | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | /// Payload <- PIPE IDENTIFIER PIPE | ||
| 1482 | fn pegPayload(a: *AstSmith) SourceError!void { | ||
| 1483 | try a.pegToken(.pipe); | ||
| 1484 | try a.pegIdentifier(); | ||
| 1485 | try a.pegToken(.pipe); | ||
| 1486 | } | ||
| 1487 | |||
| 1488 | /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE | ||
| 1489 | fn pegPtrPayload(a: *AstSmith) SourceError!void { | ||
| 1490 | try a.pegToken(.pipe); | ||
| 1491 | if (a.smith.value(bool)) { | ||
| 1492 | try a.pegToken(.asterisk); | ||
| 1493 | } | ||
| 1494 | try a.pegIdentifier(); | ||
| 1495 | try a.pegToken(.pipe); | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE | ||
| 1499 | fn pegPtrIndexPayload(a: *AstSmith) SourceError!void { | ||
| 1500 | try a.pegToken(.pipe); | ||
| 1501 | if (a.smith.value(bool)) { | ||
| 1502 | try a.pegToken(.asterisk); | ||
| 1503 | } | ||
| 1504 | try a.pegIdentifier(); | ||
| 1505 | if (a.smith.value(bool)) { | ||
| 1506 | try a.pegToken(.comma); | ||
| 1507 | try a.pegIdentifier(); | ||
| 1508 | } | ||
| 1509 | try a.pegToken(.pipe); | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | /// PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE | ||
| 1513 | fn pegPtrListPayload(a: *AstSmith, n: usize) SourceError!void { | ||
| 1514 | try a.pegToken(.pipe); | ||
| 1515 | if (a.smith.value(bool)) { | ||
| 1516 | try a.pegToken(.asterisk); | ||
| 1517 | } | ||
| 1518 | try a.pegIdentifier(); | ||
| 1519 | |||
| 1520 | for (1..n) |_| { | ||
| 1521 | try a.pegToken(.comma); | ||
| 1522 | if (a.smith.value(bool)) { | ||
| 1523 | try a.pegToken(.asterisk); | ||
| 1524 | } | ||
| 1525 | try a.pegIdentifier(); | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | if (a.smith.value(bool)) { | ||
| 1529 | try a.pegToken(.comma); | ||
| 1530 | } | ||
| 1531 | try a.pegToken(.pipe); | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | /// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr | ||
| 1535 | fn pegSwitchProng(a: *AstSmith) SourceError!void { | ||
| 1536 | if (a.smith.value(bool)) { | ||
| 1537 | try a.pegToken(.keyword_inline); | ||
| 1538 | } | ||
| 1539 | try a.pegSwitchCase(); | ||
| 1540 | try a.pegToken(.equal_angle_bracket_right); | ||
| 1541 | if (a.smith.value(bool)) { | ||
| 1542 | try a.pegPtrIndexPayload(); | ||
| 1543 | } | ||
| 1544 | try a.pegSingleAssignExpr(); | ||
| 1545 | } | ||
| 1546 | |||
| 1547 | /// SwitchCase | ||
| 1548 | /// <- SwitchItem (COMMA SwitchItem)* COMMA? | ||
| 1549 | /// / KEYWORD_else | ||
| 1550 | fn pegSwitchCase(a: *AstSmith) SourceError!void { | ||
| 1551 | if (a.smith.value(bool)) { | ||
| 1552 | try a.pegSwitchItem(); | ||
| 1553 | while (!a.smithListItemEos()) { | ||
| 1554 | try a.pegToken(.comma); | ||
| 1555 | try a.pegSwitchItem(); | ||
| 1556 | } | ||
| 1557 | if (a.smith.value(bool)) { | ||
| 1558 | try a.pegToken(.comma); | ||
| 1559 | } | ||
| 1560 | } else { | ||
| 1561 | try a.pegToken(.keyword_else); | ||
| 1562 | } | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | /// SwitchItem <- Expr (DOT3 Expr)? | ||
| 1566 | fn pegSwitchItem(a: *AstSmith) SourceError!void { | ||
| 1567 | try a.pegExpr(); | ||
| 1568 | if (a.smith.value(bool)) { | ||
| 1569 | try a.pegToken(.ellipsis3); | ||
| 1570 | try a.pegExpr(); | ||
| 1571 | } | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | /// ForArgumentsList <- ForItem (COMMA ForItem)* COMMA? | ||
| 1575 | fn pegForArgumentsList(a: *AstSmith) SourceError!usize { | ||
| 1576 | try a.pegForItem(); | ||
| 1577 | var n: usize = 1; | ||
| 1578 | while (!a.smithListItemEos()) { | ||
| 1579 | try a.pegToken(.comma); | ||
| 1580 | try a.pegForItem(); | ||
| 1581 | n += 1; | ||
| 1582 | } | ||
| 1583 | if (a.smith.value(bool)) { | ||
| 1584 | try a.pegToken(.comma); | ||
| 1585 | } | ||
| 1586 | return n; | ||
| 1587 | } | ||
| 1588 | |||
| 1589 | /// ForItem <- Expr (DOT2 Expr?)? | ||
| 1590 | fn pegForItem(a: *AstSmith) SourceError!void { | ||
| 1591 | try a.pegExpr(); | ||
| 1592 | const components = a.smith.valueRangeAtMost(u2, 0, 2); | ||
| 1593 | if (components >= 1) try a.pegToken(.ellipsis2); | ||
| 1594 | if (components >= 2) try a.pegExpr(); | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | /// AssignOp | ||
| 1598 | /// <- ASTERISKEQUAL | ||
| 1599 | /// / ASTERISKPIPEEQUAL | ||
| 1600 | /// / SLASHEQUAL | ||
| 1601 | /// / PERCENTEQUAL | ||
| 1602 | /// / PLUSEQUAL | ||
| 1603 | /// / PLUSPIPEEQUAL | ||
| 1604 | /// / MINUSEQUAL | ||
| 1605 | /// / MINUSPIPEEQUAL | ||
| 1606 | /// / LARROW2EQUAL | ||
| 1607 | /// / LARROW2PIPEEQUAL | ||
| 1608 | /// / RARROW2EQUAL | ||
| 1609 | /// / AMPERSANDEQUAL | ||
| 1610 | /// / CARETEQUAL | ||
| 1611 | /// / PIPEEQUAL | ||
| 1612 | /// / ASTERISKPERCENTEQUAL | ||
| 1613 | /// / PLUSPERCENTEQUAL | ||
| 1614 | /// / MINUSPERCENTEQUAL | ||
| 1615 | /// / EQUAL | ||
| 1616 | fn pegAssignOp(a: *AstSmith) SourceError!void { | ||
| 1617 | const tags = [_]Token.Tag{ | ||
| 1618 | .asterisk_equal, | ||
| 1619 | .asterisk_pipe_equal, | ||
| 1620 | .slash_equal, | ||
| 1621 | .percent_equal, | ||
| 1622 | .plus_equal, | ||
| 1623 | .plus_pipe_equal, | ||
| 1624 | .minus_equal, | ||
| 1625 | .minus_pipe_equal, | ||
| 1626 | .angle_bracket_angle_bracket_left_equal, | ||
| 1627 | .angle_bracket_angle_bracket_left_pipe_equal, | ||
| 1628 | .angle_bracket_angle_bracket_right_equal, | ||
| 1629 | .ampersand_equal, | ||
| 1630 | .caret_equal, | ||
| 1631 | .pipe_equal, | ||
| 1632 | .asterisk_percent_equal, | ||
| 1633 | .plus_percent_equal, | ||
| 1634 | .minus_percent_equal, | ||
| 1635 | .equal, | ||
| 1636 | }; | ||
| 1637 | try a.pegToken(tags[a.smith.index(tags.len)]); | ||
| 1638 | } | ||
| 1639 | |||
| 1640 | /// CompareOp | ||
| 1641 | /// <- EQUALEQUAL | ||
| 1642 | /// / EXCLAMATIONMARKEQUAL | ||
| 1643 | /// / LARROW | ||
| 1644 | /// / RARROW | ||
| 1645 | /// / LARROWEQUAL | ||
| 1646 | /// / RARROWEQUAL | ||
| 1647 | fn pegCompareOp(a: *AstSmith) SourceError!void { | ||
| 1648 | const tags = [_]Token.Tag{ | ||
| 1649 | .equal_equal, | ||
| 1650 | .bang_equal, | ||
| 1651 | .angle_bracket_left, | ||
| 1652 | .angle_bracket_right, | ||
| 1653 | .angle_bracket_left_equal, | ||
| 1654 | .angle_bracket_right_equal, | ||
| 1655 | }; | ||
| 1656 | try a.pegTokenWhitespaceAround(tags[a.smith.index(tags.len)]); | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | /// BitwiseOp | ||
| 1660 | /// <- AMPERSAND | ||
| 1661 | /// / CARET | ||
| 1662 | /// / PIPE | ||
| 1663 | /// / KEYWORD_orelse | ||
| 1664 | /// / KEYWORD_catch Payload? | ||
| 1665 | fn pegBitwiseOp(a: *AstSmith) SourceError!void { | ||
| 1666 | const tags = [_]Token.Tag{ | ||
| 1667 | .ampersand, | ||
| 1668 | .caret, | ||
| 1669 | .pipe, | ||
| 1670 | .keyword_orelse, | ||
| 1671 | .keyword_catch, | ||
| 1672 | }; | ||
| 1673 | const tag = tags[a.smith.index(tags.len)]; | ||
| 1674 | try a.pegTokenWhitespaceAround(tag); | ||
| 1675 | if (tag == .keyword_catch and a.smith.value(bool)) { | ||
| 1676 | try a.pegPayload(); | ||
| 1677 | } | ||
| 1678 | } | ||
| 1679 | |||
| 1680 | /// BitShiftOp | ||
| 1681 | /// <- LARROW2 | ||
| 1682 | /// / RARROW2 | ||
| 1683 | /// / LARROW2PIPE | ||
| 1684 | fn pegBitShiftOp(a: *AstSmith) SourceError!void { | ||
| 1685 | const tags = [_]Token.Tag{ | ||
| 1686 | .angle_bracket_angle_bracket_left, | ||
| 1687 | .angle_bracket_angle_bracket_right, | ||
| 1688 | .angle_bracket_angle_bracket_left_pipe, | ||
| 1689 | }; | ||
| 1690 | try a.pegTokenWhitespaceAround(tags[a.smith.index(tags.len)]); | ||
| 1691 | } | ||
| 1692 | |||
| 1693 | /// AdditionOp | ||
| 1694 | /// <- PLUS | ||
| 1695 | /// / MINUS | ||
| 1696 | /// / PLUS2 | ||
| 1697 | /// / PLUSPERCENT | ||
| 1698 | /// / MINUSPERCENT | ||
| 1699 | /// / PLUSPIPE | ||
| 1700 | /// / MINUSPIPE | ||
| 1701 | fn pegAdditionOp(a: *AstSmith) SourceError!void { | ||
| 1702 | const tags = [_]Token.Tag{ | ||
| 1703 | .plus, | ||
| 1704 | .minus, | ||
| 1705 | .plus_plus, | ||
| 1706 | .plus_percent, | ||
| 1707 | .minus_percent, | ||
| 1708 | .plus_pipe, | ||
| 1709 | .minus_pipe, | ||
| 1710 | }; | ||
| 1711 | try a.pegTokenWhitespaceAround(tags[a.smith.index(tags.len)]); | ||
| 1712 | } | ||
| 1713 | |||
| 1714 | /// MultiplyOp | ||
| 1715 | /// <- PIPE2 | ||
| 1716 | /// / ASTERISK | ||
| 1717 | /// / SLASH | ||
| 1718 | /// / PERCENT | ||
| 1719 | /// / ASTERISKPERCENT | ||
| 1720 | /// / ASTERISKPIPE | ||
| 1721 | fn pegMultiplyOp(a: *AstSmith) SourceError!void { | ||
| 1722 | const tags = [_]Token.Tag{ | ||
| 1723 | .asterisk, | ||
| 1724 | .pipe_pipe, | ||
| 1725 | .slash, | ||
| 1726 | .percent, | ||
| 1727 | .asterisk_percent, | ||
| 1728 | .asterisk_pipe, | ||
| 1729 | }; | ||
| 1730 | const start = @as(u8, 2) * @intFromBool(a.not_token == .asterisk); | ||
| 1731 | try a.pegTokenWhitespaceAround(tags[a.smith.valueRangeLessThan(u8, start, tags.len)]); | ||
| 1732 | } | ||
| 1733 | |||
| 1734 | /// PrefixOp | ||
| 1735 | /// <- EXCLAMATIONMARK | ||
| 1736 | /// / MINUS | ||
| 1737 | /// / TILDE | ||
| 1738 | /// / MINUSPERCENT | ||
| 1739 | /// / AMPERSAND | ||
| 1740 | /// / KEYWORD_try | ||
| 1741 | fn pegPrefixOp(a: *AstSmith) SourceError!void { | ||
| 1742 | const tags = [_]Token.Tag{ | ||
| 1743 | .bang, | ||
| 1744 | .minus, | ||
| 1745 | .tilde, | ||
| 1746 | .minus_percent, | ||
| 1747 | .ampersand, | ||
| 1748 | .keyword_try, | ||
| 1749 | }; | ||
| 1750 | try a.pegToken(tags[a.smith.index(tags.len)]); | ||
| 1751 | } | ||
| 1752 | |||
| 1753 | /// PrefixTypeOp | ||
| 1754 | /// <- QUESTIONMARK | ||
| 1755 | /// / KEYWORD_anyframe MINUSRARROW | ||
| 1756 | /// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? | ||
| 1757 | /// KEYWORD_const? KEYWORD_volatile? | ||
| 1758 | /// / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? | ||
| 1759 | /// KEYWORD_const? KEYWORD_volatile? | ||
| 1760 | /// / ArrayTypeStart | ||
| 1761 | fn pegPrefixTypeOp(a: *AstSmith) SourceError!void { | ||
| 1762 | switch (a.smith.value(enum { | ||
| 1763 | optional, | ||
| 1764 | anyframe_arrow, | ||
| 1765 | array, | ||
| 1766 | single_pointer, | ||
| 1767 | many_pointer, | ||
| 1768 | slice, | ||
| 1769 | })) { | ||
| 1770 | .optional => try a.pegToken(.question_mark), | ||
| 1771 | .anyframe_arrow => { | ||
| 1772 | try a.pegToken(.keyword_anyframe); | ||
| 1773 | try a.pegToken(.arrow); | ||
| 1774 | }, | ||
| 1775 | .array => try a.pegArrayTypeStart(), | ||
| 1776 | .single_pointer, .many_pointer, .slice => |kind| { | ||
| 1777 | const is_single = kind == .single_pointer and a.not_token != .asterisk; | ||
| 1778 | if (is_single) { | ||
| 1779 | try a.pegSinglePtrTypeStart(); | ||
| 1780 | } else if (kind == .many_pointer) { | ||
| 1781 | try a.pegManyPtrTypeStart(); | ||
| 1782 | } else { | ||
| 1783 | try a.pegSliceTypeStart(); | ||
| 1784 | } | ||
| 1785 | |||
| 1786 | if (a.smith.value(bool)) { | ||
| 1787 | try a.pegToken(.keyword_allowzero); | ||
| 1788 | } | ||
| 1789 | if (a.smith.value(bool)) { | ||
| 1790 | if (is_single) { | ||
| 1791 | try a.pegBitAlign(); | ||
| 1792 | } else { | ||
| 1793 | try a.pegByteAlign(); | ||
| 1794 | } | ||
| 1795 | } | ||
| 1796 | if (a.smith.value(bool)) { | ||
| 1797 | try a.pegAddrSpace(); | ||
| 1798 | } | ||
| 1799 | if (a.smith.value(bool)) { | ||
| 1800 | try a.pegToken(.keyword_const); | ||
| 1801 | } | ||
| 1802 | if (a.smith.value(bool)) { | ||
| 1803 | try a.pegToken(.keyword_volatile); | ||
| 1804 | } | ||
| 1805 | }, | ||
| 1806 | } | ||
| 1807 | } | ||
| 1808 | |||
| 1809 | /// SuffixOp | ||
| 1810 | /// <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET | ||
| 1811 | /// / DOT IDENTIFIER | ||
| 1812 | /// / DOTASTERISK | ||
| 1813 | /// / DOTQUESTIONMARK | ||
| 1814 | fn pegSuffixOp(a: *AstSmith) SourceError!void { | ||
| 1815 | switch (a.smith.value(enum { slice, field, deref, unwrap })) { | ||
| 1816 | .slice => { | ||
| 1817 | try a.pegToken(.l_bracket); | ||
| 1818 | try a.pegExpr(); | ||
| 1819 | |||
| 1820 | if (a.smith.value(bool)) { | ||
| 1821 | try a.pegToken(.ellipsis2); | ||
| 1822 | if (a.smith.value(bool)) | ||
| 1823 | try a.pegExpr(); | ||
| 1824 | if (a.smith.value(bool)) { | ||
| 1825 | try a.pegToken(.colon); | ||
| 1826 | try a.pegExpr(); | ||
| 1827 | } | ||
| 1828 | } | ||
| 1829 | |||
| 1830 | try a.pegToken(.r_bracket); | ||
| 1831 | }, | ||
| 1832 | .field => { | ||
| 1833 | try a.pegToken(.period); | ||
| 1834 | try a.pegIdentifier(); | ||
| 1835 | }, | ||
| 1836 | .deref => try a.pegToken(.period_asterisk), | ||
| 1837 | .unwrap => { | ||
| 1838 | try a.pegToken(.period); | ||
| 1839 | try a.pegToken(.question_mark); | ||
| 1840 | }, | ||
| 1841 | } | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | /// FnCallArguments <- LPAREN ExprList RPAREN | ||
| 1845 | fn pegFnCallArguments(a: *AstSmith) SourceError!void { | ||
| 1846 | try a.pegToken(.l_paren); | ||
| 1847 | try a.pegExprList(); | ||
| 1848 | try a.pegToken(.r_paren); | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET | ||
| 1852 | fn pegSliceTypeStart(a: *AstSmith) SourceError!void { | ||
| 1853 | try a.pegToken(.l_bracket); | ||
| 1854 | if (a.smith.value(bool)) { | ||
| 1855 | try a.pegToken(.colon); | ||
| 1856 | try a.pegExpr(); | ||
| 1857 | } | ||
| 1858 | try a.pegToken(.r_bracket); | ||
| 1859 | } | ||
| 1860 | |||
| 1861 | /// SinglePtrTypeStart <- ASTERISK | ||
| 1862 | fn pegSinglePtrTypeStart(a: *AstSmith) SourceError!void { | ||
| 1863 | try a.pegToken(.asterisk); | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | /// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET | ||
| 1867 | fn pegManyPtrTypeStart(a: *AstSmith) SourceError!void { | ||
| 1868 | try a.pegToken(.l_bracket); | ||
| 1869 | try a.pegToken(.asterisk); | ||
| 1870 | switch (a.smith.value(enum { many, many_c, many_sentinel })) { | ||
| 1871 | .many => {}, | ||
| 1872 | .many_c => { | ||
| 1873 | // No need for `preservePegEndOfWord` because the previous token is an asterisk | ||
| 1874 | try a.addTokenTag(.identifier); | ||
| 1875 | try a.addSourceByte('c'); | ||
| 1876 | }, | ||
| 1877 | .many_sentinel => { | ||
| 1878 | try a.pegToken(.colon); | ||
| 1879 | try a.pegExpr(); | ||
| 1880 | }, | ||
| 1881 | } | ||
| 1882 | try a.pegToken(.r_bracket); | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | /// ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET | ||
| 1886 | fn pegArrayTypeStart(a: *AstSmith) SourceError!void { | ||
| 1887 | try a.pegToken(.l_bracket); | ||
| 1888 | a.not_token = .asterisk; | ||
| 1889 | try a.pegExpr(); | ||
| 1890 | if (a.smith.value(bool)) { | ||
| 1891 | try a.pegToken(.colon); | ||
| 1892 | try a.pegExpr(); | ||
| 1893 | } | ||
| 1894 | try a.pegToken(.r_bracket); | ||
| 1895 | } | ||
| 1896 | |||
| 1897 | /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE | ||
| 1898 | fn pegContainerDeclAuto(a: *AstSmith) SourceError!void { | ||
| 1899 | try a.pegContainerDeclType(); | ||
| 1900 | try a.pegToken(.l_brace); | ||
| 1901 | try a.pegContainerMembers(); | ||
| 1902 | try a.pegToken(.r_brace); | ||
| 1903 | } | ||
| 1904 | |||
| 1905 | /// ContainerDeclType | ||
| 1906 | /// <- KEYWORD_struct (LPAREN Expr RPAREN)? | ||
| 1907 | /// / KEYWORD_opaque | ||
| 1908 | /// / KEYWORD_enum (LPAREN Expr RPAREN)? | ||
| 1909 | /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / !KEYWORD_enum Expr) RPAREN)? | ||
| 1910 | fn pegContainerDeclType(a: *AstSmith) SourceError!void { | ||
| 1911 | switch (a.smith.value(enum { @"struct", @"opaque", @"enum", @"union" })) { | ||
| 1912 | .@"struct", .@"enum" => |c| { | ||
| 1913 | const is_struct = c == .@"struct" or a.not_token == .keyword_enum; | ||
| 1914 | try a.pegToken(if (is_struct) .keyword_struct else .keyword_enum); | ||
| 1915 | if (a.smith.value(bool)) { | ||
| 1916 | try a.pegToken(.l_paren); | ||
| 1917 | try a.pegExpr(); | ||
| 1918 | try a.pegToken(.r_paren); | ||
| 1919 | } | ||
| 1920 | }, | ||
| 1921 | .@"opaque" => try a.pegToken(.keyword_opaque), | ||
| 1922 | .@"union" => { | ||
| 1923 | try a.pegToken(.keyword_union); | ||
| 1924 | switch (a.smith.value(enum { no_tag, expr_tag, enum_tag, enum_expr_tag })) { | ||
| 1925 | .no_tag => {}, | ||
| 1926 | .expr_tag => { | ||
| 1927 | try a.pegToken(.l_paren); | ||
| 1928 | a.not_token = .keyword_enum; | ||
| 1929 | try a.pegExpr(); | ||
| 1930 | try a.pegToken(.r_paren); | ||
| 1931 | }, | ||
| 1932 | .enum_tag => { | ||
| 1933 | try a.pegToken(.l_paren); | ||
| 1934 | try a.pegToken(.keyword_enum); | ||
| 1935 | try a.pegToken(.r_paren); | ||
| 1936 | }, | ||
| 1937 | .enum_expr_tag => { | ||
| 1938 | try a.pegToken(.l_paren); | ||
| 1939 | try a.pegToken(.keyword_enum); | ||
| 1940 | try a.pegToken(.l_paren); | ||
| 1941 | try a.pegExpr(); | ||
| 1942 | try a.pegToken(.r_paren); | ||
| 1943 | try a.pegToken(.r_paren); | ||
| 1944 | }, | ||
| 1945 | } | ||
| 1946 | }, | ||
| 1947 | } | ||
| 1948 | } | ||
| 1949 | |||
| 1950 | /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN | ||
| 1951 | fn pegByteAlign(a: *AstSmith) SourceError!void { | ||
| 1952 | try a.pegToken(.keyword_align); | ||
| 1953 | try a.pegToken(.l_paren); | ||
| 1954 | try a.pegExpr(); | ||
| 1955 | try a.pegToken(.r_paren); | ||
| 1956 | } | ||
| 1957 | |||
| 1958 | /// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN | ||
| 1959 | fn pegBitAlign(a: *AstSmith) SourceError!void { | ||
| 1960 | try a.pegToken(.keyword_align); | ||
| 1961 | try a.pegToken(.l_paren); | ||
| 1962 | try a.pegExpr(); | ||
| 1963 | if (a.smith.value(bool)) { | ||
| 1964 | try a.pegToken(.colon); | ||
| 1965 | try a.pegExpr(); | ||
| 1966 | try a.pegToken(.colon); | ||
| 1967 | try a.pegExpr(); | ||
| 1968 | } | ||
| 1969 | try a.pegToken(.r_paren); | ||
| 1970 | } | ||
| 1971 | |||
| 1972 | /// IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)? | ||
| 1973 | fn pegIdentifierList(a: *AstSmith) SourceError!void { | ||
| 1974 | while (!a.smith.eos()) { | ||
| 1975 | try a.pegMaybeDocComment(); | ||
| 1976 | try a.pegIdentifier(); | ||
| 1977 | try a.pegToken(.comma); | ||
| 1978 | } | ||
| 1979 | if (a.smith.value(bool)) { | ||
| 1980 | try a.pegMaybeDocComment(); | ||
| 1981 | try a.pegIdentifier(); | ||
| 1982 | } | ||
| 1983 | } | ||
| 1984 | |||
| 1985 | /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng? | ||
| 1986 | fn pegSwitchProngList(a: *AstSmith) SourceError!void { | ||
| 1987 | while (!a.smithListItemEos()) { | ||
| 1988 | try a.pegSwitchProng(); | ||
| 1989 | try a.pegToken(.comma); | ||
| 1990 | } | ||
| 1991 | if (a.smithListItemBool()) { | ||
| 1992 | try a.pegSwitchProng(); | ||
| 1993 | } | ||
| 1994 | } | ||
| 1995 | |||
| 1996 | /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? | ||
| 1997 | fn pegAsmOutputList(a: *AstSmith) SourceError!void { | ||
| 1998 | while (!a.smithListItemEos()) { | ||
| 1999 | try a.pegAsmOutputItem(); | ||
| 2000 | try a.pegToken(.comma); | ||
| 2001 | } | ||
| 2002 | if (a.smithListItemBool()) { | ||
| 2003 | try a.pegAsmOutputItem(); | ||
| 2004 | } | ||
| 2005 | } | ||
| 2006 | |||
| 2007 | /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? | ||
| 2008 | fn pegAsmInputList(a: *AstSmith) SourceError!void { | ||
| 2009 | while (!a.smithListItemEos()) { | ||
| 2010 | try a.pegAsmInputItem(); | ||
| 2011 | try a.pegToken(.comma); | ||
| 2012 | } | ||
| 2013 | if (a.smithListItemBool()) { | ||
| 2014 | try a.pegAsmInputItem(); | ||
| 2015 | } | ||
| 2016 | } | ||
| 2017 | |||
| 2018 | /// ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)? | ||
| 2019 | fn pegParamDeclList(a: *AstSmith) SourceError!void { | ||
| 2020 | while (!a.smithListItemEos()) { | ||
| 2021 | try a.pegParamDecl(); | ||
| 2022 | try a.pegToken(.comma); | ||
| 2023 | } | ||
| 2024 | const Final = enum { none, dot3, dot3_comma, param }; | ||
| 2025 | switch (a.smith.valueWeighted(Final, &.{ | ||
| 2026 | .rangeLessThan(Final, .none, .param, 2), | ||
| 2027 | .value(Final, .param, 1), | ||
| 2028 | })) { | ||
| 2029 | .none => {}, | ||
| 2030 | .dot3 => try a.pegToken(.ellipsis3), | ||
| 2031 | .dot3_comma => { | ||
| 2032 | try a.pegToken(.ellipsis3); | ||
| 2033 | try a.pegToken(.comma); | ||
| 2034 | }, | ||
| 2035 | .param => try a.pegParamDecl(), | ||
| 2036 | } | ||
| 2037 | } | ||
| 2038 | |||
| 2039 | /// ExprList <- (Expr COMMA)* Expr? | ||
| 2040 | fn pegExprList(a: *AstSmith) SourceError!void { | ||
| 2041 | while (!a.smithListItemEos()) { | ||
| 2042 | try a.pegExpr(); | ||
| 2043 | try a.pegToken(.comma); | ||
| 2044 | } | ||
| 2045 | if (a.smithListItemBool()) { | ||
| 2046 | try a.pegExpr(); | ||
| 2047 | } | ||
| 2048 | } | ||
| 2049 | |||
| 2050 | /// container_doc_comment <- ('//!' non_control_utf8* [ \n]* skip)+ | ||
| 2051 | fn pegContainerDocComment(a: *AstSmith) SourceError!void { | ||
| 2052 | while (true) { | ||
| 2053 | try a.addTokenTag(.container_doc_comment); | ||
| 2054 | try a.pegGenericLine("//!", .any); | ||
| 2055 | try a.pegSkip(); | ||
| 2056 | if (a.smith.eos()) break; | ||
| 2057 | } | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | /// doc_comment? | ||
| 2061 | fn pegMaybeDocComment(a: *AstSmith) SourceError!void { | ||
| 2062 | // A specific hash is provided here since this function is likely to be inlined, | ||
| 2063 | // however having all doc comments with the same uid is beneficial. | ||
| 2064 | if (a.smith.boolWeightedWithHash(63, 1, 0x39b94392)) { | ||
| 2065 | try a.pegDocComment(); | ||
| 2066 | } | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | /// doc_comment <- ('///' non_control_utf8* [ \n]* skip)+ | ||
| 2070 | fn pegDocComment(a: *AstSmith) SourceError!void { | ||
| 2071 | if (a.source_len > 0 and a.source_buf[a.source_len - 1] != '\n') { | ||
| 2072 | try a.addSourceByte('\n'); | ||
| 2073 | } | ||
| 2074 | while (true) { | ||
| 2075 | try a.addTokenTag(.doc_comment); | ||
| 2076 | try a.pegGenericLine("///", .doc_comment); | ||
| 2077 | try a.pegSkip(); | ||
| 2078 | if (a.smith.eosWeightedSimple(1, 3)) break; | ||
| 2079 | } | ||
| 2080 | } | ||
| 2081 | |||
| 2082 | /// line_comment <- '//' ![!/] non_control_utf8* / '////' non_control_utf8* | ||
| 2083 | fn pegLineComment(a: *AstSmith) SourceError!void { | ||
| 2084 | return a.pegGenericLine("//", .line_comment); | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | /// line_string <- '\\\\' non_control_utf8* [ \n]* | ||
| 2088 | fn pegLineString(a: *AstSmith) SourceError!void { | ||
| 2089 | try a.addTokenTag(.multiline_string_literal_line); | ||
| 2090 | return a.pegGenericLine("\\\\", .any); | ||
| 2091 | } | ||
| 2092 | |||
| 2093 | /// non_control_utf8 <- [\040-\377] | ||
| 2094 | /// | ||
| 2095 | /// Used for line, doc, and container comments as well as | ||
| 2096 | /// multiline string literal lines. | ||
| 2097 | fn pegGenericLine( | ||
| 2098 | a: *AstSmith, | ||
| 2099 | prefix: []const u8, | ||
| 2100 | /// Adds constraints to what the line contains | ||
| 2101 | prefix_kind: enum { any, line_comment, doc_comment }, | ||
| 2102 | ) SourceError!void { | ||
| 2103 | const cr = a.smith.value(bool); | ||
| 2104 | const newline_len = @intFromBool(cr) + @as(usize, 1); | ||
| 2105 | |||
| 2106 | try a.ensureSourceCapacity(prefix.len + newline_len); | ||
| 2107 | a.addSourceAssumeCapacity(prefix); | ||
| 2108 | |||
| 2109 | const line = a.variableChar(newline_len, 0, &.{ | ||
| 2110 | .rangeAtMost(u8, ' ', 0x7f - 1, 1), | ||
| 2111 | .rangeAtMost(u8, 0x7f + 1, 0xff, 1), | ||
| 2112 | }); | ||
| 2113 | if (line.len >= 1) switch (prefix_kind) { | ||
| 2114 | .any => {}, | ||
| 2115 | .line_comment => { | ||
| 2116 | // Convert doc comments to quadruple slashes when possible; | ||
| 2117 | // Otherwise, and for container doc comments, erase the '/' or '!' | ||
| 2118 | if (line[0] == '/' and line.len >= 2) { | ||
| 2119 | line[1] = '/'; | ||
| 2120 | } else if (line[0] == '/' or line[0] == '!') { | ||
| 2121 | line[0] = ' '; | ||
| 2122 | } | ||
| 2123 | }, | ||
| 2124 | .doc_comment => { | ||
| 2125 | // Avoid quadruple slashes | ||
| 2126 | if (line[0] == '/') { | ||
| 2127 | line[0] = ' '; | ||
| 2128 | } | ||
| 2129 | }, | ||
| 2130 | }; | ||
| 2131 | |||
| 2132 | if (cr) a.addSourceByteAssumeCapacity('\r'); | ||
| 2133 | a.addSourceByteAssumeCapacity('\n'); | ||
| 2134 | } | ||
| 2135 | |||
| 2136 | /// skip <- ([ \n] / line_comment)* | ||
| 2137 | fn pegSkip(a: *AstSmith) SourceError!void { | ||
| 2138 | if (a.smith.boolWeighted(63, 1)) { | ||
| 2139 | while (true) { | ||
| 2140 | const Kind = enum { | ||
| 2141 | space, | ||
| 2142 | line_break, | ||
| 2143 | cr_line_break, | ||
| 2144 | line_comment, | ||
| 2145 | line_comment_zig_fmt_off, | ||
| 2146 | line_comment_zig_fmt_on, | ||
| 2147 | }; | ||
| 2148 | |||
| 2149 | const weights = Smith.baselineWeights(Kind) ++ | ||
| 2150 | [_]Weight{.value(Kind, .space, 11)}; | ||
| 2151 | switch (a.smith.valueWeighted(Kind, weights)) { | ||
| 2152 | .space => try a.addSourceByte(' '), | ||
| 2153 | .line_break => try a.addSourceByte('\n'), | ||
| 2154 | .cr_line_break => try a.addSource("\r\n"), | ||
| 2155 | .line_comment => try a.pegLineComment(), | ||
| 2156 | .line_comment_zig_fmt_off => try a.addSource("//zig fmt: off\n"), | ||
| 2157 | .line_comment_zig_fmt_on => try a.addSource("//zig fmt: on\n"), | ||
| 2158 | } | ||
| 2159 | |||
| 2160 | if (a.smith.eos()) break; | ||
| 2161 | } | ||
| 2162 | } | ||
| 2163 | } | ||
| 2164 | |||
| 2165 | const bin_weights: []const Weight = &.{.rangeAtMost(u8, '0', '1', 1)}; | ||
| 2166 | const oct_weights: []const Weight = &.{.rangeAtMost(u8, '0', '7', 1)}; | ||
| 2167 | const dec_weights: []const Weight = &.{.rangeAtMost(u8, '0', '9', 1)}; | ||
| 2168 | const hex_weights: []const Weight = &.{ | ||
| 2169 | .rangeAtMost(u8, '0', '9', 1), | ||
| 2170 | .rangeAtMost(u8, 'a', 'f', 1), | ||
| 2171 | .rangeAtMost(u8, 'A', 'F', 1), | ||
| 2172 | }; | ||
| 2173 | |||
| 2174 | /// Asserts enough capacity for at `min + reserved_capacity` | ||
| 2175 | fn variableChar( | ||
| 2176 | a: *AstSmith, | ||
| 2177 | reserved_capacity: usize, | ||
| 2178 | min: usize, | ||
| 2179 | weights: []const Weight, | ||
| 2180 | ) []u8 { | ||
| 2181 | const capacity = a.sourceCapacity(); | ||
| 2182 | const max_out = capacity.len - reserved_capacity; | ||
| 2183 | |||
| 2184 | const len_weights: [3]Weight = .{ | ||
| 2185 | .rangeAtMost(u32, @intCast(min), @min(2, max_out), 32678), | ||
| 2186 | // For the below `.rangeAtMost` is not used because max may be less than min. | ||
| 2187 | // In this case, the weights are omitted. | ||
| 2188 | .{ .min = 3, .max = @min(16, max_out), .weight = 512 }, | ||
| 2189 | // Still allow much longer sequences to test parsing overflows | ||
| 2190 | .{ .min = 17, .max = @min(256, max_out), .weight = 1 }, | ||
| 2191 | }; | ||
| 2192 | const n_weights = @as(usize, 1) + @intFromBool(max_out >= 3) + @intFromBool(max_out >= 17); | ||
| 2193 | |||
| 2194 | const len = a.smith.sliceWeighted(capacity, len_weights[0..n_weights], weights); | ||
| 2195 | a.source_len += len; | ||
| 2196 | return capacity[0..len]; | ||
| 2197 | } | ||
| 2198 | |||
| 2199 | /// char_escape | ||
| 2200 | /// <- "\\x" hex hex | ||
| 2201 | /// / "\\u{" hex+ "}" | ||
| 2202 | /// / "\\" [nr\\t'"] | ||
| 2203 | /// char_char | ||
| 2204 | /// <- multibyte_utf8 | ||
| 2205 | /// / char_escape | ||
| 2206 | /// / ![\\'\n] non_control_ascii | ||
| 2207 | /// | ||
| 2208 | /// string_char | ||
| 2209 | /// <- multibyte_utf8 | ||
| 2210 | /// / char_escape | ||
| 2211 | /// / ![\\"\n] non_control_ascii | ||
| 2212 | fn pegChar(a: *AstSmith, quote: u8) SourceError!void { | ||
| 2213 | const Char = enum(u8) { | ||
| 2214 | ascii, | ||
| 2215 | unicode_2, | ||
| 2216 | unicode_3, | ||
| 2217 | unicode_4, | ||
| 2218 | hex_escape, | ||
| 2219 | unicode_escape, | ||
| 2220 | char_escape, | ||
| 2221 | }; | ||
| 2222 | const weights = Smith.baselineWeights(Char) ++ &[_]Weight{.value(Char, .ascii, 32)}; | ||
| 2223 | switch (a.smith.valueWeighted(Char, weights)) { | ||
| 2224 | .ascii => try a.addSourceByte(a.smith.valueWeighted(u8, &.{ | ||
| 2225 | .rangeAtMost(u8, ' ', quote - 1, 1), | ||
| 2226 | .rangeAtMost(u8, quote + 1, '\\' - 1, 1), | ||
| 2227 | .rangeAtMost(u8, '\\' + 1, 0x7e, 1), | ||
| 2228 | })), | ||
| 2229 | .unicode_2 => assert(2 == std.unicode.wtf8Encode( | ||
| 2230 | a.smith.valueRangeLessThan(u21, 0x80, 0x800), | ||
| 2231 | try a.addSourceAsSlice(2), | ||
| 2232 | ) catch unreachable), | ||
| 2233 | .unicode_3 => assert(3 == std.unicode.wtf8Encode( | ||
| 2234 | a.smith.valueRangeLessThan(u21, 0x800, 0x10000), | ||
| 2235 | try a.addSourceAsSlice(3), | ||
| 2236 | ) catch unreachable), | ||
| 2237 | .unicode_4 => assert(4 == std.unicode.wtf8Encode( | ||
| 2238 | a.smith.valueRangeLessThan(u21, 0x10000, 0x110000), | ||
| 2239 | try a.addSourceAsSlice(4), | ||
| 2240 | ) catch unreachable), | ||
| 2241 | .hex_escape => { | ||
| 2242 | try a.ensureSourceCapacity(4); | ||
| 2243 | a.addSourceAssumeCapacity("\\x"); | ||
| 2244 | a.smith.bytesWeighted(a.addSourceAsSliceAssumeCapacity(2), hex_weights); | ||
| 2245 | }, | ||
| 2246 | .unicode_escape => { | ||
| 2247 | try a.ensureSourceCapacity(5); | ||
| 2248 | a.addSourceAssumeCapacity("\\u{"); | ||
| 2249 | _ = a.variableChar(1, 1, hex_weights); | ||
| 2250 | a.addSourceByteAssumeCapacity('}'); | ||
| 2251 | }, | ||
| 2252 | .char_escape => { | ||
| 2253 | try a.ensureSourceCapacity(2); | ||
| 2254 | a.addSourceByteAssumeCapacity('\\'); | ||
| 2255 | a.addSourceByteAssumeCapacity(a.smith.valueWeighted(u8, &.{ | ||
| 2256 | .value(u8, 'n', 1), | ||
| 2257 | .value(u8, 'r', 1), | ||
| 2258 | .value(u8, 't', 1), | ||
| 2259 | .value(u8, '\\', 1), | ||
| 2260 | .value(u8, '\'', 1), | ||
| 2261 | .value(u8, '"', 1), | ||
| 2262 | })); | ||
| 2263 | }, | ||
| 2264 | } | ||
| 2265 | } | ||
| 2266 | |||
| 2267 | /// CHAR_LITERAL <- ['] char_char ['] skip | ||
| 2268 | fn pegCharLiteral(a: *AstSmith) SourceError!void { | ||
| 2269 | try a.addTokenTag(.char_literal); | ||
| 2270 | try a.addSourceByte('\''); | ||
| 2271 | try a.pegChar('\''); | ||
| 2272 | try a.addSourceByte('\''); | ||
| 2273 | try a.pegSkip(); | ||
| 2274 | } | ||
| 2275 | |||
| 2276 | ///FLOAT | ||
| 2277 | /// <- '0x' hex_int '.' hex_int ([pP] [-+]? dec_int)? skip | ||
| 2278 | /// / dec_int '.' dec_int ([eE] [-+]? dec_int)? skip | ||
| 2279 | /// / '0x' hex_int [pP] [-+]? dec_int skip | ||
| 2280 | /// / dec_int [eE] [-+]? dec_int skip | ||
| 2281 | fn pegFloat(a: *AstSmith) SourceError!void { | ||
| 2282 | try a.preservePegEndOfWord(); | ||
| 2283 | try a.addTokenTag(.number_literal); | ||
| 2284 | |||
| 2285 | const hex = a.smith.value(bool); | ||
| 2286 | const exp = a.smith.value(packed struct(u3) { | ||
| 2287 | kind: enum(u2) { none, no_sign, minus, plus }, | ||
| 2288 | upper: bool, | ||
| 2289 | }); | ||
| 2290 | const dot = exp.kind == .none or a.smith.value(bool); | ||
| 2291 | |||
| 2292 | var reserved: usize = @intFromBool(hex) * "0x".len + "0".len + @intFromBool(dot) * ".0".len + | ||
| 2293 | switch (exp.kind) { | ||
| 2294 | .none => 0, | ||
| 2295 | .no_sign => "e0".len, | ||
| 2296 | .minus => "e-0".len, | ||
| 2297 | .plus => "e+0".len, | ||
| 2298 | }; | ||
| 2299 | try a.ensureSourceCapacity(reserved); | ||
| 2300 | |||
| 2301 | if (hex) { | ||
| 2302 | reserved -= 2; | ||
| 2303 | a.addSourceAssumeCapacity("0x"); | ||
| 2304 | } | ||
| 2305 | const digits = if (hex) hex_weights else dec_weights; | ||
| 2306 | |||
| 2307 | reserved -= 1; | ||
| 2308 | _ = a.variableChar(reserved, 1, digits); | ||
| 2309 | |||
| 2310 | if (dot) { | ||
| 2311 | reserved -= 2; | ||
| 2312 | a.addSourceByteAssumeCapacity('.'); | ||
| 2313 | _ = a.variableChar(reserved, 1, digits); | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | if (exp.kind != .none) { | ||
| 2317 | reserved -= 1; | ||
| 2318 | const case_diff = @as(u8, 'a' - 'A') * @intFromBool(exp.upper); | ||
| 2319 | a.addSourceByteAssumeCapacity(@as(u8, if (hex) 'p' else 'e') - case_diff); | ||
| 2320 | |||
| 2321 | if (exp.kind != .no_sign) { | ||
| 2322 | reserved -= 1; | ||
| 2323 | a.addSourceByteAssumeCapacity(if (exp.kind == .plus) '+' else '-'); | ||
| 2324 | } | ||
| 2325 | |||
| 2326 | reserved -= 1; | ||
| 2327 | assert(reserved == 0); | ||
| 2328 | _ = a.variableChar(reserved, 1, dec_weights); | ||
| 2329 | } | ||
| 2330 | } | ||
| 2331 | |||
| 2332 | ///INTEGER | ||
| 2333 | /// <- '0b' bin_int skip | ||
| 2334 | /// / '0o' oct_int skip | ||
| 2335 | /// / '0x' hex_int skip | ||
| 2336 | /// / dec_int skip | ||
| 2337 | fn pegInteger(a: *AstSmith) SourceError!void { | ||
| 2338 | try a.preservePegEndOfWord(); | ||
| 2339 | try a.addTokenTag(.number_literal); | ||
| 2340 | const Base = enum { bin, dec, oct, hex }; | ||
| 2341 | const base_weights: []const Weight = Smith.baselineWeights(Base) ++ | ||
| 2342 | &[_]Weight{ .value(Base, .dec, 6), .value(Base, .hex, 2) }; | ||
| 2343 | const digits, const prefix = switch (a.smith.valueWeighted(Base, base_weights)) { | ||
| 2344 | .bin => .{ bin_weights, "0b" }, | ||
| 2345 | .oct => .{ oct_weights, "0o" }, | ||
| 2346 | .dec => .{ dec_weights, "" }, | ||
| 2347 | .hex => .{ hex_weights, "0x" }, | ||
| 2348 | }; | ||
| 2349 | try a.ensureSourceCapacity(prefix.len + 1); | ||
| 2350 | if (prefix.len != 0) a.addSourceAssumeCapacity(prefix); | ||
| 2351 | _ = a.variableChar(0, 1, digits); | ||
| 2352 | } | ||
| 2353 | |||
| 2354 | /// Does not include 'skip'. Does not add any token tag. | ||
| 2355 | fn stringLiteralSingleInner(a: *AstSmith) SourceError!void { | ||
| 2356 | try a.addSourceByte('"'); | ||
| 2357 | while (!a.smith.eosWeightedSimple(3, 1)) { | ||
| 2358 | try a.pegChar('"'); | ||
| 2359 | } | ||
| 2360 | try a.addSourceByte('"'); | ||
| 2361 | } | ||
| 2362 | |||
| 2363 | /// STRINGLITERALSINGLE <- ["] string_char* ["] skip | ||
| 2364 | fn pegStringLiteralSingle(a: *AstSmith) SourceError!void { | ||
| 2365 | try a.addTokenTag(.string_literal); | ||
| 2366 | try a.stringLiteralSingleInner(); | ||
| 2367 | try a.pegSkip(); | ||
| 2368 | } | ||
| 2369 | |||
| 2370 | /// STRINGLITERAL | ||
| 2371 | /// <- STRINGLITERALSINGLE | ||
| 2372 | /// / (line_string skip)+ | ||
| 2373 | fn pegStringLiteral(a: *AstSmith) SourceError!void { | ||
| 2374 | if (a.smith.value(bool)) { | ||
| 2375 | try a.pegStringLiteralSingle(); | ||
| 2376 | } else { | ||
| 2377 | while (true) { | ||
| 2378 | try a.pegLineString(); | ||
| 2379 | try a.pegSkip(); | ||
| 2380 | if (a.smith.eos()) break; | ||
| 2381 | } | ||
| 2382 | } | ||
| 2383 | } | ||
| 2384 | |||
| 2385 | const alphanumeric_weights: [4]Weight = .{ | ||
| 2386 | .rangeAtMost(u8, '0', '9', 1), | ||
| 2387 | .rangeAtMost(u8, 'A', 'Z', 1), | ||
| 2388 | .rangeAtMost(u8, 'a', 'z', 1), | ||
| 2389 | .value(u8, '_', 1), | ||
| 2390 | }; | ||
| 2391 | |||
| 2392 | /// IDENTIFIER | ||
| 2393 | /// <- !keyword [A-Za-z_] [A-Za-z0-9_]* skip | ||
| 2394 | /// / '@' STRINGLITERALSINGLE | ||
| 2395 | fn pegIdentifier(a: *AstSmith) SourceError!void { | ||
| 2396 | const Kind = enum(u2) { underscore, regular_identifier, quoted_identifier, copy_identifier }; | ||
| 2397 | const kind_weights: [4]Weight = .{ | ||
| 2398 | .value(Kind, .underscore, 6), | ||
| 2399 | .value(Kind, .regular_identifier, 3), | ||
| 2400 | .value(Kind, .quoted_identifier, 1), | ||
| 2401 | .value(Kind, .copy_identifier, 6), | ||
| 2402 | }; | ||
| 2403 | const n_weights = @as(usize, kind_weights.len) - @intFromBool(a.prev_ids_len == 0); | ||
| 2404 | const kind = a.smith.valueWeighted(Kind, kind_weights[0..n_weights]); | ||
| 2405 | |||
| 2406 | switch (kind) { | ||
| 2407 | .underscore => { | ||
| 2408 | try a.preservePegEndOfWord(); | ||
| 2409 | try a.addTokenTag(.identifier); | ||
| 2410 | try a.addSourceByte('_'); | ||
| 2411 | }, | ||
| 2412 | .regular_identifier => { | ||
| 2413 | try a.preservePegEndOfWord(); | ||
| 2414 | try a.addTokenTag(.identifier); | ||
| 2415 | |||
| 2416 | const start = a.source_len; | ||
| 2417 | try a.addSourceByte(a.smith.valueWeighted(u8, alphanumeric_weights[1..])); | ||
| 2418 | _ = a.variableChar(0, 0, &alphanumeric_weights); | ||
| 2419 | |||
| 2420 | if (Token.getKeyword(a.source_buf[start..a.source_len]) != null) { | ||
| 2421 | a.source_buf[start] = '_'; // No keywords start with '_' | ||
| 2422 | } | ||
| 2423 | }, | ||
| 2424 | .quoted_identifier => { | ||
| 2425 | try a.addTokenTag(.identifier); | ||
| 2426 | try a.addSourceByte('@'); | ||
| 2427 | try a.stringLiteralSingleInner(); | ||
| 2428 | }, | ||
| 2429 | .copy_identifier => { | ||
| 2430 | const n_prev = @min(a.prev_ids_len, a.prev_ids_buf.len); | ||
| 2431 | const prev_i = a.smith.valueRangeLessThan(u16, 0, n_prev); | ||
| 2432 | const prev = a.prev_ids_buf[prev_i]; | ||
| 2433 | |||
| 2434 | if (a.source_buf[prev.start] != '@') try a.preservePegEndOfWord(); | ||
| 2435 | try a.addTokenTag(.identifier); | ||
| 2436 | try a.addSource(a.source_buf[prev.start..][0..prev.len]); | ||
| 2437 | }, | ||
| 2438 | } | ||
| 2439 | try a.pegSkip(); | ||
| 2440 | if (kind != .copy_identifier) { | ||
| 2441 | const start = a.token_start_buf[a.tokens_len - 1]; | ||
| 2442 | a.prev_ids_buf[a.prev_ids_len % a.prev_ids_buf.len] = .{ | ||
| 2443 | .start = @intCast(start), | ||
| 2444 | .len = @intCast(a.source_len - start), | ||
| 2445 | }; | ||
| 2446 | a.prev_ids_len += 1; | ||
| 2447 | } | ||
| 2448 | } | ||
| 2449 | |||
| 2450 | /// BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip | ||
| 2451 | fn pegBuiltinIdentifier(a: *AstSmith) SourceError!void { | ||
| 2452 | try a.addTokenTag(.builtin); | ||
| 2453 | if (a.smith.boolWeighted(1, 31)) { | ||
| 2454 | if (a.smith.boolWeighted(1, 8)) { | ||
| 2455 | // Pointer cast (reordable with zig fmt) | ||
| 2456 | const ids = [_][]const u8{ | ||
| 2457 | "@ptrCast", | ||
| 2458 | "@addrspaceCast", | ||
| 2459 | "@alignCast", | ||
| 2460 | "@constCast", | ||
| 2461 | "@volatileCast", | ||
| 2462 | }; | ||
| 2463 | try a.addSource(ids[a.smith.index(ids.len)]); | ||
| 2464 | } else { | ||
| 2465 | const ids = std.zig.BuiltinFn.list.keys(); | ||
| 2466 | try a.addSource(ids[a.smith.index(ids.len)]); | ||
| 2467 | } | ||
| 2468 | } else { | ||
| 2469 | try a.ensureSourceCapacity(2); | ||
| 2470 | a.addSourceByteAssumeCapacity('@'); | ||
| 2471 | a.addSourceByteAssumeCapacity(a.smith.valueWeighted(u8, alphanumeric_weights[1..])); | ||
| 2472 | _ = a.variableChar(0, 0, &alphanumeric_weights); | ||
| 2473 | } | ||
| 2474 | try a.pegSkip(); | ||
| 2475 | } | ||
| 2476 | |||
| 2477 | test AstSmith { | ||
| 2478 | try std.testing.fuzz({}, checkGenerated, .{}); | ||
| 2479 | } | ||
| 2480 | |||
| 2481 | fn checkGenerated(_: void, smith: *Smith) !void { | ||
| 2482 | var a: AstSmith = .init(smith); | ||
| 2483 | try a.generateSource(); | ||
| 2484 | |||
| 2485 | { // Check tokenization matches source | ||
| 2486 | errdefer a.logBadSource(null); | ||
| 2487 | |||
| 2488 | const token_tags = a.token_tag_buf[0..a.tokens_len]; | ||
| 2489 | const token_starts = a.token_start_buf[0..a.tokens_len]; | ||
| 2490 | try std.testing.expectEqual(Token.Tag.eof, token_tags[token_tags.len - 1]); | ||
| 2491 | |||
| 2492 | var tokenizer: std.zig.Tokenizer = .init(a.source()); | ||
| 2493 | for (token_tags, token_starts) |tag, start| { | ||
| 2494 | const tok = tokenizer.next(); | ||
| 2495 | try std.testing.expectEqual(tok.tag, tag); | ||
| 2496 | try std.testing.expectEqual(tok.loc.start, start); | ||
| 2497 | if (tag == .invalid) return error.InvalidToken; | ||
| 2498 | } | ||
| 2499 | } | ||
| 2500 | |||
| 2501 | var fba_buf: [1 << 18]u8 = undefined; | ||
| 2502 | var fba: std.heap.FixedBufferAllocator = .init(&fba_buf); | ||
| 2503 | const ast = std.zig.Ast.parseTokens(fba.allocator(), a.source(), a.tokens(), .zig) catch | ||
| 2504 | return error.SkipZigTest; | ||
| 2505 | |||
| 2506 | errdefer a.logBadSource(ast); | ||
| 2507 | try std.testing.expectEqual(0, ast.errors.len); | ||
| 2508 | } | ||
| 2509 | |||
| 2510 | fn logBadSource(a: *AstSmith, ast: ?std.zig.Ast) void { | ||
| 2511 | var buf: [256]u8 = undefined; | ||
| 2512 | const ls = std.debug.lockStderr(&buf); | ||
| 2513 | defer std.debug.unlockStderr(); | ||
| 2514 | a.logBadSourceInner(ls.terminal(), ast) catch {}; | ||
| 2515 | } | ||
| 2516 | |||
| 2517 | fn logBadSourceInner(a: *AstSmith, t: std.Io.Terminal, ast: ?std.zig.Ast) std.Io.Writer.Error!void { | ||
| 2518 | try a.logSourceInner(t); | ||
| 2519 | const w = t.writer; | ||
| 2520 | |||
| 2521 | if (ast) |bad_ast| { | ||
| 2522 | try w.writeAll("=== Parse Errors ===\n"); | ||
| 2523 | for (bad_ast.errors) |err| { | ||
| 2524 | const loc = bad_ast.tokenLocation(0, err.token); | ||
| 2525 | try w.print("{}:{}: ", .{ loc.line + 1, loc.column + 1 }); | ||
| 2526 | try bad_ast.renderError(err, w); | ||
| 2527 | try w.writeByte('\n'); | ||
| 2528 | } | ||
| 2529 | } else { | ||
| 2530 | t.setColor(.dim) catch {}; | ||
| 2531 | try w.writeAll("=== Tokens ===\n"); | ||
| 2532 | t.setColor(.reset) catch {}; | ||
| 2533 | for ( | ||
| 2534 | 0.., | ||
| 2535 | a.token_tag_buf[0..a.tokens_len], | ||
| 2536 | a.token_start_buf[0..a.tokens_len], | ||
| 2537 | ) |i, tag, start| { | ||
| 2538 | try w.print("#{} @{}: {t}\n", .{ i, start, tag }); | ||
| 2539 | } | ||
| 2540 | |||
| 2541 | t.setColor(.dim) catch {}; | ||
| 2542 | try w.writeAll("\n=== Expected Tokens ===\n"); | ||
| 2543 | t.setColor(.reset) catch {}; | ||
| 2544 | |||
| 2545 | var tokenizer: std.zig.Tokenizer = .init(a.source()); | ||
| 2546 | var i: usize = 0; | ||
| 2547 | while (true) { | ||
| 2548 | const tok = tokenizer.next(); | ||
| 2549 | try w.print("#{} @{}-{}: {t}\n", .{ i, tok.loc.start, tok.loc.end, tok.tag }); | ||
| 2550 | i += 1; | ||
| 2551 | if (tok.tag == .invalid or tok.tag == .eof) break; | ||
| 2552 | } | ||
| 2553 | } | ||
| 2554 | } | ||
| 2555 | |||
| 2556 | pub fn logSource(a: *AstSmith) void { | ||
| 2557 | var buf: [256]u8 = undefined; | ||
| 2558 | const ls = std.debug.lockStderr(&buf); | ||
| 2559 | defer std.debug.unlockStderr(); | ||
| 2560 | a.logSourceInner(ls.terminal()) catch {}; | ||
| 2561 | } | ||
| 2562 | |||
| 2563 | fn logSourceInner(a: *AstSmith, t: std.Io.Terminal) std.Io.Writer.Error!void { | ||
| 2564 | const w = t.writer; | ||
| 2565 | |||
| 2566 | t.setColor(.dim) catch {}; | ||
| 2567 | try w.writeAll("=== Source ===\n"); | ||
| 2568 | t.setColor(.reset) catch {}; | ||
| 2569 | |||
| 2570 | var line: usize = 1; | ||
| 2571 | try w.print("{: >5} ", .{line}); | ||
| 2572 | for (a.source()) |c| switch (c) { | ||
| 2573 | ' '...0x7e => try w.writeByte(c), | ||
| 2574 | '\n' => { | ||
| 2575 | line += 1; | ||
| 2576 | try w.print("\n{: >5} ", .{line}); | ||
| 2577 | }, | ||
| 2578 | '\r' => { | ||
| 2579 | t.setColor(.cyan) catch {}; | ||
| 2580 | try w.writeAll("\\r"); | ||
| 2581 | t.setColor(.reset) catch {}; | ||
| 2582 | }, | ||
| 2583 | '\t' => { | ||
| 2584 | t.setColor(.cyan) catch {}; | ||
| 2585 | try w.writeAll("\\t"); | ||
| 2586 | t.setColor(.reset) catch {}; | ||
| 2587 | }, | ||
| 2588 | else => { | ||
| 2589 | t.setColor(.cyan) catch {}; | ||
| 2590 | try w.print("\\x{x:0>2}", .{c}); | ||
| 2591 | t.setColor(.reset) catch {}; | ||
| 2592 | }, | ||
| 2593 | }; | ||
| 2594 | try w.writeByte('\n'); | ||
| 2595 | } | ||
lib/std/zig/Parse.zig+272-256| ... | @@ -1,5 +1,18 @@ | ... | @@ -1,5 +1,18 @@ |
| 1 | //! Represents in-progress parsing, will be converted to an Ast after completion. | 1 | //! Represents in-progress parsing, will be converted to an Ast after completion. |
| 2 | 2 | ||
| 3 | // This recursive descent parser must be "predictive," using only constant | ||
| 4 | // token lookahead and never backtracking. | ||
| 5 | // | ||
| 6 | // This means that whenever the parser encounters a choice it is allowed to look | ||
| 7 | // at the next k tokens in order to make that choice, where k is a fixed constant. | ||
| 8 | // | ||
| 9 | // Once the parser has made the choice, it must either succeed at parsing that sub | ||
| 10 | // expression or fail entirely and present an error to the user. The parser is never | ||
| 11 | // allowed to backtrack and make a different choice to see if that one succeeds. | ||
| 12 | // | ||
| 13 | // This ensures worst-case linear runtime rather than worst-case exponential runtime | ||
| 14 | // and requires the Zig grammar to be LL(k). | ||
| 15 | |||
| 3 | pub const Error = error{ParseError} || Allocator.Error; | 16 | pub const Error = error{ParseError} || Allocator.Error; |
| 4 | 17 | ||
| 5 | gpa: Allocator, | 18 | gpa: Allocator, |
| ... | @@ -10,6 +23,7 @@ errors: std.ArrayList(AstError), | ... | @@ -10,6 +23,7 @@ errors: std.ArrayList(AstError), |
| 10 | nodes: Ast.NodeList, | 23 | nodes: Ast.NodeList, |
| 11 | extra_data: std.ArrayList(u32), | 24 | extra_data: std.ArrayList(u32), |
| 12 | scratch: std.ArrayList(Node.Index), | 25 | scratch: std.ArrayList(Node.Index), |
| 26 | recover: bool, | ||
| 13 | 27 | ||
| 14 | fn tokenTag(p: *const Parse, token_index: TokenIndex) Token.Tag { | 28 | fn tokenTag(p: *const Parse, token_index: TokenIndex) Token.Tag { |
| 15 | return p.tokens.items(.tag)[token_index]; | 29 | return p.tokens.items(.tag)[token_index]; |
| ... | @@ -108,7 +122,7 @@ fn addExtra(p: *Parse, extra: anytype) Allocator.Error!ExtraIndex { | ... | @@ -108,7 +122,7 @@ fn addExtra(p: *Parse, extra: anytype) Allocator.Error!ExtraIndex { |
| 108 | return result; | 122 | return result; |
| 109 | } | 123 | } |
| 110 | 124 | ||
| 111 | fn warnExpected(p: *Parse, expected_token: Token.Tag) error{OutOfMemory}!void { | 125 | fn warnExpected(p: *Parse, expected_token: Token.Tag) Error!void { |
| 112 | @branchHint(.cold); | 126 | @branchHint(.cold); |
| 113 | try p.warnMsg(.{ | 127 | try p.warnMsg(.{ |
| 114 | .tag = .expected_token, | 128 | .tag = .expected_token, |
| ... | @@ -117,12 +131,12 @@ fn warnExpected(p: *Parse, expected_token: Token.Tag) error{OutOfMemory}!void { | ... | @@ -117,12 +131,12 @@ fn warnExpected(p: *Parse, expected_token: Token.Tag) error{OutOfMemory}!void { |
| 117 | }); | 131 | }); |
| 118 | } | 132 | } |
| 119 | 133 | ||
| 120 | fn warn(p: *Parse, error_tag: AstError.Tag) error{OutOfMemory}!void { | 134 | fn warn(p: *Parse, error_tag: AstError.Tag) Error!void { |
| 121 | @branchHint(.cold); | 135 | @branchHint(.cold); |
| 122 | try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i }); | 136 | try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i }); |
| 123 | } | 137 | } |
| 124 | 138 | ||
| 125 | fn warnMsg(p: *Parse, msg: Ast.Error) error{OutOfMemory}!void { | 139 | fn warnMsg(p: *Parse, msg: Ast.Error) Error!void { |
| 126 | @branchHint(.cold); | 140 | @branchHint(.cold); |
| 127 | switch (msg.tag) { | 141 | switch (msg.tag) { |
| 128 | .expected_semi_after_decl, | 142 | .expected_semi_after_decl, |
| ... | @@ -161,11 +175,13 @@ fn warnMsg(p: *Parse, msg: Ast.Error) error{OutOfMemory}!void { | ... | @@ -161,11 +175,13 @@ fn warnMsg(p: *Parse, msg: Ast.Error) error{OutOfMemory}!void { |
| 161 | var copy = msg; | 175 | var copy = msg; |
| 162 | copy.token_is_prev = true; | 176 | copy.token_is_prev = true; |
| 163 | copy.token -= 1; | 177 | copy.token -= 1; |
| 164 | return p.errors.append(p.gpa, copy); | 178 | try p.errors.append(p.gpa, copy); |
| 179 | } else { | ||
| 180 | try p.errors.append(p.gpa, msg); | ||
| 165 | }, | 181 | }, |
| 166 | else => {}, | 182 | else => try p.errors.append(p.gpa, msg), |
| 167 | } | 183 | } |
| 168 | try p.errors.append(p.gpa, msg); | 184 | if (!p.recover) return error.ParseError; |
| 169 | } | 185 | } |
| 170 | 186 | ||
| 171 | fn fail(p: *Parse, tag: Ast.Error.Tag) error{ ParseError, OutOfMemory } { | 187 | fn fail(p: *Parse, tag: Ast.Error.Tag) error{ ParseError, OutOfMemory } { |
| ... | @@ -189,17 +205,29 @@ fn failMsg(p: *Parse, msg: Ast.Error) error{ ParseError, OutOfMemory } { | ... | @@ -189,17 +205,29 @@ fn failMsg(p: *Parse, msg: Ast.Error) error{ ParseError, OutOfMemory } { |
| 189 | } | 205 | } |
| 190 | 206 | ||
| 191 | /// Root <- skip ContainerMembers eof | 207 | /// Root <- skip ContainerMembers eof |
| 192 | pub fn parseRoot(p: *Parse) !void { | 208 | pub fn parseRoot(p: *Parse) Allocator.Error!void { |
| 193 | // Root node must be index 0. | 209 | // Root node must be index 0. |
| 194 | p.nodes.appendAssumeCapacity(.{ | 210 | p.nodes.appendAssumeCapacity(.{ |
| 195 | .tag = .root, | 211 | .tag = .root, |
| 196 | .main_token = 0, | 212 | .main_token = 0, |
| 197 | .data = undefined, | 213 | .data = undefined, |
| 198 | }); | 214 | }); |
| 199 | const root_members = try p.parseContainerMembers(); | 215 | const root_members = p.parseContainerMembers() catch |err| switch (err) { |
| 216 | error.OutOfMemory => |e| return e, | ||
| 217 | error.ParseError => { | ||
| 218 | assert(p.errors.items.len > 0); | ||
| 219 | return; | ||
| 220 | }, | ||
| 221 | }; | ||
| 200 | const root_decls = try root_members.toSpan(p); | 222 | const root_decls = try root_members.toSpan(p); |
| 201 | if (p.tokenTag(p.tok_i) != .eof) { | 223 | if (p.tokenTag(p.tok_i) != .eof) { |
| 202 | try p.warnExpected(.eof); | 224 | p.warnExpected(.eof) catch |err| switch (err) { |
| 225 | error.OutOfMemory => |e| return e, | ||
| 226 | error.ParseError => { | ||
| 227 | assert(p.errors.items.len > 0); | ||
| 228 | return; | ||
| 229 | }, | ||
| 230 | }; | ||
| 203 | } | 231 | } |
| 204 | p.nodes.items(.data)[0] = .{ .extra_range = root_decls }; | 232 | p.nodes.items(.data)[0] = .{ .extra_range = root_decls }; |
| 205 | } | 233 | } |
| ... | @@ -207,7 +235,7 @@ pub fn parseRoot(p: *Parse) !void { | ... | @@ -207,7 +235,7 @@ pub fn parseRoot(p: *Parse) !void { |
| 207 | /// Parse in ZON mode. Subset of the language. | 235 | /// Parse in ZON mode. Subset of the language. |
| 208 | /// TODO: set a flag in Parse struct, and honor that flag | 236 | /// TODO: set a flag in Parse struct, and honor that flag |
| 209 | /// by emitting compilation errors when non-zon nodes are encountered. | 237 | /// by emitting compilation errors when non-zon nodes are encountered. |
| 210 | pub fn parseZon(p: *Parse) !void { | 238 | pub fn parseZon(p: *Parse) Allocator.Error!void { |
| 211 | // We must use index 0 so that 0 can be used as null elsewhere. | 239 | // We must use index 0 so that 0 can be used as null elsewhere. |
| 212 | p.nodes.appendAssumeCapacity(.{ | 240 | p.nodes.appendAssumeCapacity(.{ |
| 213 | .tag = .root, | 241 | .tag = .root, |
| ... | @@ -222,7 +250,13 @@ pub fn parseZon(p: *Parse) !void { | ... | @@ -222,7 +250,13 @@ pub fn parseZon(p: *Parse) !void { |
| 222 | else => |e| return e, | 250 | else => |e| return e, |
| 223 | }; | 251 | }; |
| 224 | if (p.tokenTag(p.tok_i) != .eof) { | 252 | if (p.tokenTag(p.tok_i) != .eof) { |
| 225 | try p.warnExpected(.eof); | 253 | p.warnExpected(.eof) catch |err| switch (err) { |
| 254 | error.OutOfMemory => |e| return e, | ||
| 255 | error.ParseError => { | ||
| 256 | assert(p.errors.items.len > 0); | ||
| 257 | return; | ||
| 258 | }, | ||
| 259 | }; | ||
| 226 | } | 260 | } |
| 227 | p.nodes.items(.data)[0] = .{ .node = node_index }; | 261 | p.nodes.items(.data)[0] = .{ .node = node_index }; |
| 228 | } | 262 | } |
| ... | @@ -232,7 +266,7 @@ pub fn parseZon(p: *Parse) !void { | ... | @@ -232,7 +266,7 @@ pub fn parseZon(p: *Parse) !void { |
| 232 | /// ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl | 266 | /// ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl |
| 233 | /// | 267 | /// |
| 234 | /// ComptimeDecl <- KEYWORD_comptime Block | 268 | /// ComptimeDecl <- KEYWORD_comptime Block |
| 235 | fn parseContainerMembers(p: *Parse) Allocator.Error!Members { | 269 | fn parseContainerMembers(p: *Parse) Error!Members { |
| 236 | const scratch_top = p.scratch.items.len; | 270 | const scratch_top = p.scratch.items.len; |
| 237 | defer p.scratch.shrinkRetainingCapacity(scratch_top); | 271 | defer p.scratch.shrinkRetainingCapacity(scratch_top); |
| 238 | 272 | ||
| ... | @@ -300,13 +334,6 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { | ... | @@ -300,13 +334,6 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { |
| 300 | else => { | 334 | else => { |
| 301 | const identifier = p.tok_i; | 335 | const identifier = p.tok_i; |
| 302 | defer last_field = identifier; | 336 | defer last_field = identifier; |
| 303 | const container_field = p.expectContainerField() catch |err| switch (err) { | ||
| 304 | error.OutOfMemory => |e| return e, | ||
| 305 | error.ParseError => { | ||
| 306 | p.findNextContainerMember(); | ||
| 307 | continue; | ||
| 308 | }, | ||
| 309 | }; | ||
| 310 | switch (field_state) { | 337 | switch (field_state) { |
| 311 | .none => field_state = .seen, | 338 | .none => field_state = .seen, |
| 312 | .err, .seen => {}, | 339 | .err, .seen => {}, |
| ... | @@ -329,6 +356,13 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { | ... | @@ -329,6 +356,13 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { |
| 329 | field_state = .err; | 356 | field_state = .err; |
| 330 | }, | 357 | }, |
| 331 | } | 358 | } |
| 359 | const container_field = p.expectContainerField() catch |err| switch (err) { | ||
| 360 | error.OutOfMemory => |e| return e, | ||
| 361 | error.ParseError => { | ||
| 362 | p.findNextContainerMember(); | ||
| 363 | continue; | ||
| 364 | }, | ||
| 365 | }; | ||
| 332 | try p.scratch.append(p.gpa, container_field); | 366 | try p.scratch.append(p.gpa, container_field); |
| 333 | switch (p.tokenTag(p.tok_i)) { | 367 | switch (p.tokenTag(p.tok_i)) { |
| 334 | .comma => { | 368 | .comma => { |
| ... | @@ -405,13 +439,6 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { | ... | @@ -405,13 +439,6 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { |
| 405 | 439 | ||
| 406 | const identifier = p.tok_i; | 440 | const identifier = p.tok_i; |
| 407 | defer last_field = identifier; | 441 | defer last_field = identifier; |
| 408 | const container_field = p.expectContainerField() catch |err| switch (err) { | ||
| 409 | error.OutOfMemory => |e| return e, | ||
| 410 | error.ParseError => { | ||
| 411 | p.findNextContainerMember(); | ||
| 412 | continue; | ||
| 413 | }, | ||
| 414 | }; | ||
| 415 | switch (field_state) { | 442 | switch (field_state) { |
| 416 | .none => field_state = .seen, | 443 | .none => field_state = .seen, |
| 417 | .err, .seen => {}, | 444 | .err, .seen => {}, |
| ... | @@ -434,6 +461,13 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { | ... | @@ -434,6 +461,13 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { |
| 434 | field_state = .err; | 461 | field_state = .err; |
| 435 | }, | 462 | }, |
| 436 | } | 463 | } |
| 464 | const container_field = p.expectContainerField() catch |err| switch (err) { | ||
| 465 | error.OutOfMemory => |e| return e, | ||
| 466 | error.ParseError => { | ||
| 467 | p.findNextContainerMember(); | ||
| 468 | continue; | ||
| 469 | }, | ||
| 470 | }; | ||
| 437 | try p.scratch.append(p.gpa, container_field); | 471 | try p.scratch.append(p.gpa, container_field); |
| 438 | switch (p.tokenTag(p.tok_i)) { | 472 | switch (p.tokenTag(p.tok_i)) { |
| 439 | .comma => { | 473 | .comma => { |
| ... | @@ -484,6 +518,12 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { | ... | @@ -484,6 +518,12 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members { |
| 484 | 518 | ||
| 485 | /// Attempts to find next container member by searching for certain tokens | 519 | /// Attempts to find next container member by searching for certain tokens |
| 486 | fn findNextContainerMember(p: *Parse) void { | 520 | fn findNextContainerMember(p: *Parse) void { |
| 521 | if (!p.recover) { | ||
| 522 | while (p.tokenTag(p.tok_i) != .eof) { | ||
| 523 | p.tok_i += 1; | ||
| 524 | } | ||
| 525 | return; | ||
| 526 | } | ||
| 487 | var level: u32 = 0; | 527 | var level: u32 = 0; |
| 488 | while (true) { | 528 | while (true) { |
| 489 | const tok = p.nextToken(); | 529 | const tok = p.nextToken(); |
| ... | @@ -541,6 +581,12 @@ fn findNextContainerMember(p: *Parse) void { | ... | @@ -541,6 +581,12 @@ fn findNextContainerMember(p: *Parse) void { |
| 541 | 581 | ||
| 542 | /// Attempts to find the next statement by searching for a semicolon | 582 | /// Attempts to find the next statement by searching for a semicolon |
| 543 | fn findNextStmt(p: *Parse) void { | 583 | fn findNextStmt(p: *Parse) void { |
| 584 | if (!p.recover) { | ||
| 585 | while (p.tokenTag(p.tok_i) != .eof) { | ||
| 586 | p.tok_i += 1; | ||
| 587 | } | ||
| 588 | return; | ||
| 589 | } | ||
| 544 | var level: u32 = 0; | 590 | var level: u32 = 0; |
| 545 | while (true) { | 591 | while (true) { |
| 546 | const tok = p.nextToken(); | 592 | const tok = p.nextToken(); |
| ... | @@ -864,7 +910,7 @@ fn parseGlobalVarDecl(p: *Parse) !?Node.Index { | ... | @@ -864,7 +910,7 @@ fn parseGlobalVarDecl(p: *Parse) !?Node.Index { |
| 864 | return var_decl; | 910 | return var_decl; |
| 865 | } | 911 | } |
| 866 | 912 | ||
| 867 | /// ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)? | 913 | // ContainerField <- doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)? |
| 868 | fn expectContainerField(p: *Parse) !Node.Index { | 914 | fn expectContainerField(p: *Parse) !Node.Index { |
| 869 | _ = p.eatToken(.keyword_comptime); | 915 | _ = p.eatToken(.keyword_comptime); |
| 870 | const main_token = p.tok_i; | 916 | const main_token = p.tok_i; |
| ... | @@ -910,18 +956,21 @@ fn expectContainerField(p: *Parse) !Node.Index { | ... | @@ -910,18 +956,21 @@ fn expectContainerField(p: *Parse) !Node.Index { |
| 910 | /// <- Statement | 956 | /// <- Statement |
| 911 | /// / KEYWORD_defer BlockExprStatement | 957 | /// / KEYWORD_defer BlockExprStatement |
| 912 | /// / KEYWORD_errdefer BlockExprStatement | 958 | /// / KEYWORD_errdefer BlockExprStatement |
| 913 | /// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement | 959 | /// / !StatementPrefix KEYWORD_comptime? VarAssignStatement |
| 914 | /// | 960 | /// |
| 915 | /// Statement | 961 | /// Statement |
| 916 | /// <- ExprStatement | ||
| 917 | /// / KEYWORD_suspend BlockExprStatement | ||
| 918 | /// / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON | ||
| 919 | /// | ||
| 920 | /// ExprStatement | ||
| 921 | /// <- IfStatement | 962 | /// <- IfStatement |
| 922 | /// / LabeledStatement | 963 | /// / LabeledStatement |
| 923 | /// / KEYWORD_nosuspend BlockExprStatement | 964 | /// / KEYWORD_nosuspend BlockExprStatement |
| 924 | /// / KEYWORD_comptime BlockExpr | 965 | /// / KEYWORD_comptime BlockExpr |
| 966 | /// / KEYWORD_suspend BlockExprStatement | ||
| 967 | /// / !StatementPrefix KEYWORD_comptime? AssignExpr SEMICOLON | ||
| 968 | /// | ||
| 969 | /// StatementPrefix | ||
| 970 | /// <- KEYWORD_if | ||
| 971 | /// / BlockLabel? (LBRACE / KEYWORD_inline? (KEYWORD_for / KEYWORD_while) / KEYWORD_switch) | ||
| 972 | /// / KEYWORD_nosuspend | ||
| 973 | /// / KEYWORD_comptime BlockExprPrefix | ||
| 925 | fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { | 974 | fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { |
| 926 | if (p.eatToken(.keyword_comptime)) |comptime_token| { | 975 | if (p.eatToken(.keyword_comptime)) |comptime_token| { |
| 927 | const opt_block_expr = try p.parseBlockExpr(); | 976 | const opt_block_expr = try p.parseBlockExpr(); |
| ... | @@ -934,7 +983,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { | ... | @@ -934,7 +983,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { |
| 934 | } | 983 | } |
| 935 | 984 | ||
| 936 | if (is_block_level) { | 985 | if (is_block_level) { |
| 937 | return p.expectVarDeclExprStatement(comptime_token); | 986 | return p.expectVarAssignStatement(comptime_token); |
| 938 | } else { | 987 | } else { |
| 939 | const assign = try p.expectAssignExpr(); | 988 | const assign = try p.expectAssignExpr(); |
| 940 | try p.expectSemicolon(.expected_semi_after_stmt, true); | 989 | try p.expectSemicolon(.expected_semi_after_stmt, true); |
| ... | @@ -995,7 +1044,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { | ... | @@ -995,7 +1044,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { |
| 995 | if (try p.parseLabeledStatement()) |labeled_statement| return labeled_statement; | 1044 | if (try p.parseLabeledStatement()) |labeled_statement| return labeled_statement; |
| 996 | 1045 | ||
| 997 | if (is_block_level) { | 1046 | if (is_block_level) { |
| 998 | return p.expectVarDeclExprStatement(null); | 1047 | return p.expectVarAssignStatement(null); |
| 999 | } else { | 1048 | } else { |
| 1000 | const assign = try p.expectAssignExpr(); | 1049 | const assign = try p.expectAssignExpr(); |
| 1001 | try p.expectSemicolon(.expected_semi_after_stmt, true); | 1050 | try p.expectSemicolon(.expected_semi_after_stmt, true); |
| ... | @@ -1003,30 +1052,8 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { | ... | @@ -1003,30 +1052,8 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index { |
| 1003 | } | 1052 | } |
| 1004 | } | 1053 | } |
| 1005 | 1054 | ||
| 1006 | /// ComptimeStatement | ||
| 1007 | /// <- BlockExpr | ||
| 1008 | /// / VarDeclExprStatement | ||
| 1009 | fn expectComptimeStatement(p: *Parse, comptime_token: TokenIndex) !Node.Index { | ||
| 1010 | const maybe_block_expr = try p.parseBlockExpr(); | ||
| 1011 | if (maybe_block_expr) |block_expr| { | ||
| 1012 | return p.addNode(.{ | ||
| 1013 | .tag = .@"comptime", | ||
| 1014 | .main_token = comptime_token, | ||
| 1015 | .data = .{ | ||
| 1016 | .lhs = .{ .node = block_expr }, | ||
| 1017 | .rhs = undefined, | ||
| 1018 | }, | ||
| 1019 | }); | ||
| 1020 | } | ||
| 1021 | return p.expectVarDeclExprStatement(comptime_token); | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | /// VarDeclExprStatement | ||
| 1025 | /// <- Expr | ||
| 1026 | /// / VarAssignStatement | ||
| 1027 | /// | ||
| 1028 | /// VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON | 1055 | /// VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON |
| 1029 | fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index { | 1056 | fn expectVarAssignStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index { |
| 1030 | const scratch_top = p.scratch.items.len; | 1057 | const scratch_top = p.scratch.items.len; |
| 1031 | defer p.scratch.shrinkRetainingCapacity(scratch_top); | 1058 | defer p.scratch.shrinkRetainingCapacity(scratch_top); |
| 1032 | 1059 | ||
| ... | @@ -1138,7 +1165,7 @@ fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Inde | ... | @@ -1138,7 +1165,7 @@ fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Inde |
| 1138 | 1165 | ||
| 1139 | /// If a parse error occurs, reports an error, but then finds the next statement | 1166 | /// If a parse error occurs, reports an error, but then finds the next statement |
| 1140 | /// and returns that one instead. If a parse error occurs but there is no following | 1167 | /// and returns that one instead. If a parse error occurs but there is no following |
| 1141 | /// statement, returns 0. | 1168 | /// statement, returns null. |
| 1142 | fn expectStatementRecoverable(p: *Parse) Error!?Node.Index { | 1169 | fn expectStatementRecoverable(p: *Parse) Error!?Node.Index { |
| 1143 | while (true) { | 1170 | while (true) { |
| 1144 | return p.expectStatement(true) catch |err| switch (err) { | 1171 | return p.expectStatement(true) catch |err| switch (err) { |
| ... | @@ -1156,8 +1183,10 @@ fn expectStatementRecoverable(p: *Parse) Error!?Node.Index { | ... | @@ -1156,8 +1183,10 @@ fn expectStatementRecoverable(p: *Parse) Error!?Node.Index { |
| 1156 | } | 1183 | } |
| 1157 | 1184 | ||
| 1158 | /// IfStatement | 1185 | /// IfStatement |
| 1159 | /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? | 1186 | /// <- IfPrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else) |
| 1160 | /// / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | 1187 | /// / IfPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement) |
| 1188 | /// | ||
| 1189 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? | ||
| 1161 | fn expectIfStatement(p: *Parse) !Node.Index { | 1190 | fn expectIfStatement(p: *Parse) !Node.Index { |
| 1162 | const if_token = p.assertToken(.keyword_if); | 1191 | const if_token = p.assertToken(.keyword_if); |
| 1163 | _ = try p.expectToken(.l_paren); | 1192 | _ = try p.expectToken(.l_paren); |
| ... | @@ -1226,13 +1255,17 @@ fn parseLabeledStatement(p: *Parse) !?Node.Index { | ... | @@ -1226,13 +1255,17 @@ fn parseLabeledStatement(p: *Parse) !?Node.Index { |
| 1226 | const label_token = opt_label_token orelse return null; | 1255 | const label_token = opt_label_token orelse return null; |
| 1227 | 1256 | ||
| 1228 | const after_colon = p.tok_i; | 1257 | const after_colon = p.tok_i; |
| 1229 | if (try p.parseTypeExpr()) |_| { | 1258 | // Don't bother trying to give a better error message if recovery is disabled. |
| 1230 | const a = try p.parseByteAlign(); | 1259 | // This avoids a possible stack overflow in e.g. parseTypeExpr() when fuzzing. |
| 1231 | const b = try p.parseAddrSpace(); | 1260 | if (p.recover) { |
| 1232 | const c = try p.parseLinkSection(); | 1261 | if (try p.parseTypeExpr()) |_| { |
| 1233 | const d = if (p.eatToken(.equal) == null) null else try p.expectExpr(); | 1262 | const a = try p.parseByteAlign(); |
| 1234 | if (a != null or b != null or c != null or d != null) { | 1263 | const b = try p.parseAddrSpace(); |
| 1235 | return p.failMsg(.{ .tag = .expected_var_const, .token = label_token }); | 1264 | const c = try p.parseLinkSection(); |
| 1265 | const d = if (p.eatToken(.equal) == null) null else try p.expectExpr(); | ||
| 1266 | if (a != null or b != null or c != null or d != null) { | ||
| 1267 | return p.failMsg(.{ .tag = .expected_var_const, .token = label_token }); | ||
| 1268 | } | ||
| 1236 | } | 1269 | } |
| 1237 | } | 1270 | } |
| 1238 | return p.failMsg(.{ .tag = .expected_labelable, .token = after_colon }); | 1271 | return p.failMsg(.{ .tag = .expected_labelable, .token = after_colon }); |
| ... | @@ -1252,8 +1285,8 @@ fn parseLoopStatement(p: *Parse) !?Node.Index { | ... | @@ -1252,8 +1285,8 @@ fn parseLoopStatement(p: *Parse) !?Node.Index { |
| 1252 | } | 1285 | } |
| 1253 | 1286 | ||
| 1254 | /// ForStatement | 1287 | /// ForStatement |
| 1255 | /// <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else ) | 1288 | /// <- ForPrefix BlockExpr (KEYWORD_else Statement / !KEYWORD_else) |
| 1256 | /// / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement ) | 1289 | /// / ForPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Statement) |
| 1257 | fn parseForStatement(p: *Parse) !?Node.Index { | 1290 | fn parseForStatement(p: *Parse) !?Node.Index { |
| 1258 | const for_token = p.eatToken(.keyword_for) orelse return null; | 1291 | const for_token = p.eatToken(.keyword_for) orelse return null; |
| 1259 | 1292 | ||
| ... | @@ -1309,8 +1342,8 @@ fn parseForStatement(p: *Parse) !?Node.Index { | ... | @@ -1309,8 +1342,8 @@ fn parseForStatement(p: *Parse) !?Node.Index { |
| 1309 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? | 1342 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? |
| 1310 | /// | 1343 | /// |
| 1311 | /// WhileStatement | 1344 | /// WhileStatement |
| 1312 | /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? | 1345 | /// <- WhilePrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else) |
| 1313 | /// / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | 1346 | /// / WhilePrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement) |
| 1314 | fn parseWhileStatement(p: *Parse) !?Node.Index { | 1347 | fn parseWhileStatement(p: *Parse) !?Node.Index { |
| 1315 | const while_token = p.eatToken(.keyword_while) orelse return null; | 1348 | const while_token = p.eatToken(.keyword_while) orelse return null; |
| 1316 | _ = try p.expectToken(.l_paren); | 1349 | _ = try p.expectToken(.l_paren); |
| ... | @@ -1400,7 +1433,7 @@ fn parseWhileStatement(p: *Parse) !?Node.Index { | ... | @@ -1400,7 +1433,7 @@ fn parseWhileStatement(p: *Parse) !?Node.Index { |
| 1400 | 1433 | ||
| 1401 | /// BlockExprStatement | 1434 | /// BlockExprStatement |
| 1402 | /// <- BlockExpr | 1435 | /// <- BlockExpr |
| 1403 | /// / !BlockExpr AssignExpr SEMICOLON | 1436 | /// / !BlockExprPrefix AssignExpr SEMICOLON |
| 1404 | fn parseBlockExprStatement(p: *Parse) !?Node.Index { | 1437 | fn parseBlockExprStatement(p: *Parse) !?Node.Index { |
| 1405 | const block_expr = try p.parseBlockExpr(); | 1438 | const block_expr = try p.parseBlockExpr(); |
| 1406 | if (block_expr) |expr| return expr; | 1439 | if (block_expr) |expr| return expr; |
| ... | @@ -1434,7 +1467,7 @@ fn parseBlockExpr(p: *Parse) Error!?Node.Index { | ... | @@ -1434,7 +1467,7 @@ fn parseBlockExpr(p: *Parse) Error!?Node.Index { |
| 1434 | } | 1467 | } |
| 1435 | } | 1468 | } |
| 1436 | 1469 | ||
| 1437 | /// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)? | 1470 | /// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA) |
| 1438 | /// | 1471 | /// |
| 1439 | /// AssignOp | 1472 | /// AssignOp |
| 1440 | /// <- ASTERISKEQUAL | 1473 | /// <- ASTERISKEQUAL |
| ... | @@ -1460,7 +1493,7 @@ fn parseAssignExpr(p: *Parse) !?Node.Index { | ... | @@ -1460,7 +1493,7 @@ fn parseAssignExpr(p: *Parse) !?Node.Index { |
| 1460 | return try p.finishAssignExpr(expr); | 1493 | return try p.finishAssignExpr(expr); |
| 1461 | } | 1494 | } |
| 1462 | 1495 | ||
| 1463 | /// SingleAssignExpr <- Expr (AssignOp Expr)? | 1496 | /// SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp) |
| 1464 | fn parseSingleAssignExpr(p: *Parse) !?Node.Index { | 1497 | fn parseSingleAssignExpr(p: *Parse) !?Node.Index { |
| 1465 | const lhs = try p.parseExpr() orelse return null; | 1498 | const lhs = try p.parseExpr() orelse return null; |
| 1466 | const tag = assignOpNode(p.tokenTag(p.tok_i)) orelse return lhs; | 1499 | const tag = assignOpNode(p.tokenTag(p.tok_i)) orelse return lhs; |
| ... | @@ -1634,13 +1667,17 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index { | ... | @@ -1634,13 +1667,17 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index { |
| 1634 | if (tok_tag == .keyword_catch) { | 1667 | if (tok_tag == .keyword_catch) { |
| 1635 | _ = try p.parsePayload(); | 1668 | _ = try p.parsePayload(); |
| 1636 | } | 1669 | } |
| 1637 | const rhs = try p.parseExprPrecedence(info.prec + 1) orelse { | ||
| 1638 | try p.warn(.expected_expr); | ||
| 1639 | return node; | ||
| 1640 | }; | ||
| 1641 | 1670 | ||
| 1671 | // Check for whitespace error before parsing the rhs to facilitate fuzzing. | ||
| 1672 | // Consider the case where there is a mismatched whitespace error but the rhs | ||
| 1673 | // expression triggers stack overflow when parsing is attempted. In this case | ||
| 1674 | // we want to return with an error rather than crashing on stack overflow. | ||
| 1642 | { | 1675 | { |
| 1643 | const tok_len = tok_tag.lexeme().?.len; | 1676 | const tok_len = tok_tag.lexeme().?.len; |
| 1677 | if (p.tokenStart(oper_token) + tok_len >= p.source.len) { | ||
| 1678 | try p.warn(.expected_expr); | ||
| 1679 | return node; | ||
| 1680 | } | ||
| 1644 | const char_before = p.source[p.tokenStart(oper_token) - 1]; | 1681 | const char_before = p.source[p.tokenStart(oper_token) - 1]; |
| 1645 | const char_after = p.source[p.tokenStart(oper_token) + tok_len]; | 1682 | const char_after = p.source[p.tokenStart(oper_token) + tok_len]; |
| 1646 | if (tok_tag == .ampersand and char_after == '&') { | 1683 | if (tok_tag == .ampersand and char_after == '&') { |
| ... | @@ -1652,6 +1689,11 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index { | ... | @@ -1652,6 +1689,11 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index { |
| 1652 | } | 1689 | } |
| 1653 | } | 1690 | } |
| 1654 | 1691 | ||
| 1692 | const rhs = try p.parseExprPrecedence(info.prec + 1) orelse { | ||
| 1693 | try p.warn(.expected_expr); | ||
| 1694 | return node; | ||
| 1695 | }; | ||
| 1696 | |||
| 1655 | node = try p.addNode(.{ | 1697 | node = try p.addNode(.{ |
| 1656 | .tag = info.tag, | 1698 | .tag = info.tag, |
| 1657 | .main_token = oper_token, | 1699 | .main_token = oper_token, |
| ... | @@ -1666,7 +1708,7 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index { | ... | @@ -1666,7 +1708,7 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index { |
| 1666 | return node; | 1708 | return node; |
| 1667 | } | 1709 | } |
| 1668 | 1710 | ||
| 1669 | /// PrefixExpr <- PrefixOp* PrimaryExpr | 1711 | /// PrefixExpr <- PrefixOp* PrimaryExpr / !PrefixOp |
| 1670 | /// | 1712 | /// |
| 1671 | /// PrefixOp | 1713 | /// PrefixOp |
| 1672 | /// <- EXCLAMATIONMARK | 1714 | /// <- EXCLAMATIONMARK |
| ... | @@ -1696,25 +1738,28 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index { | ... | @@ -1696,25 +1738,28 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index { |
| 1696 | return try p.parsePrefixExpr() orelse return p.fail(.expected_prefix_expr); | 1738 | return try p.parsePrefixExpr() orelse return p.fail(.expected_prefix_expr); |
| 1697 | } | 1739 | } |
| 1698 | 1740 | ||
| 1699 | /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr | 1741 | /// TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr |
| 1700 | /// | 1742 | /// |
| 1701 | /// PrefixTypeOp | 1743 | /// PrefixTypeOp |
| 1702 | /// <- QUESTIONMARK | 1744 | /// <- QUESTIONMARK |
| 1703 | /// / KEYWORD_anyframe MINUSRARROW | 1745 | /// / KEYWORD_anyframe MINUSRARROW |
| 1704 | /// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? | 1746 | /// / (ManyPtrTypeStart / SliceTypeStart) PtrMods |
| 1705 | /// / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile? | 1747 | /// / SinglePtrTypeStart SinglePtrMods |
| 1706 | /// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* | ||
| 1707 | /// / ArrayTypeStart | 1748 | /// / ArrayTypeStart |
| 1708 | /// | 1749 | /// |
| 1750 | /// PrefixTypeOpPrefix | ||
| 1751 | /// <- QUESTIONMARK | ||
| 1752 | /// / KEYWORD_anyframe MINUSRARROW | ||
| 1753 | /// / LBRACKET | ||
| 1754 | /// / ASTERISK | ||
| 1755 | /// | ||
| 1709 | /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET | 1756 | /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET |
| 1710 | /// | 1757 | /// |
| 1711 | /// SinglePtrTypeStart <- ASTERISK | 1758 | /// SinglePtrTypeStart <- ASTERISK |
| 1712 | /// | 1759 | /// |
| 1713 | /// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET | 1760 | /// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET |
| 1714 | /// | 1761 | /// |
| 1715 | /// ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET | 1762 | /// ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET |
| 1716 | /// | ||
| 1717 | /// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN | ||
| 1718 | fn parseTypeExpr(p: *Parse) Error!?Node.Index { | 1763 | fn parseTypeExpr(p: *Parse) Error!?Node.Index { |
| 1719 | switch (p.tokenTag(p.tok_i)) { | 1764 | switch (p.tokenTag(p.tok_i)) { |
| 1720 | .question_mark => return try p.addNode(.{ | 1765 | .question_mark => return try p.addNode(.{ |
| ... | @@ -1735,7 +1780,7 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index { | ... | @@ -1735,7 +1780,7 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index { |
| 1735 | }, | 1780 | }, |
| 1736 | .asterisk => { | 1781 | .asterisk => { |
| 1737 | const asterisk = p.nextToken(); | 1782 | const asterisk = p.nextToken(); |
| 1738 | const mods = try p.parsePtrModifiers(); | 1783 | const mods = try p.parsePtrModifiers(.bit_align); |
| 1739 | const elem_type = try p.expectTypeExpr(); | 1784 | const elem_type = try p.expectTypeExpr(); |
| 1740 | if (mods.bit_range_start != .none) { | 1785 | if (mods.bit_range_start != .none) { |
| 1741 | return try p.addNode(.{ | 1786 | return try p.addNode(.{ |
| ... | @@ -1790,14 +1835,8 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index { | ... | @@ -1790,14 +1835,8 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index { |
| 1790 | sentinel = try p.expectExpr(); | 1835 | sentinel = try p.expectExpr(); |
| 1791 | } | 1836 | } |
| 1792 | _ = try p.expectToken(.r_bracket); | 1837 | _ = try p.expectToken(.r_bracket); |
| 1793 | const mods = try p.parsePtrModifiers(); | 1838 | const mods = try p.parsePtrModifiers(.byte_align); |
| 1794 | const elem_type = try p.expectTypeExpr(); | 1839 | const elem_type = try p.expectTypeExpr(); |
| 1795 | if (mods.bit_range_start.unwrap()) |bit_range_start| { | ||
| 1796 | try p.warnMsg(.{ | ||
| 1797 | .tag = .invalid_bit_range, | ||
| 1798 | .token = p.nodeMainToken(bit_range_start), | ||
| 1799 | }); | ||
| 1800 | } | ||
| 1801 | if (sentinel == null and mods.addrspace_node == .none) { | 1840 | if (sentinel == null and mods.addrspace_node == .none) { |
| 1802 | return try p.addNode(.{ | 1841 | return try p.addNode(.{ |
| 1803 | .tag = .ptr_type_aligned, | 1842 | .tag = .ptr_type_aligned, |
| ... | @@ -1840,14 +1879,8 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index { | ... | @@ -1840,14 +1879,8 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index { |
| 1840 | null; | 1879 | null; |
| 1841 | _ = try p.expectToken(.r_bracket); | 1880 | _ = try p.expectToken(.r_bracket); |
| 1842 | if (len_expr == null) { | 1881 | if (len_expr == null) { |
| 1843 | const mods = try p.parsePtrModifiers(); | 1882 | const mods = try p.parsePtrModifiers(.byte_align); |
| 1844 | const elem_type = try p.expectTypeExpr(); | 1883 | const elem_type = try p.expectTypeExpr(); |
| 1845 | if (mods.bit_range_start.unwrap()) |bit_range_start| { | ||
| 1846 | try p.warnMsg(.{ | ||
| 1847 | .tag = .invalid_bit_range, | ||
| 1848 | .token = p.nodeMainToken(bit_range_start), | ||
| 1849 | }); | ||
| 1850 | } | ||
| 1851 | if (sentinel == null and mods.addrspace_node == .none) { | 1884 | if (sentinel == null and mods.addrspace_node == .none) { |
| 1852 | return try p.addNode(.{ | 1885 | return try p.addNode(.{ |
| 1853 | .tag = .ptr_type_aligned, | 1886 | .tag = .ptr_type_aligned, |
| ... | @@ -1927,19 +1960,19 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index { | ... | @@ -1927,19 +1960,19 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index { |
| 1927 | /// PrimaryExpr | 1960 | /// PrimaryExpr |
| 1928 | /// <- AsmExpr | 1961 | /// <- AsmExpr |
| 1929 | /// / IfExpr | 1962 | /// / IfExpr |
| 1930 | /// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) | 1963 | /// / KEYWORD_break BreakLabel? Expr? |
| 1931 | /// / KEYWORD_comptime Expr !ExprSuffix | 1964 | /// / KEYWORD_comptime Expr |
| 1932 | /// / KEYWORD_nosuspend Expr !ExprSuffix | 1965 | /// / KEYWORD_nosuspend Expr |
| 1933 | /// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart) | 1966 | /// / KEYWORD_continue BreakLabel? Expr? |
| 1934 | /// / KEYWORD_resume Expr !ExprSuffix | 1967 | /// / KEYWORD_resume Expr |
| 1935 | /// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart) | 1968 | /// / KEYWORD_return Expr? |
| 1936 | /// / BlockLabel? LoopExpr | 1969 | /// / BlockLabel? LoopExpr |
| 1937 | /// / Block | 1970 | /// / Block |
| 1938 | /// / CurlySuffixExpr | 1971 | /// / CurlySuffixExpr |
| 1939 | fn parsePrimaryExpr(p: *Parse) !?Node.Index { | 1972 | fn parsePrimaryExpr(p: *Parse) !?Node.Index { |
| 1940 | switch (p.tokenTag(p.tok_i)) { | 1973 | switch (p.tokenTag(p.tok_i)) { |
| 1941 | .keyword_asm => return try p.expectAsmExpr(), | 1974 | .keyword_asm => return try p.expectAsmExpr(), |
| 1942 | .keyword_if => return try p.parseIfExpr(), | 1975 | .keyword_if => return try p.expectIf(expectExpr), |
| 1943 | .keyword_break => { | 1976 | .keyword_break => { |
| 1944 | return try p.addNode(.{ | 1977 | return try p.addNode(.{ |
| 1945 | .tag = .@"break", | 1978 | .tag = .@"break", |
| ... | @@ -1994,18 +2027,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index { | ... | @@ -1994,18 +2027,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index { |
| 1994 | .keyword_inline => { | 2027 | .keyword_inline => { |
| 1995 | p.tok_i += 3; | 2028 | p.tok_i += 3; |
| 1996 | switch (p.tokenTag(p.tok_i)) { | 2029 | switch (p.tokenTag(p.tok_i)) { |
| 1997 | .keyword_for => return try p.parseFor(expectExpr), | 2030 | .keyword_for => return try p.expectFor(expectExpr), |
| 1998 | .keyword_while => return try p.parseWhileExpr(), | 2031 | .keyword_while => return try p.expectWhileExpr(), |
| 1999 | else => return p.fail(.expected_inlinable), | 2032 | else => return p.fail(.expected_inlinable), |
| 2000 | } | 2033 | } |
| 2001 | }, | 2034 | }, |
| 2002 | .keyword_for => { | 2035 | .keyword_for => { |
| 2003 | p.tok_i += 2; | 2036 | p.tok_i += 2; |
| 2004 | return try p.parseFor(expectExpr); | 2037 | return try p.expectFor(expectExpr); |
| 2005 | }, | 2038 | }, |
| 2006 | .keyword_while => { | 2039 | .keyword_while => { |
| 2007 | p.tok_i += 2; | 2040 | p.tok_i += 2; |
| 2008 | return try p.parseWhileExpr(); | 2041 | return try p.expectWhileExpr(); |
| 2009 | }, | 2042 | }, |
| 2010 | else => return try p.parseCurlySuffixExpr(), | 2043 | else => return try p.parseCurlySuffixExpr(), |
| 2011 | } | 2044 | } |
| ... | @@ -2016,23 +2049,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index { | ... | @@ -2016,23 +2049,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index { |
| 2016 | .keyword_inline => { | 2049 | .keyword_inline => { |
| 2017 | p.tok_i += 1; | 2050 | p.tok_i += 1; |
| 2018 | switch (p.tokenTag(p.tok_i)) { | 2051 | switch (p.tokenTag(p.tok_i)) { |
| 2019 | .keyword_for => return try p.parseFor(expectExpr), | 2052 | .keyword_for => return try p.expectFor(expectExpr), |
| 2020 | .keyword_while => return try p.parseWhileExpr(), | 2053 | .keyword_while => return try p.expectWhileExpr(), |
| 2021 | else => return p.fail(.expected_inlinable), | 2054 | else => return p.fail(.expected_inlinable), |
| 2022 | } | 2055 | } |
| 2023 | }, | 2056 | }, |
| 2024 | .keyword_for => return try p.parseFor(expectExpr), | 2057 | .keyword_for => return try p.expectFor(expectExpr), |
| 2025 | .keyword_while => return try p.parseWhileExpr(), | 2058 | .keyword_while => return try p.expectWhileExpr(), |
| 2026 | .l_brace => return try p.parseBlock(), | 2059 | .l_brace => return try p.parseBlock(), |
| 2027 | else => return try p.parseCurlySuffixExpr(), | 2060 | else => return try p.parseCurlySuffixExpr(), |
| 2028 | } | 2061 | } |
| 2029 | } | 2062 | } |
| 2030 | 2063 | ||
| 2031 | /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix | ||
| 2032 | fn parseIfExpr(p: *Parse) !?Node.Index { | ||
| 2033 | return try p.parseIf(expectExpr); | ||
| 2034 | } | ||
| 2035 | |||
| 2036 | /// Block <- LBRACE BlockStatement* RBRACE | 2064 | /// Block <- LBRACE BlockStatement* RBRACE |
| 2037 | fn parseBlock(p: *Parse) !?Node.Index { | 2065 | fn parseBlock(p: *Parse) !?Node.Index { |
| 2038 | const lbrace = p.eatToken(.l_brace) orelse return null; | 2066 | const lbrace = p.eatToken(.l_brace) orelse return null; |
| ... | @@ -2106,16 +2134,9 @@ fn forPrefix(p: *Parse) Error!usize { | ... | @@ -2106,16 +2134,9 @@ fn forPrefix(p: *Parse) Error!usize { |
| 2106 | return inputs; | 2134 | return inputs; |
| 2107 | }; | 2135 | }; |
| 2108 | 2136 | ||
| 2109 | var warned_excess = false; | ||
| 2110 | var captures: u32 = 0; | ||
| 2111 | while (true) { | 2137 | while (true) { |
| 2112 | _ = p.eatToken(.asterisk); | 2138 | _ = p.eatToken(.asterisk); |
| 2113 | const identifier = try p.expectToken(.identifier); | 2139 | _ = try p.expectToken(.identifier); |
| 2114 | captures += 1; | ||
| 2115 | if (captures > inputs and !warned_excess) { | ||
| 2116 | try p.warnMsg(.{ .tag = .extra_for_capture, .token = identifier }); | ||
| 2117 | warned_excess = true; | ||
| 2118 | } | ||
| 2119 | switch (p.tokenTag(p.tok_i)) { | 2140 | switch (p.tokenTag(p.tok_i)) { |
| 2120 | .comma => p.tok_i += 1, | 2141 | .comma => p.tok_i += 1, |
| 2121 | .pipe => { | 2142 | .pipe => { |
| ... | @@ -2128,19 +2149,14 @@ fn forPrefix(p: *Parse) Error!usize { | ... | @@ -2128,19 +2149,14 @@ fn forPrefix(p: *Parse) Error!usize { |
| 2128 | if (p.eatToken(.pipe)) |_| break; | 2149 | if (p.eatToken(.pipe)) |_| break; |
| 2129 | } | 2150 | } |
| 2130 | 2151 | ||
| 2131 | if (captures < inputs) { | ||
| 2132 | const index = p.scratch.items.len - captures; | ||
| 2133 | const input = p.nodeMainToken(p.scratch.items[index]); | ||
| 2134 | try p.warnMsg(.{ .tag = .for_input_not_captured, .token = input }); | ||
| 2135 | } | ||
| 2136 | return inputs; | 2152 | return inputs; |
| 2137 | } | 2153 | } |
| 2138 | 2154 | ||
| 2139 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? | 2155 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? |
| 2140 | /// | 2156 | /// |
| 2141 | /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi | 2157 | /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi |
| 2142 | fn parseWhileExpr(p: *Parse) !?Node.Index { | 2158 | fn expectWhileExpr(p: *Parse) !Node.Index { |
| 2143 | const while_token = p.eatToken(.keyword_while) orelse return null; | 2159 | const while_token = p.assertToken(.keyword_while); |
| 2144 | _ = try p.expectToken(.l_paren); | 2160 | _ = try p.expectToken(.l_paren); |
| 2145 | const condition = try p.expectExpr(); | 2161 | const condition = try p.expectExpr(); |
| 2146 | _ = try p.expectToken(.r_paren); | 2162 | _ = try p.expectToken(.r_paren); |
| ... | @@ -2188,7 +2204,7 @@ fn parseWhileExpr(p: *Parse) !?Node.Index { | ... | @@ -2188,7 +2204,7 @@ fn parseWhileExpr(p: *Parse) !?Node.Index { |
| 2188 | }); | 2204 | }); |
| 2189 | } | 2205 | } |
| 2190 | 2206 | ||
| 2191 | /// CurlySuffixExpr <- TypeExpr InitList? | 2207 | /// CurlySuffixExpr <- TypeExpr (InitList / !LBRACE) |
| 2192 | /// | 2208 | /// |
| 2193 | /// InitList | 2209 | /// InitList |
| 2194 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | 2210 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE |
| ... | @@ -2290,7 +2306,7 @@ fn parseCurlySuffixExpr(p: *Parse) !?Node.Index { | ... | @@ -2290,7 +2306,7 @@ fn parseCurlySuffixExpr(p: *Parse) !?Node.Index { |
| 2290 | } | 2306 | } |
| 2291 | } | 2307 | } |
| 2292 | 2308 | ||
| 2293 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? | 2309 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK) |
| 2294 | fn parseErrorUnionExpr(p: *Parse) !?Node.Index { | 2310 | fn parseErrorUnionExpr(p: *Parse) !?Node.Index { |
| 2295 | const suffix_expr = try p.parseSuffixExpr() orelse return null; | 2311 | const suffix_expr = try p.parseSuffixExpr() orelse return null; |
| 2296 | const bang = p.eatToken(.bang) orelse return suffix_expr; | 2312 | const bang = p.eatToken(.bang) orelse return suffix_expr; |
| ... | @@ -2304,59 +2320,13 @@ fn parseErrorUnionExpr(p: *Parse) !?Node.Index { | ... | @@ -2304,59 +2320,13 @@ fn parseErrorUnionExpr(p: *Parse) !?Node.Index { |
| 2304 | }); | 2320 | }); |
| 2305 | } | 2321 | } |
| 2306 | 2322 | ||
| 2307 | /// SuffixExpr | 2323 | /// SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix |
| 2308 | /// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* | ||
| 2309 | /// | ||
| 2310 | /// FnCallArguments <- LPAREN ExprList RPAREN | ||
| 2311 | /// | ||
| 2312 | /// ExprList <- (Expr COMMA)* Expr? | ||
| 2313 | fn parseSuffixExpr(p: *Parse) !?Node.Index { | 2324 | fn parseSuffixExpr(p: *Parse) !?Node.Index { |
| 2314 | var res = try p.parsePrimaryTypeExpr() orelse return null; | 2325 | var res = try p.parsePrimaryTypeExpr() orelse return null; |
| 2315 | while (true) { | 2326 | while (try p.parseSuffixOp(res)) |suffix_op| { |
| 2316 | const opt_suffix_op = try p.parseSuffixOp(res); | 2327 | res = suffix_op; |
| 2317 | if (opt_suffix_op) |suffix_op| { | ||
| 2318 | res = suffix_op; | ||
| 2319 | continue; | ||
| 2320 | } | ||
| 2321 | const lparen = p.eatToken(.l_paren) orelse return res; | ||
| 2322 | const scratch_top = p.scratch.items.len; | ||
| 2323 | defer p.scratch.shrinkRetainingCapacity(scratch_top); | ||
| 2324 | while (true) { | ||
| 2325 | if (p.eatToken(.r_paren)) |_| break; | ||
| 2326 | const param = try p.expectExpr(); | ||
| 2327 | try p.scratch.append(p.gpa, param); | ||
| 2328 | switch (p.tokenTag(p.tok_i)) { | ||
| 2329 | .comma => p.tok_i += 1, | ||
| 2330 | .r_paren => { | ||
| 2331 | p.tok_i += 1; | ||
| 2332 | break; | ||
| 2333 | }, | ||
| 2334 | .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), | ||
| 2335 | // Likely just a missing comma; give error but continue parsing. | ||
| 2336 | else => try p.warn(.expected_comma_after_arg), | ||
| 2337 | } | ||
| 2338 | } | ||
| 2339 | const comma = (p.tokenTag(p.tok_i - 2)) == .comma; | ||
| 2340 | const params = p.scratch.items[scratch_top..]; | ||
| 2341 | res = switch (params.len) { | ||
| 2342 | 0, 1 => try p.addNode(.{ | ||
| 2343 | .tag = if (comma) .call_one_comma else .call_one, | ||
| 2344 | .main_token = lparen, | ||
| 2345 | .data = .{ .node_and_opt_node = .{ | ||
| 2346 | res, | ||
| 2347 | if (params.len >= 1) .fromOptional(params[0]) else .none, | ||
| 2348 | } }, | ||
| 2349 | }), | ||
| 2350 | else => try p.addNode(.{ | ||
| 2351 | .tag = if (comma) .call_comma else .call, | ||
| 2352 | .main_token = lparen, | ||
| 2353 | .data = .{ .node_and_extra = .{ | ||
| 2354 | res, | ||
| 2355 | try p.addExtra(try p.listToSpan(params)), | ||
| 2356 | } }, | ||
| 2357 | }), | ||
| 2358 | }; | ||
| 2359 | } | 2328 | } |
| 2329 | return res; | ||
| 2360 | } | 2330 | } |
| 2361 | 2331 | ||
| 2362 | /// PrimaryTypeExpr | 2332 | /// PrimaryTypeExpr |
| ... | @@ -2366,17 +2336,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index { | ... | @@ -2366,17 +2336,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index { |
| 2366 | /// / DOT IDENTIFIER | 2336 | /// / DOT IDENTIFIER |
| 2367 | /// / DOT InitList | 2337 | /// / DOT InitList |
| 2368 | /// / ErrorSetDecl | 2338 | /// / ErrorSetDecl |
| 2369 | /// / FLOAT | ||
| 2370 | /// / FnProto | 2339 | /// / FnProto |
| 2371 | /// / GroupedExpr | 2340 | /// / GroupedExpr |
| 2372 | /// / LabeledTypeExpr | 2341 | /// / LabeledTypeExpr |
| 2373 | /// / IDENTIFIER !(COLON LabelableExpr) | 2342 | /// / IDENTIFIER |
| 2374 | /// / IfTypeExpr | 2343 | /// / IfTypeExpr |
| 2375 | /// / INTEGER | 2344 | /// / KEYWORD_comptime TypeExpr |
| 2376 | /// / KEYWORD_comptime TypeExpr !ExprSuffix | ||
| 2377 | /// / KEYWORD_error DOT IDENTIFIER | 2345 | /// / KEYWORD_error DOT IDENTIFIER |
| 2378 | /// / KEYWORD_anyframe | 2346 | /// / KEYWORD_anyframe |
| 2379 | /// / KEYWORD_unreachable | 2347 | /// / KEYWORD_unreachable |
| 2348 | /// / NUMBERLITERAL | ||
| 2380 | /// / STRINGLITERAL | 2349 | /// / STRINGLITERAL |
| 2381 | /// | 2350 | /// |
| 2382 | /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto | 2351 | /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto |
| ... | @@ -2431,23 +2400,23 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { | ... | @@ -2431,23 +2400,23 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2431 | }); | 2400 | }); |
| 2432 | }, | 2401 | }, |
| 2433 | 2402 | ||
| 2434 | .builtin => return try p.parseBuiltinCall(), | 2403 | .builtin => return try p.expectBuiltinCall(), |
| 2435 | .keyword_fn => return try p.parseFnProto(), | 2404 | .keyword_fn => return (try p.parseFnProto()).?, |
| 2436 | .keyword_if => return try p.parseIf(expectTypeExpr), | 2405 | .keyword_if => return try p.expectIf(expectTypeExpr), |
| 2437 | .keyword_switch => return try p.expectSwitchExpr(false), | 2406 | .keyword_switch => return try p.expectSwitchExpr(false), |
| 2438 | 2407 | ||
| 2439 | .keyword_extern, | 2408 | .keyword_extern, |
| 2440 | .keyword_packed, | 2409 | .keyword_packed, |
| 2441 | => { | 2410 | => { |
| 2442 | p.tok_i += 1; | 2411 | p.tok_i += 1; |
| 2443 | return try p.parseContainerDeclAuto(); | 2412 | return try p.expectContainerDeclAuto(); |
| 2444 | }, | 2413 | }, |
| 2445 | 2414 | ||
| 2446 | .keyword_struct, | 2415 | .keyword_struct, |
| 2447 | .keyword_opaque, | 2416 | .keyword_opaque, |
| 2448 | .keyword_enum, | 2417 | .keyword_enum, |
| 2449 | .keyword_union, | 2418 | .keyword_union, |
| 2450 | => return try p.parseContainerDeclAuto(), | 2419 | => return try p.expectContainerDeclAuto(), |
| 2451 | 2420 | ||
| 2452 | .keyword_comptime => return try p.addNode(.{ | 2421 | .keyword_comptime => return try p.addNode(.{ |
| 2453 | .tag = .@"comptime", | 2422 | .tag = .@"comptime", |
| ... | @@ -2473,18 +2442,18 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { | ... | @@ -2473,18 +2442,18 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2473 | .keyword_inline => { | 2442 | .keyword_inline => { |
| 2474 | p.tok_i += 3; | 2443 | p.tok_i += 3; |
| 2475 | switch (p.tokenTag(p.tok_i)) { | 2444 | switch (p.tokenTag(p.tok_i)) { |
| 2476 | .keyword_for => return try p.parseFor(expectTypeExpr), | 2445 | .keyword_for => return try p.expectFor(expectTypeExpr), |
| 2477 | .keyword_while => return try p.parseWhileTypeExpr(), | 2446 | .keyword_while => return try p.expectWhileTypeExpr(), |
| 2478 | else => return p.fail(.expected_inlinable), | 2447 | else => return p.fail(.expected_inlinable), |
| 2479 | } | 2448 | } |
| 2480 | }, | 2449 | }, |
| 2481 | .keyword_for => { | 2450 | .keyword_for => { |
| 2482 | p.tok_i += 2; | 2451 | p.tok_i += 2; |
| 2483 | return try p.parseFor(expectTypeExpr); | 2452 | return try p.expectFor(expectTypeExpr); |
| 2484 | }, | 2453 | }, |
| 2485 | .keyword_while => { | 2454 | .keyword_while => { |
| 2486 | p.tok_i += 2; | 2455 | p.tok_i += 2; |
| 2487 | return try p.parseWhileTypeExpr(); | 2456 | return try p.expectWhileTypeExpr(); |
| 2488 | }, | 2457 | }, |
| 2489 | .keyword_switch => { | 2458 | .keyword_switch => { |
| 2490 | p.tok_i += 2; | 2459 | p.tok_i += 2; |
| ... | @@ -2492,7 +2461,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { | ... | @@ -2492,7 +2461,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2492 | }, | 2461 | }, |
| 2493 | .l_brace => { | 2462 | .l_brace => { |
| 2494 | p.tok_i += 2; | 2463 | p.tok_i += 2; |
| 2495 | return try p.parseBlock(); | 2464 | return (try p.parseBlock()).?; |
| 2496 | }, | 2465 | }, |
| 2497 | else => return try p.addNode(.{ | 2466 | else => return try p.addNode(.{ |
| 2498 | .tag = .identifier, | 2467 | .tag = .identifier, |
| ... | @@ -2509,13 +2478,13 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { | ... | @@ -2509,13 +2478,13 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2509 | .keyword_inline => { | 2478 | .keyword_inline => { |
| 2510 | p.tok_i += 1; | 2479 | p.tok_i += 1; |
| 2511 | switch (p.tokenTag(p.tok_i)) { | 2480 | switch (p.tokenTag(p.tok_i)) { |
| 2512 | .keyword_for => return try p.parseFor(expectTypeExpr), | 2481 | .keyword_for => return try p.expectFor(expectTypeExpr), |
| 2513 | .keyword_while => return try p.parseWhileTypeExpr(), | 2482 | .keyword_while => return try p.expectWhileTypeExpr(), |
| 2514 | else => return p.fail(.expected_inlinable), | 2483 | else => return p.fail(.expected_inlinable), |
| 2515 | } | 2484 | } |
| 2516 | }, | 2485 | }, |
| 2517 | .keyword_for => return try p.parseFor(expectTypeExpr), | 2486 | .keyword_for => return try p.expectFor(expectTypeExpr), |
| 2518 | .keyword_while => return try p.parseWhileTypeExpr(), | 2487 | .keyword_while => return try p.expectWhileTypeExpr(), |
| 2519 | .period => switch (p.tokenTag(p.tok_i + 1)) { | 2488 | .period => switch (p.tokenTag(p.tok_i + 1)) { |
| 2520 | .identifier => { | 2489 | .identifier => { |
| 2521 | p.tok_i += 1; | 2490 | p.tok_i += 1; |
| ... | @@ -2643,10 +2612,8 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { | ... | @@ -2643,10 +2612,8 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index { |
| 2643 | }, | 2612 | }, |
| 2644 | else => { | 2613 | else => { |
| 2645 | const main_token = p.nextToken(); | 2614 | const main_token = p.nextToken(); |
| 2646 | const period = p.eatToken(.period); | 2615 | _ = try p.expectToken(.period); |
| 2647 | if (period == null) return p.failExpected(.period); | 2616 | _ = try p.expectToken(.identifier); |
| 2648 | const identifier = p.eatToken(.identifier); | ||
| 2649 | if (identifier == null) return p.failExpected(.identifier); | ||
| 2650 | return try p.addNode(.{ | 2617 | return try p.addNode(.{ |
| 2651 | .tag = .error_value, | 2618 | .tag = .error_value, |
| 2652 | .main_token = main_token, | 2619 | .main_token = main_token, |
| ... | @@ -2672,9 +2639,9 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index { | ... | @@ -2672,9 +2639,9 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index { |
| 2672 | 2639 | ||
| 2673 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? | 2640 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? |
| 2674 | /// | 2641 | /// |
| 2675 | /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix | 2642 | /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) |
| 2676 | fn parseWhileTypeExpr(p: *Parse) !?Node.Index { | 2643 | fn expectWhileTypeExpr(p: *Parse) !Node.Index { |
| 2677 | const while_token = p.eatToken(.keyword_while) orelse return null; | 2644 | const while_token = p.assertToken(.keyword_while); |
| 2678 | _ = try p.expectToken(.l_paren); | 2645 | _ = try p.expectToken(.l_paren); |
| 2679 | const condition = try p.expectExpr(); | 2646 | const condition = try p.expectExpr(); |
| 2680 | _ = try p.expectToken(.r_paren); | 2647 | _ = try p.expectToken(.r_paren); |
| ... | @@ -3076,16 +3043,29 @@ const PtrModifiers = struct { | ... | @@ -3076,16 +3043,29 @@ const PtrModifiers = struct { |
| 3076 | bit_range_end: Node.OptionalIndex, | 3043 | bit_range_end: Node.OptionalIndex, |
| 3077 | }; | 3044 | }; |
| 3078 | 3045 | ||
| 3079 | fn parsePtrModifiers(p: *Parse) !PtrModifiers { | 3046 | /// PtrMods |
| 3047 | /// <- PtrMod* ByteAlign? PtrMod* AddrSpace? PtrMod* | ||
| 3048 | /// / PtrMod* AddrSpace? PtrMod* ByteAlign? PtrMod* | ||
| 3049 | /// | ||
| 3050 | /// SinglePtrMods | ||
| 3051 | /// <- PtrMod* BitAlign? PtrMod* AddrSpace? PtrMod* | ||
| 3052 | /// / PtrMod* AddrSpace? PtrMod* BitAlign? PtrMod* | ||
| 3053 | /// | ||
| 3054 | /// PtrMod | ||
| 3055 | /// <- KEYWORD_allowzero | ||
| 3056 | /// / KEYWORD_const | ||
| 3057 | /// / KEYWORD_volatile | ||
| 3058 | /// | ||
| 3059 | /// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN | ||
| 3060 | /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN | ||
| 3061 | /// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN | ||
| 3062 | fn parsePtrModifiers(p: *Parse, align_type: enum { bit_align, byte_align }) !PtrModifiers { | ||
| 3080 | var result: PtrModifiers = .{ | 3063 | var result: PtrModifiers = .{ |
| 3081 | .align_node = .none, | 3064 | .align_node = .none, |
| 3082 | .addrspace_node = .none, | 3065 | .addrspace_node = .none, |
| 3083 | .bit_range_start = .none, | 3066 | .bit_range_start = .none, |
| 3084 | .bit_range_end = .none, | 3067 | .bit_range_end = .none, |
| 3085 | }; | 3068 | }; |
| 3086 | var saw_const = false; | ||
| 3087 | var saw_volatile = false; | ||
| 3088 | var saw_allowzero = false; | ||
| 3089 | while (true) { | 3069 | while (true) { |
| 3090 | switch (p.tokenTag(p.tok_i)) { | 3070 | switch (p.tokenTag(p.tok_i)) { |
| 3091 | .keyword_align => { | 3071 | .keyword_align => { |
| ... | @@ -3096,7 +3076,10 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers { | ... | @@ -3096,7 +3076,10 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers { |
| 3096 | _ = try p.expectToken(.l_paren); | 3076 | _ = try p.expectToken(.l_paren); |
| 3097 | result.align_node = (try p.expectExpr()).toOptional(); | 3077 | result.align_node = (try p.expectExpr()).toOptional(); |
| 3098 | 3078 | ||
| 3099 | if (p.eatToken(.colon)) |_| { | 3079 | if (p.eatToken(.colon)) |colon| { |
| 3080 | if (align_type == .byte_align) { | ||
| 3081 | try p.warnMsg(.{ .tag = .invalid_bit_range, .token = colon }); | ||
| 3082 | } | ||
| 3100 | result.bit_range_start = (try p.expectExpr()).toOptional(); | 3083 | result.bit_range_start = (try p.expectExpr()).toOptional(); |
| 3101 | _ = try p.expectToken(.colon); | 3084 | _ = try p.expectToken(.colon); |
| 3102 | result.bit_range_end = (try p.expectExpr()).toOptional(); | 3085 | result.bit_range_end = (try p.expectExpr()).toOptional(); |
| ... | @@ -3104,33 +3087,16 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers { | ... | @@ -3104,33 +3087,16 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers { |
| 3104 | 3087 | ||
| 3105 | _ = try p.expectToken(.r_paren); | 3088 | _ = try p.expectToken(.r_paren); |
| 3106 | }, | 3089 | }, |
| 3107 | .keyword_const => { | ||
| 3108 | if (saw_const) { | ||
| 3109 | try p.warn(.extra_const_qualifier); | ||
| 3110 | } | ||
| 3111 | p.tok_i += 1; | ||
| 3112 | saw_const = true; | ||
| 3113 | }, | ||
| 3114 | .keyword_volatile => { | ||
| 3115 | if (saw_volatile) { | ||
| 3116 | try p.warn(.extra_volatile_qualifier); | ||
| 3117 | } | ||
| 3118 | p.tok_i += 1; | ||
| 3119 | saw_volatile = true; | ||
| 3120 | }, | ||
| 3121 | .keyword_allowzero => { | ||
| 3122 | if (saw_allowzero) { | ||
| 3123 | try p.warn(.extra_allowzero_qualifier); | ||
| 3124 | } | ||
| 3125 | p.tok_i += 1; | ||
| 3126 | saw_allowzero = true; | ||
| 3127 | }, | ||
| 3128 | .keyword_addrspace => { | 3090 | .keyword_addrspace => { |
| 3129 | if (result.addrspace_node != .none) { | 3091 | if (result.addrspace_node != .none) { |
| 3130 | try p.warn(.extra_addrspace_qualifier); | 3092 | try p.warn(.extra_addrspace_qualifier); |
| 3131 | } | 3093 | } |
| 3132 | result.addrspace_node = .fromOptional(try p.parseAddrSpace()); | 3094 | result.addrspace_node = .fromOptional(try p.parseAddrSpace()); |
| 3133 | }, | 3095 | }, |
| 3096 | .keyword_allowzero, | ||
| 3097 | .keyword_const, | ||
| 3098 | .keyword_volatile, | ||
| 3099 | => p.tok_i += 1, | ||
| 3134 | else => return result, | 3100 | else => return result, |
| 3135 | } | 3101 | } |
| 3136 | } | 3102 | } |
| ... | @@ -3140,7 +3106,12 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers { | ... | @@ -3140,7 +3106,12 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers { |
| 3140 | /// <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET | 3106 | /// <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET |
| 3141 | /// / DOT IDENTIFIER | 3107 | /// / DOT IDENTIFIER |
| 3142 | /// / DOTASTERISK | 3108 | /// / DOTASTERISK |
| 3143 | /// / DOTQUESTIONMARK | 3109 | /// / DOT QUESTIONMARK |
| 3110 | /// / FnCallArguments | ||
| 3111 | /// | ||
| 3112 | /// FnCallArguments <- LPAREN ExprList RPAREN | ||
| 3113 | /// | ||
| 3114 | /// ExprList <- (Expr COMMA)* Expr? | ||
| 3144 | fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { | 3115 | fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { |
| 3145 | switch (p.tokenTag(p.tok_i)) { | 3116 | switch (p.tokenTag(p.tok_i)) { |
| 3146 | .l_bracket => { | 3117 | .l_bracket => { |
| ... | @@ -3230,6 +3201,46 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { | ... | @@ -3230,6 +3201,46 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { |
| 3230 | return null; | 3201 | return null; |
| 3231 | }, | 3202 | }, |
| 3232 | }, | 3203 | }, |
| 3204 | .l_paren => { | ||
| 3205 | const lparen = p.nextToken(); | ||
| 3206 | const scratch_top = p.scratch.items.len; | ||
| 3207 | defer p.scratch.shrinkRetainingCapacity(scratch_top); | ||
| 3208 | while (true) { | ||
| 3209 | if (p.eatToken(.r_paren)) |_| break; | ||
| 3210 | const param = try p.expectExpr(); | ||
| 3211 | try p.scratch.append(p.gpa, param); | ||
| 3212 | switch (p.tokenTag(p.tok_i)) { | ||
| 3213 | .comma => p.tok_i += 1, | ||
| 3214 | .r_paren => { | ||
| 3215 | p.tok_i += 1; | ||
| 3216 | break; | ||
| 3217 | }, | ||
| 3218 | .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), | ||
| 3219 | // Likely just a missing comma; give error but continue parsing. | ||
| 3220 | else => try p.warn(.expected_comma_after_arg), | ||
| 3221 | } | ||
| 3222 | } | ||
| 3223 | const comma = (p.tokenTag(p.tok_i - 2)) == .comma; | ||
| 3224 | const params = p.scratch.items[scratch_top..]; | ||
| 3225 | switch (params.len) { | ||
| 3226 | 0, 1 => return try p.addNode(.{ | ||
| 3227 | .tag = if (comma) .call_one_comma else .call_one, | ||
| 3228 | .main_token = lparen, | ||
| 3229 | .data = .{ .node_and_opt_node = .{ | ||
| 3230 | lhs, | ||
| 3231 | if (params.len >= 1) .fromOptional(params[0]) else .none, | ||
| 3232 | } }, | ||
| 3233 | }), | ||
| 3234 | else => return try p.addNode(.{ | ||
| 3235 | .tag = if (comma) .call_comma else .call, | ||
| 3236 | .main_token = lparen, | ||
| 3237 | .data = .{ .node_and_extra = .{ | ||
| 3238 | lhs, | ||
| 3239 | try p.addExtra(try p.listToSpan(params)), | ||
| 3240 | } }, | ||
| 3241 | }), | ||
| 3242 | } | ||
| 3243 | }, | ||
| 3233 | else => return null, | 3244 | else => return null, |
| 3234 | } | 3245 | } |
| 3235 | } | 3246 | } |
| ... | @@ -3243,7 +3254,7 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { | ... | @@ -3243,7 +3254,7 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index { |
| 3243 | /// / KEYWORD_opaque | 3254 | /// / KEYWORD_opaque |
| 3244 | /// / KEYWORD_enum (LPAREN Expr RPAREN)? | 3255 | /// / KEYWORD_enum (LPAREN Expr RPAREN)? |
| 3245 | /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? | 3256 | /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? |
| 3246 | fn parseContainerDeclAuto(p: *Parse) !?Node.Index { | 3257 | fn expectContainerDeclAuto(p: *Parse) !Node.Index { |
| 3247 | const main_token = p.nextToken(); | 3258 | const main_token = p.nextToken(); |
| 3248 | const arg_expr = switch (p.tokenTag(main_token)) { | 3259 | const arg_expr = switch (p.tokenTag(main_token)) { |
| 3249 | .keyword_opaque => null, | 3260 | .keyword_opaque => null, |
| ... | @@ -3366,6 +3377,7 @@ fn parseContainerDeclAuto(p: *Parse) !?Node.Index { | ... | @@ -3366,6 +3377,7 @@ fn parseContainerDeclAuto(p: *Parse) !?Node.Index { |
| 3366 | /// Give a helpful error message for those transitioning from | 3377 | /// Give a helpful error message for those transitioning from |
| 3367 | /// C's 'struct Foo {};' to Zig's 'const Foo = struct {};'. | 3378 | /// C's 'struct Foo {};' to Zig's 'const Foo = struct {};'. |
| 3368 | fn parseCStyleContainer(p: *Parse) Error!bool { | 3379 | fn parseCStyleContainer(p: *Parse) Error!bool { |
| 3380 | if (!p.recover) return false; | ||
| 3369 | const main_token = p.tok_i; | 3381 | const main_token = p.tok_i; |
| 3370 | switch (p.tokenTag(p.tok_i)) { | 3382 | switch (p.tokenTag(p.tok_i)) { |
| 3371 | .keyword_enum, .keyword_union, .keyword_struct => {}, | 3383 | .keyword_enum, .keyword_union, .keyword_struct => {}, |
| ... | @@ -3431,10 +3443,13 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { | ... | @@ -3431,10 +3443,13 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { |
| 3431 | _ = try p.expectToken(.l_paren); | 3443 | _ = try p.expectToken(.l_paren); |
| 3432 | const scratch_top = p.scratch.items.len; | 3444 | const scratch_top = p.scratch.items.len; |
| 3433 | defer p.scratch.shrinkRetainingCapacity(scratch_top); | 3445 | defer p.scratch.shrinkRetainingCapacity(scratch_top); |
| 3434 | var varargs: union(enum) { none, seen, nonfinal: TokenIndex } = .none; | 3446 | var varargs: enum { none, seen, err } = .none; |
| 3435 | while (true) { | 3447 | while (true) { |
| 3436 | if (p.eatToken(.r_paren)) |_| break; | 3448 | if (p.eatToken(.r_paren)) |_| break; |
| 3437 | if (varargs == .seen) varargs = .{ .nonfinal = p.tok_i }; | 3449 | if (varargs == .seen) { |
| 3450 | try p.warnMsg(.{ .tag = .varargs_nonfinal, .token = p.tok_i }); | ||
| 3451 | varargs = .err; | ||
| 3452 | } | ||
| 3438 | const opt_param = try p.expectParamDecl(); | 3453 | const opt_param = try p.expectParamDecl(); |
| 3439 | if (opt_param) |param| { | 3454 | if (opt_param) |param| { |
| 3440 | try p.scratch.append(p.gpa, param); | 3455 | try p.scratch.append(p.gpa, param); |
| ... | @@ -3452,9 +3467,6 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { | ... | @@ -3452,9 +3467,6 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { |
| 3452 | else => try p.warn(.expected_comma_after_param), | 3467 | else => try p.warn(.expected_comma_after_param), |
| 3453 | } | 3468 | } |
| 3454 | } | 3469 | } |
| 3455 | if (varargs == .nonfinal) { | ||
| 3456 | try p.warnMsg(.{ .tag = .varargs_nonfinal, .token = varargs.nonfinal }); | ||
| 3457 | } | ||
| 3458 | const params = p.scratch.items[scratch_top..]; | 3470 | const params = p.scratch.items[scratch_top..]; |
| 3459 | return switch (params.len) { | 3471 | return switch (params.len) { |
| 3460 | 0 => .{ .zero_or_one = .none }, | 3472 | 0 => .{ .zero_or_one = .none }, |
| ... | @@ -3466,7 +3478,7 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { | ... | @@ -3466,7 +3478,7 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { |
| 3466 | /// FnCallArguments <- LPAREN ExprList RPAREN | 3478 | /// FnCallArguments <- LPAREN ExprList RPAREN |
| 3467 | /// | 3479 | /// |
| 3468 | /// ExprList <- (Expr COMMA)* Expr? | 3480 | /// ExprList <- (Expr COMMA)* Expr? |
| 3469 | fn parseBuiltinCall(p: *Parse) !Node.Index { | 3481 | fn expectBuiltinCall(p: *Parse) !Node.Index { |
| 3470 | const builtin_token = p.assertToken(.builtin); | 3482 | const builtin_token = p.assertToken(.builtin); |
| 3471 | _ = p.eatToken(.l_paren) orelse { | 3483 | _ = p.eatToken(.l_paren) orelse { |
| 3472 | try p.warn(.expected_param_list); | 3484 | try p.warn(.expected_param_list); |
| ... | @@ -3514,9 +3526,13 @@ fn parseBuiltinCall(p: *Parse) !Node.Index { | ... | @@ -3514,9 +3526,13 @@ fn parseBuiltinCall(p: *Parse) !Node.Index { |
| 3514 | } | 3526 | } |
| 3515 | } | 3527 | } |
| 3516 | 3528 | ||
| 3529 | /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else) | ||
| 3530 | /// | ||
| 3531 | /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) | ||
| 3532 | /// | ||
| 3517 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? | 3533 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? |
| 3518 | fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index { | 3534 | fn expectIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index { |
| 3519 | const if_token = p.eatToken(.keyword_if) orelse return null; | 3535 | const if_token = p.assertToken(.keyword_if); |
| 3520 | _ = try p.expectToken(.l_paren); | 3536 | _ = try p.expectToken(.l_paren); |
| 3521 | const condition = try p.expectExpr(); | 3537 | const condition = try p.expectExpr(); |
| 3522 | _ = try p.expectToken(.r_paren); | 3538 | _ = try p.expectToken(.r_paren); |
| ... | @@ -3548,11 +3564,11 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N | ... | @@ -3548,11 +3564,11 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N |
| 3548 | }); | 3564 | }); |
| 3549 | } | 3565 | } |
| 3550 | 3566 | ||
| 3551 | /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix | 3567 | /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) |
| 3552 | /// | 3568 | /// |
| 3553 | /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix | 3569 | /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) |
| 3554 | fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index { | 3570 | fn expectFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index { |
| 3555 | const for_token = p.eatToken(.keyword_for) orelse return null; | 3571 | const for_token = p.assertToken(.keyword_for); |
| 3556 | 3572 | ||
| 3557 | const scratch_top = p.scratch.items.len; | 3573 | const scratch_top = p.scratch.items.len; |
| 3558 | defer p.scratch.shrinkRetainingCapacity(scratch_top); | 3574 | defer p.scratch.shrinkRetainingCapacity(scratch_top); |
| ... | @@ -3588,7 +3604,7 @@ fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !? | ... | @@ -3588,7 +3604,7 @@ fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !? |
| 3588 | } | 3604 | } |
| 3589 | 3605 | ||
| 3590 | /// Skips over doc comment tokens. Returns the first one, if any. | 3606 | /// Skips over doc comment tokens. Returns the first one, if any. |
| 3591 | fn eatDocComments(p: *Parse) Allocator.Error!?TokenIndex { | 3607 | fn eatDocComments(p: *Parse) Error!?TokenIndex { |
| 3592 | if (p.eatToken(.doc_comment)) |tok| { | 3608 | if (p.eatToken(.doc_comment)) |tok| { |
| 3593 | var first_line = tok; | 3609 | var first_line = tok; |
| 3594 | if (tok > 0 and tokensOnSameLine(p, tok - 1, tok)) { | 3610 | if (tok > 0 and tokensOnSameLine(p, tok - 1, tok)) { |
| ... | @@ -3643,7 +3659,7 @@ fn expectSemicolon(p: *Parse, error_tag: AstError.Tag, recoverable: bool) Error! | ... | @@ -3643,7 +3659,7 @@ fn expectSemicolon(p: *Parse, error_tag: AstError.Tag, recoverable: bool) Error! |
| 3643 | return; | 3659 | return; |
| 3644 | } | 3660 | } |
| 3645 | try p.warn(error_tag); | 3661 | try p.warn(error_tag); |
| 3646 | if (!recoverable) return error.ParseError; | 3662 | if (!recoverable or !p.recover) return error.ParseError; |
| 3647 | } | 3663 | } |
| 3648 | 3664 | ||
| 3649 | fn nextToken(p: *Parse) TokenIndex { | 3665 | fn nextToken(p: *Parse) TokenIndex { |
lib/std/zig/parser_fuzz.zig created+243| ... | @@ -0,0 +1,243 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const Allocator = std.mem.Allocator; | ||
| 3 | const Smith = std.testing.Smith; | ||
| 4 | |||
| 5 | const oracle = @import("parser_generated_oracle.zig"); | ||
| 6 | |||
| 7 | test "fuzz std.zig.Ast.parse() against generated oracle" { | ||
| 8 | try std.testing.fuzz({}, fuzzAgainstOracle, .{}); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn fuzzAgainstOracle(_: void, smith: *Smith) !void { | ||
| 12 | var buffer: [1 << 14]u8 = undefined; | ||
| 13 | const len = smith.slice(buffer[0 .. buffer.len - 1]); | ||
| 14 | buffer[len] = 0; | ||
| 15 | const source = buffer[0..len :0]; | ||
| 16 | |||
| 17 | checkAgainstOracle(source) catch |err| switch (err) { | ||
| 18 | error.MaxDepth => return error.SkipZigTest, | ||
| 19 | else => |e| return e, | ||
| 20 | }; | ||
| 21 | } | ||
| 22 | |||
| 23 | test "max depth" { | ||
| 24 | try std.testing.expectError(error.MaxDepth, checkAgainstOracle("(((((")); | ||
| 25 | _ = checkAgainstOracle("((((") catch |err| switch (err) { | ||
| 26 | error.MaxDepth => try std.testing.expect(false), | ||
| 27 | else => |e| return e, | ||
| 28 | }; | ||
| 29 | } | ||
| 30 | |||
| 31 | // Found using AFL++ | ||
| 32 | test "operator whitespace" { | ||
| 33 | try checkAgainstOracle( | ||
| 34 | \\test { | ||
| 35 | \\ _!= 0; | ||
| 36 | \\} | ||
| 37 | ); | ||
| 38 | try checkAgainstOracle( | ||
| 39 | \\test{{\\ | ||
| 40 | \\*0;}} | ||
| 41 | ); | ||
| 42 | } | ||
| 43 | |||
| 44 | // Found using AFL++ | ||
| 45 | test "doc comment or division operator" { | ||
| 46 | try checkAgainstOracle("0=0///\n0"); | ||
| 47 | } | ||
| 48 | |||
| 49 | // Found using AFL++ | ||
| 50 | test "double ampersand" { | ||
| 51 | try checkAgainstOracle("0=0&&0"); // error | ||
| 52 | try checkAgainstOracle("test{&&0;}"); // ok | ||
| 53 | } | ||
| 54 | |||
| 55 | // Found using AFL++ | ||
| 56 | test "newline required before doc comment not at start of file" { | ||
| 57 | try checkAgainstOracle("0,///\n0"); // error | ||
| 58 | try checkAgainstOracle("///\n0"); // ok | ||
| 59 | try checkAgainstOracle(" ///\n0"); // ok | ||
| 60 | try checkAgainstOracle("\n///\n0"); // ok | ||
| 61 | try checkAgainstOracle("///"); // error | ||
| 62 | try checkAgainstOracle("///\n//!"); | ||
| 63 | try checkAgainstOracle("///\ntest {}"); | ||
| 64 | try checkAgainstOracle("///\ncomptime 0"); | ||
| 65 | } | ||
| 66 | |||
| 67 | // Found using AFL++ | ||
| 68 | test "extra capture in for loop" { | ||
| 69 | try checkAgainstOracle("for(0)|t,r|0"); | ||
| 70 | } | ||
| 71 | |||
| 72 | // Found using AFL++ | ||
| 73 | test "expression nesting" { | ||
| 74 | try checkAgainstOracle("test{*comptime 0 == 0;}"); | ||
| 75 | } | ||
| 76 | |||
| 77 | // Found using AFL++ | ||
| 78 | test "comptime fn" { | ||
| 79 | try checkAgainstOracle("comptime fn()0"); | ||
| 80 | } | ||
| 81 | |||
| 82 | // Found using AFL++ | ||
| 83 | test "return asterisk" { | ||
| 84 | try checkAgainstOracle("test{return*!0;}"); | ||
| 85 | } | ||
| 86 | |||
| 87 | // Found using AFL++ | ||
| 88 | test "fn container field" { | ||
| 89 | try checkAgainstOracle("fn()0"); | ||
| 90 | } | ||
| 91 | |||
| 92 | // Found using AFL++ | ||
| 93 | test "at newline string" { | ||
| 94 | try checkAgainstOracle( | ||
| 95 | \\@ | ||
| 96 | \\"" | ||
| 97 | ); | ||
| 98 | } | ||
| 99 | |||
| 100 | // Found using AFL++ | ||
| 101 | test "string lit" { | ||
| 102 | try checkAgainstOracle( | ||
| 103 | \\"\\" | ||
| 104 | ); | ||
| 105 | } | ||
| 106 | |||
| 107 | // Found using AFL++ | ||
| 108 | test "dot question" { | ||
| 109 | try checkAgainstOracle("0. ?"); | ||
| 110 | } | ||
| 111 | |||
| 112 | // Found using AFL++ | ||
| 113 | test "volatile const" { | ||
| 114 | try checkAgainstOracle("*volatile\nconst\n0"); | ||
| 115 | } | ||
| 116 | |||
| 117 | // Found using AFL++ | ||
| 118 | test "addrspace align" { | ||
| 119 | try checkAgainstOracle("*addrspace(0) align(0) 0"); | ||
| 120 | try checkAgainstOracle("*align(0) addrspace(0) 0"); | ||
| 121 | try checkAgainstOracle("[*]addrspace(0) align(0) 0"); | ||
| 122 | try checkAgainstOracle("[*]align(0) addrspace(0) 0"); | ||
| 123 | } | ||
| 124 | |||
| 125 | // Found using AFL++ | ||
| 126 | test "catch capture whitespace" { | ||
| 127 | try checkAgainstOracle("test{0 catch |h|0;}"); | ||
| 128 | } | ||
| 129 | |||
| 130 | // Found using AFL++ | ||
| 131 | test "byte order mark" { | ||
| 132 | // https://en.wikipedia.org/wiki/Byte_order_mark | ||
| 133 | try checkAgainstOracle("\xef\xbb\xbf"); | ||
| 134 | try checkAgainstOracle("\xef\xbb\xbf///\n0"); | ||
| 135 | } | ||
| 136 | |||
| 137 | // Found using AFL++ | ||
| 138 | test "nosuspend multi assign" { | ||
| 139 | try checkAgainstOracle("test{nosuspend*0,var _=0;}"); | ||
| 140 | } | ||
| 141 | |||
| 142 | // Found using AFL++ | ||
| 143 | test "bin op at end of file" { | ||
| 144 | try checkAgainstOracle( | ||
| 145 | \\test { | ||
| 146 | \\ _ = 00 | ||
| 147 | \\| | ||
| 148 | ); | ||
| 149 | } | ||
| 150 | |||
| 151 | // Found using AFL++ | ||
| 152 | test "resume block chained compare ops" { | ||
| 153 | try checkAgainstOracle("test{resume{0 > 0;} > 0 > 0;}"); | ||
| 154 | } | ||
| 155 | |||
| 156 | // Found using AFL++ | ||
| 157 | test "for multiassign" { | ||
| 158 | try checkAgainstOracle("test{for(0)|t|0,const w=0;}"); | ||
| 159 | } | ||
| 160 | |||
| 161 | fn checkAgainstOracle(source: [:0]const u8) !void { | ||
| 162 | var fba_buf: [1 << 18]u8 = undefined; | ||
| 163 | var fba: std.heap.FixedBufferAllocator = .init(&fba_buf); | ||
| 164 | |||
| 165 | const expected = try oracle.parse(source); | ||
| 166 | |||
| 167 | // It is important to disable recovery for fuzz testing. | ||
| 168 | // Consider the case where there is a parse error right at the beginning of the file, | ||
| 169 | // followed by a valid declaration with a million nested parens. The oracle will not | ||
| 170 | // skip this input due to the max depth being exceeded since the oracle hits a parse | ||
| 171 | // error right away and does no recovery. However, std.zig.Ast.parse() does recovery | ||
| 172 | // by default and will hit a stack overflow rather than returning after the parser error. | ||
| 173 | // Stack overflows are not interesting and we do not want the fuzzer to be able to find them. | ||
| 174 | const ast = try std.zig.Ast.parse(fba.allocator(), source, .zig, .{ .recover = false }); | ||
| 175 | |||
| 176 | errdefer logBadSource(source, ast); | ||
| 177 | try std.testing.expectEqual(expected, ast.errors.len == 0); | ||
| 178 | } | ||
| 179 | |||
| 180 | fn logBadSource(source: []const u8, ast: std.zig.Ast) void { | ||
| 181 | @disableInstrumentation(); | ||
| 182 | var buf: [256]u8 = undefined; | ||
| 183 | const ls = std.debug.lockStderr(&buf); | ||
| 184 | defer std.debug.unlockStderr(); | ||
| 185 | logBadSourceInner(source, ls.terminal(), ast) catch {}; | ||
| 186 | } | ||
| 187 | |||
| 188 | fn logBadSourceInner(source: []const u8, t: std.Io.Terminal, ast: std.zig.Ast) std.Io.Writer.Error!void { | ||
| 189 | @disableInstrumentation(); | ||
| 190 | try logSourceInner(source, t); | ||
| 191 | const w = t.writer; | ||
| 192 | |||
| 193 | try w.writeAll("=== Parse Errors ===\n"); | ||
| 194 | for (ast.errors) |err| { | ||
| 195 | const loc = ast.tokenLocation(0, err.token); | ||
| 196 | try w.print("{}:{}: ", .{ loc.line + 1, loc.column + 1 }); | ||
| 197 | try ast.renderError(err, w); | ||
| 198 | try w.writeByte('\n'); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | pub fn logSource(source: []const u8) void { | ||
| 203 | @disableInstrumentation(); | ||
| 204 | var buf: [256]u8 = undefined; | ||
| 205 | const ls = std.debug.lockStderr(&buf); | ||
| 206 | defer std.debug.unlockStderr(); | ||
| 207 | logSourceInner(source, ls.terminal()) catch {}; | ||
| 208 | } | ||
| 209 | |||
| 210 | fn logSourceInner(source: []const u8, t: std.Io.Terminal) std.Io.Writer.Error!void { | ||
| 211 | @disableInstrumentation(); | ||
| 212 | const w = t.writer; | ||
| 213 | |||
| 214 | t.setColor(.dim) catch {}; | ||
| 215 | try w.writeAll("=== Source ===\n"); | ||
| 216 | t.setColor(.reset) catch {}; | ||
| 217 | |||
| 218 | var line: usize = 1; | ||
| 219 | try w.print("{: >5} ", .{line}); | ||
| 220 | for (source) |c| switch (c) { | ||
| 221 | ' '...0x7e => try w.writeByte(c), | ||
| 222 | '\n' => { | ||
| 223 | line += 1; | ||
| 224 | try w.print("\n{: >5} ", .{line}); | ||
| 225 | }, | ||
| 226 | '\r' => { | ||
| 227 | t.setColor(.cyan) catch {}; | ||
| 228 | try w.writeAll("\\r"); | ||
| 229 | t.setColor(.reset) catch {}; | ||
| 230 | }, | ||
| 231 | '\t' => { | ||
| 232 | t.setColor(.cyan) catch {}; | ||
| 233 | try w.writeAll("\\t"); | ||
| 234 | t.setColor(.reset) catch {}; | ||
| 235 | }, | ||
| 236 | else => { | ||
| 237 | t.setColor(.cyan) catch {}; | ||
| 238 | try w.print("\\x{x:0>2}", .{c}); | ||
| 239 | t.setColor(.reset) catch {}; | ||
| 240 | }, | ||
| 241 | }; | ||
| 242 | try w.writeByte('\n'); | ||
| 243 | } | ||
lib/std/zig/parser_generated_oracle.zig created+6552| ... | @@ -0,0 +1,6552 @@ | ||
| 1 | //! This file is generated, do not edit manually! To generate, run: | ||
| 2 | //! zig build gen-parser-oracle | ||
| 3 | |||
| 4 | const std = @import("std"); | ||
| 5 | |||
| 6 | const Error = error{MaxDepth}; | ||
| 7 | const max_depth = 5; | ||
| 8 | |||
| 9 | /// Returns true if the input source is in the language defined by | ||
| 10 | /// the grammar. | ||
| 11 | /// Returns error.MaxDepth if more than `max_depth` levels of recursion/iteration are reached. | ||
| 12 | pub fn parse(source: []const u8) Error!bool { | ||
| 13 | var p: Parser = .{ .source = source, .i = 0, .depths = @splat(1) }; | ||
| 14 | return p.parseRoot(); | ||
| 15 | } | ||
| 16 | const Def = enum { | ||
| 17 | defRoot, | ||
| 18 | defContainerMembers, | ||
| 19 | defContainerMembersRest, | ||
| 20 | defContainerDecl, | ||
| 21 | defContainerDeclPrefix, | ||
| 22 | defTestDecl, | ||
| 23 | defComptimeDecl, | ||
| 24 | defDecl, | ||
| 25 | defDeclPrefix, | ||
| 26 | defFnProto, | ||
| 27 | defVarDeclProto, | ||
| 28 | defGlobalVarDecl, | ||
| 29 | defContainerField, | ||
| 30 | defBlockStatement, | ||
| 31 | defStatement, | ||
| 32 | defStatementPrefix, | ||
| 33 | defIfStatement, | ||
| 34 | defLabeledStatement, | ||
| 35 | defLoopStatement, | ||
| 36 | defForStatement, | ||
| 37 | defWhileStatement, | ||
| 38 | defBlockExprStatement, | ||
| 39 | defBlockExprPrefix, | ||
| 40 | defBlockExpr, | ||
| 41 | defVarAssignStatement, | ||
| 42 | defAssignExpr, | ||
| 43 | defSingleAssignExpr, | ||
| 44 | defExpr, | ||
| 45 | defBoolOrExpr, | ||
| 46 | defBoolAndExpr, | ||
| 47 | defCompareExpr, | ||
| 48 | defBitwiseExpr, | ||
| 49 | defBitShiftExpr, | ||
| 50 | defAdditionExpr, | ||
| 51 | defMultiplyExpr, | ||
| 52 | defPrefixExpr, | ||
| 53 | defPrimaryExpr, | ||
| 54 | defIfExpr, | ||
| 55 | defBlock, | ||
| 56 | defLoopExpr, | ||
| 57 | defForExpr, | ||
| 58 | defWhileExpr, | ||
| 59 | defCurlySuffixExpr, | ||
| 60 | defInitList, | ||
| 61 | defTypeExpr, | ||
| 62 | defErrorUnionExpr, | ||
| 63 | defSuffixExpr, | ||
| 64 | defPrimaryTypeExpr, | ||
| 65 | defContainerType, | ||
| 66 | defErrorSetDecl, | ||
| 67 | defGroupedExpr, | ||
| 68 | defIfTypeExpr, | ||
| 69 | defLabeledTypeExpr, | ||
| 70 | defLoopTypeExpr, | ||
| 71 | defForTypeExpr, | ||
| 72 | defWhileTypeExpr, | ||
| 73 | defSwitchExpr, | ||
| 74 | defAsmExpr, | ||
| 75 | defAsmOutput, | ||
| 76 | defAsmOutputItem, | ||
| 77 | defAsmInput, | ||
| 78 | defAsmInputItem, | ||
| 79 | defAsmClobbers, | ||
| 80 | defBreakLabel, | ||
| 81 | defBlockLabel, | ||
| 82 | defFieldInit, | ||
| 83 | defWhileContinueExpr, | ||
| 84 | defLinkSection, | ||
| 85 | defAddrSpace, | ||
| 86 | defCallConv, | ||
| 87 | defParamDecl, | ||
| 88 | defParamType, | ||
| 89 | defIfPrefix, | ||
| 90 | defWhilePrefix, | ||
| 91 | defForPrefix, | ||
| 92 | defPayload, | ||
| 93 | defPtrPayload, | ||
| 94 | defPtrIndexPayload, | ||
| 95 | defPtrListPayload, | ||
| 96 | defSwitchProng, | ||
| 97 | defSwitchCase, | ||
| 98 | defSwitchItem, | ||
| 99 | defForArgumentsList, | ||
| 100 | defForItem, | ||
| 101 | defAssignOp, | ||
| 102 | defOrOp, | ||
| 103 | defAndOp, | ||
| 104 | defCompareOp, | ||
| 105 | defCompareOpTok, | ||
| 106 | defBitwiseOp, | ||
| 107 | defBitwiseOpTok, | ||
| 108 | defBitShiftOp, | ||
| 109 | defBitShiftOpTok, | ||
| 110 | defAdditionOp, | ||
| 111 | defAdditionOpTok, | ||
| 112 | defMultiplyOp, | ||
| 113 | defMultiplyOpTok, | ||
| 114 | defPrefixOp, | ||
| 115 | defPrefixTypeOp, | ||
| 116 | defPtrMods, | ||
| 117 | defSinglePtrMods, | ||
| 118 | defPtrMod, | ||
| 119 | defPrefixTypeOpPrefix, | ||
| 120 | defSuffixOp, | ||
| 121 | defSuffixOpPrefix, | ||
| 122 | defFnCallArguments, | ||
| 123 | defSliceTypeStart, | ||
| 124 | defSinglePtrTypeStart, | ||
| 125 | defManyPtrTypeStart, | ||
| 126 | defArrayTypeStart, | ||
| 127 | defContainerTypeAuto, | ||
| 128 | defContainerTypeKind, | ||
| 129 | defByteAlign, | ||
| 130 | defBitAlign, | ||
| 131 | defIdentifierList, | ||
| 132 | defSwitchProngList, | ||
| 133 | defAsmOutputList, | ||
| 134 | defAsmInputList, | ||
| 135 | defParamDeclList, | ||
| 136 | defParamDeclListRest, | ||
| 137 | defExprList, | ||
| 138 | defExprPrefix, | ||
| 139 | defbyte_order_mark, | ||
| 140 | defsof, | ||
| 141 | defeof, | ||
| 142 | defox80_oxBF, | ||
| 143 | defoxF4, | ||
| 144 | defox80_ox8F, | ||
| 145 | defoxF1_oxF3, | ||
| 146 | defoxF0, | ||
| 147 | defox90_0xBF, | ||
| 148 | defoxEE_oxEF, | ||
| 149 | defoxED, | ||
| 150 | defox80_ox9F, | ||
| 151 | defoxE1_oxEC, | ||
| 152 | defoxE0, | ||
| 153 | defoxA0_oxBF, | ||
| 154 | defoxC2_oxDF, | ||
| 155 | defmultibyte_utf8, | ||
| 156 | defnon_control_ascii, | ||
| 157 | defnon_control_utf8, | ||
| 158 | defchar_char, | ||
| 159 | defstring_char, | ||
| 160 | defcontainer_doc_comment, | ||
| 161 | defdoc_comment, | ||
| 162 | defline_comment, | ||
| 163 | defline_string, | ||
| 164 | defnewline, | ||
| 165 | defskip, | ||
| 166 | defskip_require_newline, | ||
| 167 | defpre_op_white, | ||
| 168 | defpost_op_white, | ||
| 169 | defCHAR_LITERAL, | ||
| 170 | defdigit, | ||
| 171 | defdigit_int, | ||
| 172 | defdigit_float, | ||
| 173 | defNUMBERLITERAL, | ||
| 174 | defstring, | ||
| 175 | defSTRINGLITERALSINGLE, | ||
| 176 | defSTRINGLITERAL, | ||
| 177 | defIDENTIFIER, | ||
| 178 | defBUILTINIDENTIFIER, | ||
| 179 | defAMPERSAND, | ||
| 180 | defAMPERSANDEQUAL, | ||
| 181 | defASTERISK, | ||
| 182 | defASTERISKEQUAL, | ||
| 183 | defASTERISKPERCENT, | ||
| 184 | defASTERISKPERCENTEQUAL, | ||
| 185 | defASTERISKPIPE, | ||
| 186 | defASTERISKPIPEEQUAL, | ||
| 187 | defCARET, | ||
| 188 | defCARETEQUAL, | ||
| 189 | defCOLON, | ||
| 190 | defCOMMA, | ||
| 191 | defDOT, | ||
| 192 | defDOT2, | ||
| 193 | defDOT3, | ||
| 194 | defDOTASTERISK, | ||
| 195 | defEQUAL, | ||
| 196 | defEQUALEQUAL, | ||
| 197 | defEQUALRARROW, | ||
| 198 | defEXCLAMATIONMARK, | ||
| 199 | defEXCLAMATIONMARKEQUAL, | ||
| 200 | defLARROW, | ||
| 201 | defLARROW2, | ||
| 202 | defLARROW2EQUAL, | ||
| 203 | defLARROW2PIPE, | ||
| 204 | defLARROW2PIPEEQUAL, | ||
| 205 | defLARROWEQUAL, | ||
| 206 | defLBRACE, | ||
| 207 | defLBRACKET, | ||
| 208 | defLPAREN, | ||
| 209 | defMINUS, | ||
| 210 | defMINUSEQUAL, | ||
| 211 | defMINUSPERCENT, | ||
| 212 | defMINUSPERCENTEQUAL, | ||
| 213 | defMINUSPIPE, | ||
| 214 | defMINUSPIPEEQUAL, | ||
| 215 | defMINUSRARROW, | ||
| 216 | defPERCENT, | ||
| 217 | defPERCENTEQUAL, | ||
| 218 | defPIPE, | ||
| 219 | defPIPE2, | ||
| 220 | defPIPEEQUAL, | ||
| 221 | defPLUS, | ||
| 222 | defPLUS2, | ||
| 223 | defPLUSEQUAL, | ||
| 224 | defPLUSPERCENT, | ||
| 225 | defPLUSPERCENTEQUAL, | ||
| 226 | defPLUSPIPE, | ||
| 227 | defPLUSPIPEEQUAL, | ||
| 228 | defLETTERC, | ||
| 229 | defQUESTIONMARK, | ||
| 230 | defRARROW, | ||
| 231 | defRARROW2, | ||
| 232 | defRARROW2EQUAL, | ||
| 233 | defRARROWEQUAL, | ||
| 234 | defRBRACE, | ||
| 235 | defRBRACKET, | ||
| 236 | defRPAREN, | ||
| 237 | defSEMICOLON, | ||
| 238 | defSLASH, | ||
| 239 | defSLASHEQUAL, | ||
| 240 | defTILDE, | ||
| 241 | defend_of_word, | ||
| 242 | defKEYWORD_addrspace, | ||
| 243 | defKEYWORD_align, | ||
| 244 | defKEYWORD_allowzero, | ||
| 245 | defKEYWORD_and, | ||
| 246 | defKEYWORD_anyframe, | ||
| 247 | defKEYWORD_anytype, | ||
| 248 | defKEYWORD_asm, | ||
| 249 | defKEYWORD_break, | ||
| 250 | defKEYWORD_callconv, | ||
| 251 | defKEYWORD_catch, | ||
| 252 | defKEYWORD_comptime, | ||
| 253 | defKEYWORD_const, | ||
| 254 | defKEYWORD_continue, | ||
| 255 | defKEYWORD_defer, | ||
| 256 | defKEYWORD_else, | ||
| 257 | defKEYWORD_enum, | ||
| 258 | defKEYWORD_errdefer, | ||
| 259 | defKEYWORD_error, | ||
| 260 | defKEYWORD_export, | ||
| 261 | defKEYWORD_extern, | ||
| 262 | defKEYWORD_fn, | ||
| 263 | defKEYWORD_for, | ||
| 264 | defKEYWORD_if, | ||
| 265 | defKEYWORD_inline, | ||
| 266 | defKEYWORD_noalias, | ||
| 267 | defKEYWORD_nosuspend, | ||
| 268 | defKEYWORD_noinline, | ||
| 269 | defKEYWORD_opaque, | ||
| 270 | defKEYWORD_or, | ||
| 271 | defKEYWORD_orelse, | ||
| 272 | defKEYWORD_packed, | ||
| 273 | defKEYWORD_pub, | ||
| 274 | defKEYWORD_resume, | ||
| 275 | defKEYWORD_return, | ||
| 276 | defKEYWORD_linksection, | ||
| 277 | defKEYWORD_struct, | ||
| 278 | defKEYWORD_suspend, | ||
| 279 | defKEYWORD_switch, | ||
| 280 | defKEYWORD_test, | ||
| 281 | defKEYWORD_threadlocal, | ||
| 282 | defKEYWORD_try, | ||
| 283 | defKEYWORD_union, | ||
| 284 | defKEYWORD_unreachable, | ||
| 285 | defKEYWORD_var, | ||
| 286 | defKEYWORD_volatile, | ||
| 287 | defKEYWORD_while, | ||
| 288 | defkeyword, | ||
| 289 | }; | ||
| 290 | const Parser = struct { | ||
| 291 | source: []const u8, | ||
| 292 | i: usize, | ||
| 293 | depths: [272]u8, | ||
| 294 | pub fn parseRoot(p: *Parser) Error!bool { | ||
| 295 | const def_index = @intFromEnum(Def.defRoot); | ||
| 296 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 297 | p.depths[def_index] += 1; | ||
| 298 | defer p.depths[def_index] -= 1; | ||
| 299 | return blk_0: { | ||
| 300 | const pos_0 = p.i; | ||
| 301 | if (try p.parseContainerMembers() and try p.parseskip() and try p.parseeof()) break :blk_0 true; | ||
| 302 | p.i = pos_0; | ||
| 303 | break :blk_0 false; | ||
| 304 | }; | ||
| 305 | } | ||
| 306 | pub fn parseContainerMembers(p: *Parser) Error!bool { | ||
| 307 | const def_index = @intFromEnum(Def.defContainerMembers); | ||
| 308 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 309 | p.depths[def_index] += 1; | ||
| 310 | defer p.depths[def_index] -= 1; | ||
| 311 | return blk_0: { | ||
| 312 | const pos_0 = p.i; | ||
| 313 | if ((try p.parsecontainer_doc_comment() or true) and blk_1: { | ||
| 314 | var i_1: usize = 0; | ||
| 315 | while (try p.parseContainerDecl()) { | ||
| 316 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 317 | i_1 += 1; | ||
| 318 | } | ||
| 319 | break :blk_1 true; | ||
| 320 | } and try p.parseContainerMembersRest()) break :blk_0 true; | ||
| 321 | p.i = pos_0; | ||
| 322 | break :blk_0 false; | ||
| 323 | }; | ||
| 324 | } | ||
| 325 | pub fn parseContainerMembersRest(p: *Parser) Error!bool { | ||
| 326 | const def_index = @intFromEnum(Def.defContainerMembersRest); | ||
| 327 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 328 | p.depths[def_index] += 1; | ||
| 329 | defer p.depths[def_index] -= 1; | ||
| 330 | return blk_0: { | ||
| 331 | const pos_0 = p.i; | ||
| 332 | if (blk_1: { | ||
| 333 | const pos_1 = p.i; | ||
| 334 | const match_1 = try p.parseContainerDeclPrefix(); | ||
| 335 | p.i = pos_1; | ||
| 336 | break :blk_1 !match_1; | ||
| 337 | } and try p.parseContainerField() and (blk_3: { | ||
| 338 | const pos_3 = p.i; | ||
| 339 | if (try p.parseCOMMA() and try p.parseContainerMembersRest()) break :blk_3 true; | ||
| 340 | p.i = pos_3; | ||
| 341 | break :blk_3 false; | ||
| 342 | } or true)) break :blk_0 true; | ||
| 343 | p.i = pos_0; | ||
| 344 | if (blk_1: { | ||
| 345 | var i_1: usize = 0; | ||
| 346 | while (try p.parseContainerDecl()) { | ||
| 347 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 348 | i_1 += 1; | ||
| 349 | } | ||
| 350 | break :blk_1 true; | ||
| 351 | }) break :blk_0 true; | ||
| 352 | p.i = pos_0; | ||
| 353 | break :blk_0 false; | ||
| 354 | }; | ||
| 355 | } | ||
| 356 | pub fn parseContainerDecl(p: *Parser) Error!bool { | ||
| 357 | const def_index = @intFromEnum(Def.defContainerDecl); | ||
| 358 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 359 | p.depths[def_index] += 1; | ||
| 360 | defer p.depths[def_index] -= 1; | ||
| 361 | return blk_0: { | ||
| 362 | const pos_0 = p.i; | ||
| 363 | if (try p.parseTestDecl()) break :blk_0 true; | ||
| 364 | p.i = pos_0; | ||
| 365 | if (try p.parseComptimeDecl()) break :blk_0 true; | ||
| 366 | p.i = pos_0; | ||
| 367 | if ((try p.parsedoc_comment() or true) and (try p.parseKEYWORD_pub() or true) and try p.parseDecl()) break :blk_0 true; | ||
| 368 | p.i = pos_0; | ||
| 369 | break :blk_0 false; | ||
| 370 | }; | ||
| 371 | } | ||
| 372 | pub fn parseContainerDeclPrefix(p: *Parser) Error!bool { | ||
| 373 | const def_index = @intFromEnum(Def.defContainerDeclPrefix); | ||
| 374 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 375 | p.depths[def_index] += 1; | ||
| 376 | defer p.depths[def_index] -= 1; | ||
| 377 | return blk_0: { | ||
| 378 | const pos_0 = p.i; | ||
| 379 | if (try p.parseKEYWORD_test()) break :blk_0 true; | ||
| 380 | p.i = pos_0; | ||
| 381 | if (try p.parseKEYWORD_comptime() and try p.parseLBRACE()) break :blk_0 true; | ||
| 382 | p.i = pos_0; | ||
| 383 | if ((try p.parsedoc_comment() or true) and (try p.parseKEYWORD_pub() or true) and try p.parseDeclPrefix()) break :blk_0 true; | ||
| 384 | p.i = pos_0; | ||
| 385 | break :blk_0 false; | ||
| 386 | }; | ||
| 387 | } | ||
| 388 | pub fn parseTestDecl(p: *Parser) Error!bool { | ||
| 389 | const def_index = @intFromEnum(Def.defTestDecl); | ||
| 390 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 391 | p.depths[def_index] += 1; | ||
| 392 | defer p.depths[def_index] -= 1; | ||
| 393 | return blk_0: { | ||
| 394 | const pos_0 = p.i; | ||
| 395 | if (try p.parseKEYWORD_test() and (blk_3: { | ||
| 396 | const pos_3 = p.i; | ||
| 397 | if (try p.parseSTRINGLITERALSINGLE()) break :blk_3 true; | ||
| 398 | p.i = pos_3; | ||
| 399 | if (try p.parseIDENTIFIER()) break :blk_3 true; | ||
| 400 | p.i = pos_3; | ||
| 401 | break :blk_3 false; | ||
| 402 | } or true) and try p.parseBlock()) break :blk_0 true; | ||
| 403 | p.i = pos_0; | ||
| 404 | break :blk_0 false; | ||
| 405 | }; | ||
| 406 | } | ||
| 407 | pub fn parseComptimeDecl(p: *Parser) Error!bool { | ||
| 408 | const def_index = @intFromEnum(Def.defComptimeDecl); | ||
| 409 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 410 | p.depths[def_index] += 1; | ||
| 411 | defer p.depths[def_index] -= 1; | ||
| 412 | return blk_0: { | ||
| 413 | const pos_0 = p.i; | ||
| 414 | if (try p.parseKEYWORD_comptime() and try p.parseBlock()) break :blk_0 true; | ||
| 415 | p.i = pos_0; | ||
| 416 | break :blk_0 false; | ||
| 417 | }; | ||
| 418 | } | ||
| 419 | pub fn parseDecl(p: *Parser) Error!bool { | ||
| 420 | const def_index = @intFromEnum(Def.defDecl); | ||
| 421 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 422 | p.depths[def_index] += 1; | ||
| 423 | defer p.depths[def_index] -= 1; | ||
| 424 | return blk_0: { | ||
| 425 | const pos_0 = p.i; | ||
| 426 | if ((blk_3: { | ||
| 427 | const pos_3 = p.i; | ||
| 428 | if (try p.parseKEYWORD_export()) break :blk_3 true; | ||
| 429 | p.i = pos_3; | ||
| 430 | if (try p.parseKEYWORD_inline()) break :blk_3 true; | ||
| 431 | p.i = pos_3; | ||
| 432 | if (try p.parseKEYWORD_noinline()) break :blk_3 true; | ||
| 433 | p.i = pos_3; | ||
| 434 | break :blk_3 false; | ||
| 435 | } or true) and try p.parseFnProto() and blk_2: { | ||
| 436 | const pos_2 = p.i; | ||
| 437 | if (try p.parseSEMICOLON()) break :blk_2 true; | ||
| 438 | p.i = pos_2; | ||
| 439 | if (try p.parseBlock()) break :blk_2 true; | ||
| 440 | p.i = pos_2; | ||
| 441 | break :blk_2 false; | ||
| 442 | }) break :blk_0 true; | ||
| 443 | p.i = pos_0; | ||
| 444 | if (try p.parseKEYWORD_extern() and (try p.parseSTRINGLITERALSINGLE() or true) and try p.parseFnProto() and try p.parseSEMICOLON()) break :blk_0 true; | ||
| 445 | p.i = pos_0; | ||
| 446 | if ((blk_3: { | ||
| 447 | const pos_3 = p.i; | ||
| 448 | if (try p.parseKEYWORD_export()) break :blk_3 true; | ||
| 449 | p.i = pos_3; | ||
| 450 | if (try p.parseKEYWORD_extern() and (try p.parseSTRINGLITERALSINGLE() or true)) break :blk_3 true; | ||
| 451 | p.i = pos_3; | ||
| 452 | break :blk_3 false; | ||
| 453 | } or true) and (try p.parseKEYWORD_threadlocal() or true) and try p.parseGlobalVarDecl()) break :blk_0 true; | ||
| 454 | p.i = pos_0; | ||
| 455 | break :blk_0 false; | ||
| 456 | }; | ||
| 457 | } | ||
| 458 | pub fn parseDeclPrefix(p: *Parser) Error!bool { | ||
| 459 | const def_index = @intFromEnum(Def.defDeclPrefix); | ||
| 460 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 461 | p.depths[def_index] += 1; | ||
| 462 | defer p.depths[def_index] -= 1; | ||
| 463 | return blk_0: { | ||
| 464 | const pos_0 = p.i; | ||
| 465 | if ((blk_3: { | ||
| 466 | const pos_3 = p.i; | ||
| 467 | if (try p.parseKEYWORD_export()) break :blk_3 true; | ||
| 468 | p.i = pos_3; | ||
| 469 | if (try p.parseKEYWORD_inline()) break :blk_3 true; | ||
| 470 | p.i = pos_3; | ||
| 471 | if (try p.parseKEYWORD_noinline()) break :blk_3 true; | ||
| 472 | p.i = pos_3; | ||
| 473 | break :blk_3 false; | ||
| 474 | } or true) and try p.parseKEYWORD_fn()) break :blk_0 true; | ||
| 475 | p.i = pos_0; | ||
| 476 | if (try p.parseKEYWORD_extern() and (try p.parseSTRINGLITERALSINGLE() or true) and try p.parseKEYWORD_fn()) break :blk_0 true; | ||
| 477 | p.i = pos_0; | ||
| 478 | if ((blk_3: { | ||
| 479 | const pos_3 = p.i; | ||
| 480 | if (try p.parseKEYWORD_export()) break :blk_3 true; | ||
| 481 | p.i = pos_3; | ||
| 482 | if (try p.parseKEYWORD_extern() and (try p.parseSTRINGLITERALSINGLE() or true)) break :blk_3 true; | ||
| 483 | p.i = pos_3; | ||
| 484 | break :blk_3 false; | ||
| 485 | } or true) and (try p.parseKEYWORD_threadlocal() or true) and blk_2: { | ||
| 486 | const pos_2 = p.i; | ||
| 487 | if (try p.parseKEYWORD_const()) break :blk_2 true; | ||
| 488 | p.i = pos_2; | ||
| 489 | if (try p.parseKEYWORD_var()) break :blk_2 true; | ||
| 490 | p.i = pos_2; | ||
| 491 | break :blk_2 false; | ||
| 492 | }) break :blk_0 true; | ||
| 493 | p.i = pos_0; | ||
| 494 | break :blk_0 false; | ||
| 495 | }; | ||
| 496 | } | ||
| 497 | pub fn parseFnProto(p: *Parser) Error!bool { | ||
| 498 | const def_index = @intFromEnum(Def.defFnProto); | ||
| 499 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 500 | p.depths[def_index] += 1; | ||
| 501 | defer p.depths[def_index] -= 1; | ||
| 502 | return blk_0: { | ||
| 503 | const pos_0 = p.i; | ||
| 504 | if (try p.parseKEYWORD_fn() and (try p.parseIDENTIFIER() or true) and try p.parseParamDeclList() and (try p.parseByteAlign() or true) and (try p.parseAddrSpace() or true) and (try p.parseLinkSection() or true) and (try p.parseCallConv() or true) and (try p.parseEXCLAMATIONMARK() or true) and try p.parseTypeExpr()) break :blk_0 true; | ||
| 505 | p.i = pos_0; | ||
| 506 | break :blk_0 false; | ||
| 507 | }; | ||
| 508 | } | ||
| 509 | pub fn parseVarDeclProto(p: *Parser) Error!bool { | ||
| 510 | const def_index = @intFromEnum(Def.defVarDeclProto); | ||
| 511 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 512 | p.depths[def_index] += 1; | ||
| 513 | defer p.depths[def_index] -= 1; | ||
| 514 | return blk_0: { | ||
| 515 | const pos_0 = p.i; | ||
| 516 | if (blk_2: { | ||
| 517 | const pos_2 = p.i; | ||
| 518 | if (try p.parseKEYWORD_const()) break :blk_2 true; | ||
| 519 | p.i = pos_2; | ||
| 520 | if (try p.parseKEYWORD_var()) break :blk_2 true; | ||
| 521 | p.i = pos_2; | ||
| 522 | break :blk_2 false; | ||
| 523 | } and try p.parseIDENTIFIER() and (blk_3: { | ||
| 524 | const pos_3 = p.i; | ||
| 525 | if (try p.parseCOLON() and try p.parseTypeExpr()) break :blk_3 true; | ||
| 526 | p.i = pos_3; | ||
| 527 | break :blk_3 false; | ||
| 528 | } or true) and (try p.parseByteAlign() or true) and (try p.parseAddrSpace() or true) and (try p.parseLinkSection() or true)) break :blk_0 true; | ||
| 529 | p.i = pos_0; | ||
| 530 | break :blk_0 false; | ||
| 531 | }; | ||
| 532 | } | ||
| 533 | pub fn parseGlobalVarDecl(p: *Parser) Error!bool { | ||
| 534 | const def_index = @intFromEnum(Def.defGlobalVarDecl); | ||
| 535 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 536 | p.depths[def_index] += 1; | ||
| 537 | defer p.depths[def_index] -= 1; | ||
| 538 | return blk_0: { | ||
| 539 | const pos_0 = p.i; | ||
| 540 | if (try p.parseVarDeclProto() and (blk_3: { | ||
| 541 | const pos_3 = p.i; | ||
| 542 | if (try p.parseEQUAL() and try p.parseExpr()) break :blk_3 true; | ||
| 543 | p.i = pos_3; | ||
| 544 | break :blk_3 false; | ||
| 545 | } or true) and try p.parseSEMICOLON()) break :blk_0 true; | ||
| 546 | p.i = pos_0; | ||
| 547 | break :blk_0 false; | ||
| 548 | }; | ||
| 549 | } | ||
| 550 | pub fn parseContainerField(p: *Parser) Error!bool { | ||
| 551 | const def_index = @intFromEnum(Def.defContainerField); | ||
| 552 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 553 | p.depths[def_index] += 1; | ||
| 554 | defer p.depths[def_index] -= 1; | ||
| 555 | return blk_0: { | ||
| 556 | const pos_0 = p.i; | ||
| 557 | if ((try p.parsedoc_comment() or true) and (try p.parseKEYWORD_comptime() or true) and (blk_3: { | ||
| 558 | const pos_3 = p.i; | ||
| 559 | if (try p.parseIDENTIFIER() and try p.parseCOLON()) break :blk_3 true; | ||
| 560 | p.i = pos_3; | ||
| 561 | break :blk_3 false; | ||
| 562 | } or true) and try p.parseTypeExpr() and (try p.parseByteAlign() or true) and (blk_3: { | ||
| 563 | const pos_3 = p.i; | ||
| 564 | if (try p.parseEQUAL() and try p.parseExpr()) break :blk_3 true; | ||
| 565 | p.i = pos_3; | ||
| 566 | break :blk_3 false; | ||
| 567 | } or true)) break :blk_0 true; | ||
| 568 | p.i = pos_0; | ||
| 569 | break :blk_0 false; | ||
| 570 | }; | ||
| 571 | } | ||
| 572 | pub fn parseBlockStatement(p: *Parser) Error!bool { | ||
| 573 | const def_index = @intFromEnum(Def.defBlockStatement); | ||
| 574 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 575 | p.depths[def_index] += 1; | ||
| 576 | defer p.depths[def_index] -= 1; | ||
| 577 | return blk_0: { | ||
| 578 | const pos_0 = p.i; | ||
| 579 | if (try p.parseStatement()) break :blk_0 true; | ||
| 580 | p.i = pos_0; | ||
| 581 | if (try p.parseKEYWORD_defer() and try p.parseBlockExprStatement()) break :blk_0 true; | ||
| 582 | p.i = pos_0; | ||
| 583 | if (try p.parseKEYWORD_errdefer() and try p.parseBlockExprStatement()) break :blk_0 true; | ||
| 584 | p.i = pos_0; | ||
| 585 | if (blk_1: { | ||
| 586 | const pos_1 = p.i; | ||
| 587 | const match_1 = try p.parseStatementPrefix(); | ||
| 588 | p.i = pos_1; | ||
| 589 | break :blk_1 !match_1; | ||
| 590 | } and (try p.parseKEYWORD_comptime() or true) and try p.parseVarAssignStatement()) break :blk_0 true; | ||
| 591 | p.i = pos_0; | ||
| 592 | break :blk_0 false; | ||
| 593 | }; | ||
| 594 | } | ||
| 595 | pub fn parseStatement(p: *Parser) Error!bool { | ||
| 596 | const def_index = @intFromEnum(Def.defStatement); | ||
| 597 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 598 | p.depths[def_index] += 1; | ||
| 599 | defer p.depths[def_index] -= 1; | ||
| 600 | return blk_0: { | ||
| 601 | const pos_0 = p.i; | ||
| 602 | if (try p.parseIfStatement()) break :blk_0 true; | ||
| 603 | p.i = pos_0; | ||
| 604 | if (try p.parseLabeledStatement()) break :blk_0 true; | ||
| 605 | p.i = pos_0; | ||
| 606 | if (try p.parseKEYWORD_nosuspend() and try p.parseBlockExprStatement()) break :blk_0 true; | ||
| 607 | p.i = pos_0; | ||
| 608 | if (try p.parseKEYWORD_comptime() and try p.parseBlockExpr()) break :blk_0 true; | ||
| 609 | p.i = pos_0; | ||
| 610 | if (try p.parseKEYWORD_suspend() and try p.parseBlockExprStatement()) break :blk_0 true; | ||
| 611 | p.i = pos_0; | ||
| 612 | if (blk_1: { | ||
| 613 | const pos_1 = p.i; | ||
| 614 | const match_1 = try p.parseStatementPrefix(); | ||
| 615 | p.i = pos_1; | ||
| 616 | break :blk_1 !match_1; | ||
| 617 | } and (try p.parseKEYWORD_comptime() or true) and try p.parseAssignExpr() and try p.parseSEMICOLON()) break :blk_0 true; | ||
| 618 | p.i = pos_0; | ||
| 619 | break :blk_0 false; | ||
| 620 | }; | ||
| 621 | } | ||
| 622 | pub fn parseStatementPrefix(p: *Parser) Error!bool { | ||
| 623 | const def_index = @intFromEnum(Def.defStatementPrefix); | ||
| 624 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 625 | p.depths[def_index] += 1; | ||
| 626 | defer p.depths[def_index] -= 1; | ||
| 627 | return blk_0: { | ||
| 628 | const pos_0 = p.i; | ||
| 629 | if (try p.parseKEYWORD_if()) break :blk_0 true; | ||
| 630 | p.i = pos_0; | ||
| 631 | if ((try p.parseBlockLabel() or true) and blk_2: { | ||
| 632 | const pos_2 = p.i; | ||
| 633 | if (try p.parseLBRACE()) break :blk_2 true; | ||
| 634 | p.i = pos_2; | ||
| 635 | if ((try p.parseKEYWORD_inline() or true) and blk_4: { | ||
| 636 | const pos_4 = p.i; | ||
| 637 | if (try p.parseKEYWORD_for()) break :blk_4 true; | ||
| 638 | p.i = pos_4; | ||
| 639 | if (try p.parseKEYWORD_while()) break :blk_4 true; | ||
| 640 | p.i = pos_4; | ||
| 641 | break :blk_4 false; | ||
| 642 | }) break :blk_2 true; | ||
| 643 | p.i = pos_2; | ||
| 644 | if (try p.parseKEYWORD_switch()) break :blk_2 true; | ||
| 645 | p.i = pos_2; | ||
| 646 | break :blk_2 false; | ||
| 647 | }) break :blk_0 true; | ||
| 648 | p.i = pos_0; | ||
| 649 | if (try p.parseKEYWORD_nosuspend()) break :blk_0 true; | ||
| 650 | p.i = pos_0; | ||
| 651 | if (try p.parseKEYWORD_comptime() and try p.parseBlockExprPrefix()) break :blk_0 true; | ||
| 652 | p.i = pos_0; | ||
| 653 | break :blk_0 false; | ||
| 654 | }; | ||
| 655 | } | ||
| 656 | pub fn parseIfStatement(p: *Parser) Error!bool { | ||
| 657 | const def_index = @intFromEnum(Def.defIfStatement); | ||
| 658 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 659 | p.depths[def_index] += 1; | ||
| 660 | defer p.depths[def_index] -= 1; | ||
| 661 | return blk_0: { | ||
| 662 | const pos_0 = p.i; | ||
| 663 | if (try p.parseIfPrefix() and try p.parseBlockExpr() and blk_2: { | ||
| 664 | const pos_2 = p.i; | ||
| 665 | if (try p.parseKEYWORD_else() and (try p.parsePayload() or true) and try p.parseStatement()) break :blk_2 true; | ||
| 666 | p.i = pos_2; | ||
| 667 | if (blk_3: { | ||
| 668 | const pos_3 = p.i; | ||
| 669 | const match_3 = try p.parseKEYWORD_else(); | ||
| 670 | p.i = pos_3; | ||
| 671 | break :blk_3 !match_3; | ||
| 672 | }) break :blk_2 true; | ||
| 673 | p.i = pos_2; | ||
| 674 | break :blk_2 false; | ||
| 675 | }) break :blk_0 true; | ||
| 676 | p.i = pos_0; | ||
| 677 | if (try p.parseIfPrefix() and blk_1: { | ||
| 678 | const pos_1 = p.i; | ||
| 679 | const match_1 = try p.parseBlockExprPrefix(); | ||
| 680 | p.i = pos_1; | ||
| 681 | break :blk_1 !match_1; | ||
| 682 | } and try p.parseAssignExpr() and blk_2: { | ||
| 683 | const pos_2 = p.i; | ||
| 684 | if (try p.parseSEMICOLON()) break :blk_2 true; | ||
| 685 | p.i = pos_2; | ||
| 686 | if (try p.parseKEYWORD_else() and (try p.parsePayload() or true) and try p.parseStatement()) break :blk_2 true; | ||
| 687 | p.i = pos_2; | ||
| 688 | break :blk_2 false; | ||
| 689 | }) break :blk_0 true; | ||
| 690 | p.i = pos_0; | ||
| 691 | break :blk_0 false; | ||
| 692 | }; | ||
| 693 | } | ||
| 694 | pub fn parseLabeledStatement(p: *Parser) Error!bool { | ||
| 695 | const def_index = @intFromEnum(Def.defLabeledStatement); | ||
| 696 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 697 | p.depths[def_index] += 1; | ||
| 698 | defer p.depths[def_index] -= 1; | ||
| 699 | return blk_0: { | ||
| 700 | const pos_0 = p.i; | ||
| 701 | if ((try p.parseBlockLabel() or true) and blk_2: { | ||
| 702 | const pos_2 = p.i; | ||
| 703 | if (try p.parseBlock()) break :blk_2 true; | ||
| 704 | p.i = pos_2; | ||
| 705 | if (try p.parseLoopStatement()) break :blk_2 true; | ||
| 706 | p.i = pos_2; | ||
| 707 | if (try p.parseSwitchExpr()) break :blk_2 true; | ||
| 708 | p.i = pos_2; | ||
| 709 | break :blk_2 false; | ||
| 710 | }) break :blk_0 true; | ||
| 711 | p.i = pos_0; | ||
| 712 | break :blk_0 false; | ||
| 713 | }; | ||
| 714 | } | ||
| 715 | pub fn parseLoopStatement(p: *Parser) Error!bool { | ||
| 716 | const def_index = @intFromEnum(Def.defLoopStatement); | ||
| 717 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 718 | p.depths[def_index] += 1; | ||
| 719 | defer p.depths[def_index] -= 1; | ||
| 720 | return blk_0: { | ||
| 721 | const pos_0 = p.i; | ||
| 722 | if ((try p.parseKEYWORD_inline() or true) and blk_2: { | ||
| 723 | const pos_2 = p.i; | ||
| 724 | if (try p.parseForStatement()) break :blk_2 true; | ||
| 725 | p.i = pos_2; | ||
| 726 | if (try p.parseWhileStatement()) break :blk_2 true; | ||
| 727 | p.i = pos_2; | ||
| 728 | break :blk_2 false; | ||
| 729 | }) break :blk_0 true; | ||
| 730 | p.i = pos_0; | ||
| 731 | break :blk_0 false; | ||
| 732 | }; | ||
| 733 | } | ||
| 734 | pub fn parseForStatement(p: *Parser) Error!bool { | ||
| 735 | const def_index = @intFromEnum(Def.defForStatement); | ||
| 736 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 737 | p.depths[def_index] += 1; | ||
| 738 | defer p.depths[def_index] -= 1; | ||
| 739 | return blk_0: { | ||
| 740 | const pos_0 = p.i; | ||
| 741 | if (try p.parseForPrefix() and try p.parseBlockExpr() and blk_2: { | ||
| 742 | const pos_2 = p.i; | ||
| 743 | if (try p.parseKEYWORD_else() and try p.parseStatement()) break :blk_2 true; | ||
| 744 | p.i = pos_2; | ||
| 745 | if (blk_3: { | ||
| 746 | const pos_3 = p.i; | ||
| 747 | const match_3 = try p.parseKEYWORD_else(); | ||
| 748 | p.i = pos_3; | ||
| 749 | break :blk_3 !match_3; | ||
| 750 | }) break :blk_2 true; | ||
| 751 | p.i = pos_2; | ||
| 752 | break :blk_2 false; | ||
| 753 | }) break :blk_0 true; | ||
| 754 | p.i = pos_0; | ||
| 755 | if (try p.parseForPrefix() and blk_1: { | ||
| 756 | const pos_1 = p.i; | ||
| 757 | const match_1 = try p.parseBlockExprPrefix(); | ||
| 758 | p.i = pos_1; | ||
| 759 | break :blk_1 !match_1; | ||
| 760 | } and try p.parseAssignExpr() and blk_2: { | ||
| 761 | const pos_2 = p.i; | ||
| 762 | if (try p.parseSEMICOLON()) break :blk_2 true; | ||
| 763 | p.i = pos_2; | ||
| 764 | if (try p.parseKEYWORD_else() and try p.parseStatement()) break :blk_2 true; | ||
| 765 | p.i = pos_2; | ||
| 766 | break :blk_2 false; | ||
| 767 | }) break :blk_0 true; | ||
| 768 | p.i = pos_0; | ||
| 769 | break :blk_0 false; | ||
| 770 | }; | ||
| 771 | } | ||
| 772 | pub fn parseWhileStatement(p: *Parser) Error!bool { | ||
| 773 | const def_index = @intFromEnum(Def.defWhileStatement); | ||
| 774 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 775 | p.depths[def_index] += 1; | ||
| 776 | defer p.depths[def_index] -= 1; | ||
| 777 | return blk_0: { | ||
| 778 | const pos_0 = p.i; | ||
| 779 | if (try p.parseWhilePrefix() and try p.parseBlockExpr() and blk_2: { | ||
| 780 | const pos_2 = p.i; | ||
| 781 | if (try p.parseKEYWORD_else() and (try p.parsePayload() or true) and try p.parseStatement()) break :blk_2 true; | ||
| 782 | p.i = pos_2; | ||
| 783 | if (blk_3: { | ||
| 784 | const pos_3 = p.i; | ||
| 785 | const match_3 = try p.parseKEYWORD_else(); | ||
| 786 | p.i = pos_3; | ||
| 787 | break :blk_3 !match_3; | ||
| 788 | }) break :blk_2 true; | ||
| 789 | p.i = pos_2; | ||
| 790 | break :blk_2 false; | ||
| 791 | }) break :blk_0 true; | ||
| 792 | p.i = pos_0; | ||
| 793 | if (try p.parseWhilePrefix() and blk_1: { | ||
| 794 | const pos_1 = p.i; | ||
| 795 | const match_1 = try p.parseBlockExprPrefix(); | ||
| 796 | p.i = pos_1; | ||
| 797 | break :blk_1 !match_1; | ||
| 798 | } and try p.parseAssignExpr() and blk_2: { | ||
| 799 | const pos_2 = p.i; | ||
| 800 | if (try p.parseSEMICOLON()) break :blk_2 true; | ||
| 801 | p.i = pos_2; | ||
| 802 | if (try p.parseKEYWORD_else() and (try p.parsePayload() or true) and try p.parseStatement()) break :blk_2 true; | ||
| 803 | p.i = pos_2; | ||
| 804 | break :blk_2 false; | ||
| 805 | }) break :blk_0 true; | ||
| 806 | p.i = pos_0; | ||
| 807 | break :blk_0 false; | ||
| 808 | }; | ||
| 809 | } | ||
| 810 | pub fn parseBlockExprStatement(p: *Parser) Error!bool { | ||
| 811 | const def_index = @intFromEnum(Def.defBlockExprStatement); | ||
| 812 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 813 | p.depths[def_index] += 1; | ||
| 814 | defer p.depths[def_index] -= 1; | ||
| 815 | return blk_0: { | ||
| 816 | const pos_0 = p.i; | ||
| 817 | if (try p.parseBlockExpr()) break :blk_0 true; | ||
| 818 | p.i = pos_0; | ||
| 819 | if (blk_1: { | ||
| 820 | const pos_1 = p.i; | ||
| 821 | const match_1 = try p.parseBlockExprPrefix(); | ||
| 822 | p.i = pos_1; | ||
| 823 | break :blk_1 !match_1; | ||
| 824 | } and try p.parseAssignExpr() and try p.parseSEMICOLON()) break :blk_0 true; | ||
| 825 | p.i = pos_0; | ||
| 826 | break :blk_0 false; | ||
| 827 | }; | ||
| 828 | } | ||
| 829 | pub fn parseBlockExprPrefix(p: *Parser) Error!bool { | ||
| 830 | const def_index = @intFromEnum(Def.defBlockExprPrefix); | ||
| 831 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 832 | p.depths[def_index] += 1; | ||
| 833 | defer p.depths[def_index] -= 1; | ||
| 834 | return blk_0: { | ||
| 835 | const pos_0 = p.i; | ||
| 836 | if ((try p.parseBlockLabel() or true) and try p.parseLBRACE()) break :blk_0 true; | ||
| 837 | p.i = pos_0; | ||
| 838 | break :blk_0 false; | ||
| 839 | }; | ||
| 840 | } | ||
| 841 | pub fn parseBlockExpr(p: *Parser) Error!bool { | ||
| 842 | const def_index = @intFromEnum(Def.defBlockExpr); | ||
| 843 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 844 | p.depths[def_index] += 1; | ||
| 845 | defer p.depths[def_index] -= 1; | ||
| 846 | return blk_0: { | ||
| 847 | const pos_0 = p.i; | ||
| 848 | if ((try p.parseBlockLabel() or true) and try p.parseBlock()) break :blk_0 true; | ||
| 849 | p.i = pos_0; | ||
| 850 | break :blk_0 false; | ||
| 851 | }; | ||
| 852 | } | ||
| 853 | pub fn parseVarAssignStatement(p: *Parser) Error!bool { | ||
| 854 | const def_index = @intFromEnum(Def.defVarAssignStatement); | ||
| 855 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 856 | p.depths[def_index] += 1; | ||
| 857 | defer p.depths[def_index] -= 1; | ||
| 858 | return blk_0: { | ||
| 859 | const pos_0 = p.i; | ||
| 860 | if (blk_2: { | ||
| 861 | const pos_2 = p.i; | ||
| 862 | if (try p.parseVarDeclProto()) break :blk_2 true; | ||
| 863 | p.i = pos_2; | ||
| 864 | if (try p.parseExpr()) break :blk_2 true; | ||
| 865 | p.i = pos_2; | ||
| 866 | break :blk_2 false; | ||
| 867 | } and blk_1: { | ||
| 868 | var i_1: usize = 0; | ||
| 869 | while (blk_3: { | ||
| 870 | const pos_3 = p.i; | ||
| 871 | if (try p.parseCOMMA() and blk_5: { | ||
| 872 | const pos_5 = p.i; | ||
| 873 | if (try p.parseVarDeclProto()) break :blk_5 true; | ||
| 874 | p.i = pos_5; | ||
| 875 | if (try p.parseExpr()) break :blk_5 true; | ||
| 876 | p.i = pos_5; | ||
| 877 | break :blk_5 false; | ||
| 878 | }) break :blk_3 true; | ||
| 879 | p.i = pos_3; | ||
| 880 | break :blk_3 false; | ||
| 881 | }) { | ||
| 882 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 883 | i_1 += 1; | ||
| 884 | } | ||
| 885 | break :blk_1 true; | ||
| 886 | } and try p.parseEQUAL() and try p.parseExpr() and try p.parseSEMICOLON()) break :blk_0 true; | ||
| 887 | p.i = pos_0; | ||
| 888 | break :blk_0 false; | ||
| 889 | }; | ||
| 890 | } | ||
| 891 | pub fn parseAssignExpr(p: *Parser) Error!bool { | ||
| 892 | const def_index = @intFromEnum(Def.defAssignExpr); | ||
| 893 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 894 | p.depths[def_index] += 1; | ||
| 895 | defer p.depths[def_index] -= 1; | ||
| 896 | return blk_0: { | ||
| 897 | const pos_0 = p.i; | ||
| 898 | if (try p.parseExpr() and blk_2: { | ||
| 899 | const pos_2 = p.i; | ||
| 900 | if (try p.parseAssignOp() and try p.parseExpr()) break :blk_2 true; | ||
| 901 | p.i = pos_2; | ||
| 902 | if (blk_3: { | ||
| 903 | var match_3 = false; | ||
| 904 | var i_3: usize = 0; | ||
| 905 | while (blk_5: { | ||
| 906 | const pos_5 = p.i; | ||
| 907 | if (try p.parseCOMMA() and try p.parseExpr()) break :blk_5 true; | ||
| 908 | p.i = pos_5; | ||
| 909 | break :blk_5 false; | ||
| 910 | }) { | ||
| 911 | match_3 = true; | ||
| 912 | if (i_3 > max_depth) return error.MaxDepth; | ||
| 913 | i_3 += 1; | ||
| 914 | } | ||
| 915 | break :blk_3 match_3; | ||
| 916 | } and try p.parseEQUAL() and try p.parseExpr()) break :blk_2 true; | ||
| 917 | p.i = pos_2; | ||
| 918 | if (blk_3: { | ||
| 919 | const pos_3 = p.i; | ||
| 920 | const match_3 = try p.parseAssignOp(); | ||
| 921 | p.i = pos_3; | ||
| 922 | break :blk_3 !match_3; | ||
| 923 | } and blk_3: { | ||
| 924 | const pos_3 = p.i; | ||
| 925 | const match_3 = try p.parseCOMMA(); | ||
| 926 | p.i = pos_3; | ||
| 927 | break :blk_3 !match_3; | ||
| 928 | }) break :blk_2 true; | ||
| 929 | p.i = pos_2; | ||
| 930 | break :blk_2 false; | ||
| 931 | }) break :blk_0 true; | ||
| 932 | p.i = pos_0; | ||
| 933 | break :blk_0 false; | ||
| 934 | }; | ||
| 935 | } | ||
| 936 | pub fn parseSingleAssignExpr(p: *Parser) Error!bool { | ||
| 937 | const def_index = @intFromEnum(Def.defSingleAssignExpr); | ||
| 938 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 939 | p.depths[def_index] += 1; | ||
| 940 | defer p.depths[def_index] -= 1; | ||
| 941 | return blk_0: { | ||
| 942 | const pos_0 = p.i; | ||
| 943 | if (try p.parseExpr() and blk_2: { | ||
| 944 | const pos_2 = p.i; | ||
| 945 | if (try p.parseAssignOp() and try p.parseExpr()) break :blk_2 true; | ||
| 946 | p.i = pos_2; | ||
| 947 | if (blk_3: { | ||
| 948 | const pos_3 = p.i; | ||
| 949 | const match_3 = try p.parseAssignOp(); | ||
| 950 | p.i = pos_3; | ||
| 951 | break :blk_3 !match_3; | ||
| 952 | }) break :blk_2 true; | ||
| 953 | p.i = pos_2; | ||
| 954 | break :blk_2 false; | ||
| 955 | }) break :blk_0 true; | ||
| 956 | p.i = pos_0; | ||
| 957 | break :blk_0 false; | ||
| 958 | }; | ||
| 959 | } | ||
| 960 | pub fn parseExpr(p: *Parser) Error!bool { | ||
| 961 | const def_index = @intFromEnum(Def.defExpr); | ||
| 962 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 963 | p.depths[def_index] += 1; | ||
| 964 | defer p.depths[def_index] -= 1; | ||
| 965 | return blk_0: { | ||
| 966 | const pos_0 = p.i; | ||
| 967 | if (try p.parseBoolOrExpr()) break :blk_0 true; | ||
| 968 | p.i = pos_0; | ||
| 969 | break :blk_0 false; | ||
| 970 | }; | ||
| 971 | } | ||
| 972 | pub fn parseBoolOrExpr(p: *Parser) Error!bool { | ||
| 973 | const def_index = @intFromEnum(Def.defBoolOrExpr); | ||
| 974 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 975 | p.depths[def_index] += 1; | ||
| 976 | defer p.depths[def_index] -= 1; | ||
| 977 | return blk_0: { | ||
| 978 | const pos_0 = p.i; | ||
| 979 | if (try p.parseBoolAndExpr() and blk_1: { | ||
| 980 | var i_1: usize = 0; | ||
| 981 | while (blk_3: { | ||
| 982 | const pos_3 = p.i; | ||
| 983 | if (try p.parseOrOp() and try p.parseBoolAndExpr()) break :blk_3 true; | ||
| 984 | p.i = pos_3; | ||
| 985 | break :blk_3 false; | ||
| 986 | }) { | ||
| 987 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 988 | i_1 += 1; | ||
| 989 | } | ||
| 990 | break :blk_1 true; | ||
| 991 | } and blk_1: { | ||
| 992 | const pos_1 = p.i; | ||
| 993 | const match_1 = try p.parseOrOp(); | ||
| 994 | p.i = pos_1; | ||
| 995 | break :blk_1 !match_1; | ||
| 996 | }) break :blk_0 true; | ||
| 997 | p.i = pos_0; | ||
| 998 | break :blk_0 false; | ||
| 999 | }; | ||
| 1000 | } | ||
| 1001 | pub fn parseBoolAndExpr(p: *Parser) Error!bool { | ||
| 1002 | const def_index = @intFromEnum(Def.defBoolAndExpr); | ||
| 1003 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1004 | p.depths[def_index] += 1; | ||
| 1005 | defer p.depths[def_index] -= 1; | ||
| 1006 | return blk_0: { | ||
| 1007 | const pos_0 = p.i; | ||
| 1008 | if (try p.parseCompareExpr() and blk_1: { | ||
| 1009 | var i_1: usize = 0; | ||
| 1010 | while (blk_3: { | ||
| 1011 | const pos_3 = p.i; | ||
| 1012 | if (try p.parseAndOp() and try p.parseCompareExpr()) break :blk_3 true; | ||
| 1013 | p.i = pos_3; | ||
| 1014 | break :blk_3 false; | ||
| 1015 | }) { | ||
| 1016 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1017 | i_1 += 1; | ||
| 1018 | } | ||
| 1019 | break :blk_1 true; | ||
| 1020 | } and blk_1: { | ||
| 1021 | const pos_1 = p.i; | ||
| 1022 | const match_1 = try p.parseAndOp(); | ||
| 1023 | p.i = pos_1; | ||
| 1024 | break :blk_1 !match_1; | ||
| 1025 | }) break :blk_0 true; | ||
| 1026 | p.i = pos_0; | ||
| 1027 | break :blk_0 false; | ||
| 1028 | }; | ||
| 1029 | } | ||
| 1030 | pub fn parseCompareExpr(p: *Parser) Error!bool { | ||
| 1031 | const def_index = @intFromEnum(Def.defCompareExpr); | ||
| 1032 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1033 | p.depths[def_index] += 1; | ||
| 1034 | defer p.depths[def_index] -= 1; | ||
| 1035 | return blk_0: { | ||
| 1036 | const pos_0 = p.i; | ||
| 1037 | if (try p.parseBitwiseExpr() and (blk_3: { | ||
| 1038 | const pos_3 = p.i; | ||
| 1039 | if (try p.parseCompareOp() and try p.parseBitwiseExpr()) break :blk_3 true; | ||
| 1040 | p.i = pos_3; | ||
| 1041 | break :blk_3 false; | ||
| 1042 | } or true) and blk_1: { | ||
| 1043 | const pos_1 = p.i; | ||
| 1044 | const match_1 = try p.parseCompareOp(); | ||
| 1045 | p.i = pos_1; | ||
| 1046 | break :blk_1 !match_1; | ||
| 1047 | }) break :blk_0 true; | ||
| 1048 | p.i = pos_0; | ||
| 1049 | break :blk_0 false; | ||
| 1050 | }; | ||
| 1051 | } | ||
| 1052 | pub fn parseBitwiseExpr(p: *Parser) Error!bool { | ||
| 1053 | const def_index = @intFromEnum(Def.defBitwiseExpr); | ||
| 1054 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1055 | p.depths[def_index] += 1; | ||
| 1056 | defer p.depths[def_index] -= 1; | ||
| 1057 | return blk_0: { | ||
| 1058 | const pos_0 = p.i; | ||
| 1059 | if (try p.parseBitShiftExpr() and blk_1: { | ||
| 1060 | var i_1: usize = 0; | ||
| 1061 | while (blk_3: { | ||
| 1062 | const pos_3 = p.i; | ||
| 1063 | if (try p.parseBitwiseOp() and try p.parseBitShiftExpr()) break :blk_3 true; | ||
| 1064 | p.i = pos_3; | ||
| 1065 | break :blk_3 false; | ||
| 1066 | }) { | ||
| 1067 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1068 | i_1 += 1; | ||
| 1069 | } | ||
| 1070 | break :blk_1 true; | ||
| 1071 | } and blk_1: { | ||
| 1072 | const pos_1 = p.i; | ||
| 1073 | const match_1 = try p.parseBitwiseOp(); | ||
| 1074 | p.i = pos_1; | ||
| 1075 | break :blk_1 !match_1; | ||
| 1076 | }) break :blk_0 true; | ||
| 1077 | p.i = pos_0; | ||
| 1078 | break :blk_0 false; | ||
| 1079 | }; | ||
| 1080 | } | ||
| 1081 | pub fn parseBitShiftExpr(p: *Parser) Error!bool { | ||
| 1082 | const def_index = @intFromEnum(Def.defBitShiftExpr); | ||
| 1083 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1084 | p.depths[def_index] += 1; | ||
| 1085 | defer p.depths[def_index] -= 1; | ||
| 1086 | return blk_0: { | ||
| 1087 | const pos_0 = p.i; | ||
| 1088 | if (try p.parseAdditionExpr() and blk_1: { | ||
| 1089 | var i_1: usize = 0; | ||
| 1090 | while (blk_3: { | ||
| 1091 | const pos_3 = p.i; | ||
| 1092 | if (try p.parseBitShiftOp() and try p.parseAdditionExpr()) break :blk_3 true; | ||
| 1093 | p.i = pos_3; | ||
| 1094 | break :blk_3 false; | ||
| 1095 | }) { | ||
| 1096 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1097 | i_1 += 1; | ||
| 1098 | } | ||
| 1099 | break :blk_1 true; | ||
| 1100 | } and blk_1: { | ||
| 1101 | const pos_1 = p.i; | ||
| 1102 | const match_1 = try p.parseBitShiftOp(); | ||
| 1103 | p.i = pos_1; | ||
| 1104 | break :blk_1 !match_1; | ||
| 1105 | }) break :blk_0 true; | ||
| 1106 | p.i = pos_0; | ||
| 1107 | break :blk_0 false; | ||
| 1108 | }; | ||
| 1109 | } | ||
| 1110 | pub fn parseAdditionExpr(p: *Parser) Error!bool { | ||
| 1111 | const def_index = @intFromEnum(Def.defAdditionExpr); | ||
| 1112 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1113 | p.depths[def_index] += 1; | ||
| 1114 | defer p.depths[def_index] -= 1; | ||
| 1115 | return blk_0: { | ||
| 1116 | const pos_0 = p.i; | ||
| 1117 | if (try p.parseMultiplyExpr() and blk_1: { | ||
| 1118 | var i_1: usize = 0; | ||
| 1119 | while (blk_3: { | ||
| 1120 | const pos_3 = p.i; | ||
| 1121 | if (try p.parseAdditionOp() and try p.parseMultiplyExpr()) break :blk_3 true; | ||
| 1122 | p.i = pos_3; | ||
| 1123 | break :blk_3 false; | ||
| 1124 | }) { | ||
| 1125 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1126 | i_1 += 1; | ||
| 1127 | } | ||
| 1128 | break :blk_1 true; | ||
| 1129 | } and blk_1: { | ||
| 1130 | const pos_1 = p.i; | ||
| 1131 | const match_1 = try p.parseAdditionOp(); | ||
| 1132 | p.i = pos_1; | ||
| 1133 | break :blk_1 !match_1; | ||
| 1134 | }) break :blk_0 true; | ||
| 1135 | p.i = pos_0; | ||
| 1136 | break :blk_0 false; | ||
| 1137 | }; | ||
| 1138 | } | ||
| 1139 | pub fn parseMultiplyExpr(p: *Parser) Error!bool { | ||
| 1140 | const def_index = @intFromEnum(Def.defMultiplyExpr); | ||
| 1141 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1142 | p.depths[def_index] += 1; | ||
| 1143 | defer p.depths[def_index] -= 1; | ||
| 1144 | return blk_0: { | ||
| 1145 | const pos_0 = p.i; | ||
| 1146 | if (try p.parsePrefixExpr() and blk_1: { | ||
| 1147 | var i_1: usize = 0; | ||
| 1148 | while (blk_3: { | ||
| 1149 | const pos_3 = p.i; | ||
| 1150 | if (try p.parseMultiplyOp() and try p.parsePrefixExpr()) break :blk_3 true; | ||
| 1151 | p.i = pos_3; | ||
| 1152 | break :blk_3 false; | ||
| 1153 | }) { | ||
| 1154 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1155 | i_1 += 1; | ||
| 1156 | } | ||
| 1157 | break :blk_1 true; | ||
| 1158 | } and blk_1: { | ||
| 1159 | const pos_1 = p.i; | ||
| 1160 | const match_1 = try p.parseMultiplyOp(); | ||
| 1161 | p.i = pos_1; | ||
| 1162 | break :blk_1 !match_1; | ||
| 1163 | }) break :blk_0 true; | ||
| 1164 | p.i = pos_0; | ||
| 1165 | break :blk_0 false; | ||
| 1166 | }; | ||
| 1167 | } | ||
| 1168 | pub fn parsePrefixExpr(p: *Parser) Error!bool { | ||
| 1169 | const def_index = @intFromEnum(Def.defPrefixExpr); | ||
| 1170 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1171 | p.depths[def_index] += 1; | ||
| 1172 | defer p.depths[def_index] -= 1; | ||
| 1173 | return blk_0: { | ||
| 1174 | const pos_0 = p.i; | ||
| 1175 | if (blk_1: { | ||
| 1176 | var i_1: usize = 0; | ||
| 1177 | while (try p.parsePrefixOp()) { | ||
| 1178 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1179 | i_1 += 1; | ||
| 1180 | } | ||
| 1181 | break :blk_1 true; | ||
| 1182 | } and blk_1: { | ||
| 1183 | const pos_1 = p.i; | ||
| 1184 | const match_1 = try p.parsePrefixOp(); | ||
| 1185 | p.i = pos_1; | ||
| 1186 | break :blk_1 !match_1; | ||
| 1187 | } and try p.parsePrimaryExpr()) break :blk_0 true; | ||
| 1188 | p.i = pos_0; | ||
| 1189 | break :blk_0 false; | ||
| 1190 | }; | ||
| 1191 | } | ||
| 1192 | pub fn parsePrimaryExpr(p: *Parser) Error!bool { | ||
| 1193 | const def_index = @intFromEnum(Def.defPrimaryExpr); | ||
| 1194 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1195 | p.depths[def_index] += 1; | ||
| 1196 | defer p.depths[def_index] -= 1; | ||
| 1197 | return blk_0: { | ||
| 1198 | const pos_0 = p.i; | ||
| 1199 | if (try p.parseAsmExpr()) break :blk_0 true; | ||
| 1200 | p.i = pos_0; | ||
| 1201 | if (try p.parseIfExpr()) break :blk_0 true; | ||
| 1202 | p.i = pos_0; | ||
| 1203 | if (try p.parseKEYWORD_break() and (try p.parseBreakLabel() or true) and blk_2: { | ||
| 1204 | const pos_2 = p.i; | ||
| 1205 | if (try p.parseExpr()) break :blk_2 true; | ||
| 1206 | p.i = pos_2; | ||
| 1207 | if (blk_3: { | ||
| 1208 | const pos_3 = p.i; | ||
| 1209 | const match_3 = try p.parseExprPrefix(); | ||
| 1210 | p.i = pos_3; | ||
| 1211 | break :blk_3 !match_3; | ||
| 1212 | }) break :blk_2 true; | ||
| 1213 | p.i = pos_2; | ||
| 1214 | break :blk_2 false; | ||
| 1215 | }) break :blk_0 true; | ||
| 1216 | p.i = pos_0; | ||
| 1217 | if (try p.parseKEYWORD_comptime() and try p.parseExpr()) break :blk_0 true; | ||
| 1218 | p.i = pos_0; | ||
| 1219 | if (try p.parseKEYWORD_nosuspend() and try p.parseExpr()) break :blk_0 true; | ||
| 1220 | p.i = pos_0; | ||
| 1221 | if (try p.parseKEYWORD_continue() and (try p.parseBreakLabel() or true) and blk_2: { | ||
| 1222 | const pos_2 = p.i; | ||
| 1223 | if (try p.parseExpr()) break :blk_2 true; | ||
| 1224 | p.i = pos_2; | ||
| 1225 | if (blk_3: { | ||
| 1226 | const pos_3 = p.i; | ||
| 1227 | const match_3 = try p.parseExprPrefix(); | ||
| 1228 | p.i = pos_3; | ||
| 1229 | break :blk_3 !match_3; | ||
| 1230 | }) break :blk_2 true; | ||
| 1231 | p.i = pos_2; | ||
| 1232 | break :blk_2 false; | ||
| 1233 | }) break :blk_0 true; | ||
| 1234 | p.i = pos_0; | ||
| 1235 | if (try p.parseKEYWORD_resume() and try p.parseExpr()) break :blk_0 true; | ||
| 1236 | p.i = pos_0; | ||
| 1237 | if (try p.parseKEYWORD_return() and blk_2: { | ||
| 1238 | const pos_2 = p.i; | ||
| 1239 | if (try p.parseExpr()) break :blk_2 true; | ||
| 1240 | p.i = pos_2; | ||
| 1241 | if (blk_3: { | ||
| 1242 | const pos_3 = p.i; | ||
| 1243 | const match_3 = try p.parseExprPrefix(); | ||
| 1244 | p.i = pos_3; | ||
| 1245 | break :blk_3 !match_3; | ||
| 1246 | }) break :blk_2 true; | ||
| 1247 | p.i = pos_2; | ||
| 1248 | break :blk_2 false; | ||
| 1249 | }) break :blk_0 true; | ||
| 1250 | p.i = pos_0; | ||
| 1251 | if ((try p.parseBlockLabel() or true) and try p.parseLoopExpr()) break :blk_0 true; | ||
| 1252 | p.i = pos_0; | ||
| 1253 | if (try p.parseBlock()) break :blk_0 true; | ||
| 1254 | p.i = pos_0; | ||
| 1255 | if (try p.parseCurlySuffixExpr()) break :blk_0 true; | ||
| 1256 | p.i = pos_0; | ||
| 1257 | break :blk_0 false; | ||
| 1258 | }; | ||
| 1259 | } | ||
| 1260 | pub fn parseIfExpr(p: *Parser) Error!bool { | ||
| 1261 | const def_index = @intFromEnum(Def.defIfExpr); | ||
| 1262 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1263 | p.depths[def_index] += 1; | ||
| 1264 | defer p.depths[def_index] -= 1; | ||
| 1265 | return blk_0: { | ||
| 1266 | const pos_0 = p.i; | ||
| 1267 | if (try p.parseIfPrefix() and try p.parseExpr() and blk_2: { | ||
| 1268 | const pos_2 = p.i; | ||
| 1269 | if (try p.parseKEYWORD_else() and (try p.parsePayload() or true) and try p.parseExpr()) break :blk_2 true; | ||
| 1270 | p.i = pos_2; | ||
| 1271 | if (blk_3: { | ||
| 1272 | const pos_3 = p.i; | ||
| 1273 | const match_3 = try p.parseKEYWORD_else(); | ||
| 1274 | p.i = pos_3; | ||
| 1275 | break :blk_3 !match_3; | ||
| 1276 | }) break :blk_2 true; | ||
| 1277 | p.i = pos_2; | ||
| 1278 | break :blk_2 false; | ||
| 1279 | }) break :blk_0 true; | ||
| 1280 | p.i = pos_0; | ||
| 1281 | break :blk_0 false; | ||
| 1282 | }; | ||
| 1283 | } | ||
| 1284 | pub fn parseBlock(p: *Parser) Error!bool { | ||
| 1285 | const def_index = @intFromEnum(Def.defBlock); | ||
| 1286 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1287 | p.depths[def_index] += 1; | ||
| 1288 | defer p.depths[def_index] -= 1; | ||
| 1289 | return blk_0: { | ||
| 1290 | const pos_0 = p.i; | ||
| 1291 | if (try p.parseLBRACE() and blk_1: { | ||
| 1292 | var i_1: usize = 0; | ||
| 1293 | while (try p.parseBlockStatement()) { | ||
| 1294 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1295 | i_1 += 1; | ||
| 1296 | } | ||
| 1297 | break :blk_1 true; | ||
| 1298 | } and try p.parseRBRACE()) break :blk_0 true; | ||
| 1299 | p.i = pos_0; | ||
| 1300 | break :blk_0 false; | ||
| 1301 | }; | ||
| 1302 | } | ||
| 1303 | pub fn parseLoopExpr(p: *Parser) Error!bool { | ||
| 1304 | const def_index = @intFromEnum(Def.defLoopExpr); | ||
| 1305 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1306 | p.depths[def_index] += 1; | ||
| 1307 | defer p.depths[def_index] -= 1; | ||
| 1308 | return blk_0: { | ||
| 1309 | const pos_0 = p.i; | ||
| 1310 | if ((try p.parseKEYWORD_inline() or true) and blk_2: { | ||
| 1311 | const pos_2 = p.i; | ||
| 1312 | if (try p.parseForExpr()) break :blk_2 true; | ||
| 1313 | p.i = pos_2; | ||
| 1314 | if (try p.parseWhileExpr()) break :blk_2 true; | ||
| 1315 | p.i = pos_2; | ||
| 1316 | break :blk_2 false; | ||
| 1317 | }) break :blk_0 true; | ||
| 1318 | p.i = pos_0; | ||
| 1319 | break :blk_0 false; | ||
| 1320 | }; | ||
| 1321 | } | ||
| 1322 | pub fn parseForExpr(p: *Parser) Error!bool { | ||
| 1323 | const def_index = @intFromEnum(Def.defForExpr); | ||
| 1324 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1325 | p.depths[def_index] += 1; | ||
| 1326 | defer p.depths[def_index] -= 1; | ||
| 1327 | return blk_0: { | ||
| 1328 | const pos_0 = p.i; | ||
| 1329 | if (try p.parseForPrefix() and try p.parseExpr() and blk_2: { | ||
| 1330 | const pos_2 = p.i; | ||
| 1331 | if (try p.parseKEYWORD_else() and try p.parseExpr()) break :blk_2 true; | ||
| 1332 | p.i = pos_2; | ||
| 1333 | if (blk_3: { | ||
| 1334 | const pos_3 = p.i; | ||
| 1335 | const match_3 = try p.parseKEYWORD_else(); | ||
| 1336 | p.i = pos_3; | ||
| 1337 | break :blk_3 !match_3; | ||
| 1338 | }) break :blk_2 true; | ||
| 1339 | p.i = pos_2; | ||
| 1340 | break :blk_2 false; | ||
| 1341 | }) break :blk_0 true; | ||
| 1342 | p.i = pos_0; | ||
| 1343 | break :blk_0 false; | ||
| 1344 | }; | ||
| 1345 | } | ||
| 1346 | pub fn parseWhileExpr(p: *Parser) Error!bool { | ||
| 1347 | const def_index = @intFromEnum(Def.defWhileExpr); | ||
| 1348 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1349 | p.depths[def_index] += 1; | ||
| 1350 | defer p.depths[def_index] -= 1; | ||
| 1351 | return blk_0: { | ||
| 1352 | const pos_0 = p.i; | ||
| 1353 | if (try p.parseWhilePrefix() and try p.parseExpr() and (blk_3: { | ||
| 1354 | const pos_3 = p.i; | ||
| 1355 | if (try p.parseKEYWORD_else() and (try p.parsePayload() or true) and try p.parseExpr()) break :blk_3 true; | ||
| 1356 | p.i = pos_3; | ||
| 1357 | break :blk_3 false; | ||
| 1358 | } or true)) break :blk_0 true; | ||
| 1359 | p.i = pos_0; | ||
| 1360 | break :blk_0 false; | ||
| 1361 | }; | ||
| 1362 | } | ||
| 1363 | pub fn parseCurlySuffixExpr(p: *Parser) Error!bool { | ||
| 1364 | const def_index = @intFromEnum(Def.defCurlySuffixExpr); | ||
| 1365 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1366 | p.depths[def_index] += 1; | ||
| 1367 | defer p.depths[def_index] -= 1; | ||
| 1368 | return blk_0: { | ||
| 1369 | const pos_0 = p.i; | ||
| 1370 | if (try p.parseTypeExpr() and blk_2: { | ||
| 1371 | const pos_2 = p.i; | ||
| 1372 | if (try p.parseInitList()) break :blk_2 true; | ||
| 1373 | p.i = pos_2; | ||
| 1374 | if (blk_3: { | ||
| 1375 | const pos_3 = p.i; | ||
| 1376 | const match_3 = try p.parseLBRACE(); | ||
| 1377 | p.i = pos_3; | ||
| 1378 | break :blk_3 !match_3; | ||
| 1379 | }) break :blk_2 true; | ||
| 1380 | p.i = pos_2; | ||
| 1381 | break :blk_2 false; | ||
| 1382 | }) break :blk_0 true; | ||
| 1383 | p.i = pos_0; | ||
| 1384 | break :blk_0 false; | ||
| 1385 | }; | ||
| 1386 | } | ||
| 1387 | pub fn parseInitList(p: *Parser) Error!bool { | ||
| 1388 | const def_index = @intFromEnum(Def.defInitList); | ||
| 1389 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1390 | p.depths[def_index] += 1; | ||
| 1391 | defer p.depths[def_index] -= 1; | ||
| 1392 | return blk_0: { | ||
| 1393 | const pos_0 = p.i; | ||
| 1394 | if (try p.parseLBRACE() and try p.parseFieldInit() and blk_1: { | ||
| 1395 | var i_1: usize = 0; | ||
| 1396 | while (blk_3: { | ||
| 1397 | const pos_3 = p.i; | ||
| 1398 | if (try p.parseCOMMA() and try p.parseFieldInit()) break :blk_3 true; | ||
| 1399 | p.i = pos_3; | ||
| 1400 | break :blk_3 false; | ||
| 1401 | }) { | ||
| 1402 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1403 | i_1 += 1; | ||
| 1404 | } | ||
| 1405 | break :blk_1 true; | ||
| 1406 | } and (try p.parseCOMMA() or true) and try p.parseRBRACE()) break :blk_0 true; | ||
| 1407 | p.i = pos_0; | ||
| 1408 | if (try p.parseLBRACE() and try p.parseExpr() and blk_1: { | ||
| 1409 | var i_1: usize = 0; | ||
| 1410 | while (blk_3: { | ||
| 1411 | const pos_3 = p.i; | ||
| 1412 | if (try p.parseCOMMA() and try p.parseExpr()) break :blk_3 true; | ||
| 1413 | p.i = pos_3; | ||
| 1414 | break :blk_3 false; | ||
| 1415 | }) { | ||
| 1416 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1417 | i_1 += 1; | ||
| 1418 | } | ||
| 1419 | break :blk_1 true; | ||
| 1420 | } and (try p.parseCOMMA() or true) and try p.parseRBRACE()) break :blk_0 true; | ||
| 1421 | p.i = pos_0; | ||
| 1422 | if (try p.parseLBRACE() and try p.parseRBRACE()) break :blk_0 true; | ||
| 1423 | p.i = pos_0; | ||
| 1424 | break :blk_0 false; | ||
| 1425 | }; | ||
| 1426 | } | ||
| 1427 | pub fn parseTypeExpr(p: *Parser) Error!bool { | ||
| 1428 | const def_index = @intFromEnum(Def.defTypeExpr); | ||
| 1429 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1430 | p.depths[def_index] += 1; | ||
| 1431 | defer p.depths[def_index] -= 1; | ||
| 1432 | return blk_0: { | ||
| 1433 | const pos_0 = p.i; | ||
| 1434 | if (blk_1: { | ||
| 1435 | var i_1: usize = 0; | ||
| 1436 | while (try p.parsePrefixTypeOp()) { | ||
| 1437 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1438 | i_1 += 1; | ||
| 1439 | } | ||
| 1440 | break :blk_1 true; | ||
| 1441 | } and blk_1: { | ||
| 1442 | const pos_1 = p.i; | ||
| 1443 | const match_1 = try p.parsePrefixTypeOpPrefix(); | ||
| 1444 | p.i = pos_1; | ||
| 1445 | break :blk_1 !match_1; | ||
| 1446 | } and try p.parseErrorUnionExpr()) break :blk_0 true; | ||
| 1447 | p.i = pos_0; | ||
| 1448 | break :blk_0 false; | ||
| 1449 | }; | ||
| 1450 | } | ||
| 1451 | pub fn parseErrorUnionExpr(p: *Parser) Error!bool { | ||
| 1452 | const def_index = @intFromEnum(Def.defErrorUnionExpr); | ||
| 1453 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1454 | p.depths[def_index] += 1; | ||
| 1455 | defer p.depths[def_index] -= 1; | ||
| 1456 | return blk_0: { | ||
| 1457 | const pos_0 = p.i; | ||
| 1458 | if (try p.parseSuffixExpr() and blk_2: { | ||
| 1459 | const pos_2 = p.i; | ||
| 1460 | if (try p.parseEXCLAMATIONMARK() and try p.parseTypeExpr()) break :blk_2 true; | ||
| 1461 | p.i = pos_2; | ||
| 1462 | if (blk_3: { | ||
| 1463 | const pos_3 = p.i; | ||
| 1464 | const match_3 = try p.parseEXCLAMATIONMARK(); | ||
| 1465 | p.i = pos_3; | ||
| 1466 | break :blk_3 !match_3; | ||
| 1467 | }) break :blk_2 true; | ||
| 1468 | p.i = pos_2; | ||
| 1469 | break :blk_2 false; | ||
| 1470 | }) break :blk_0 true; | ||
| 1471 | p.i = pos_0; | ||
| 1472 | break :blk_0 false; | ||
| 1473 | }; | ||
| 1474 | } | ||
| 1475 | pub fn parseSuffixExpr(p: *Parser) Error!bool { | ||
| 1476 | const def_index = @intFromEnum(Def.defSuffixExpr); | ||
| 1477 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1478 | p.depths[def_index] += 1; | ||
| 1479 | defer p.depths[def_index] -= 1; | ||
| 1480 | return blk_0: { | ||
| 1481 | const pos_0 = p.i; | ||
| 1482 | if (try p.parsePrimaryTypeExpr() and blk_1: { | ||
| 1483 | var i_1: usize = 0; | ||
| 1484 | while (try p.parseSuffixOp()) { | ||
| 1485 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1486 | i_1 += 1; | ||
| 1487 | } | ||
| 1488 | break :blk_1 true; | ||
| 1489 | } and blk_1: { | ||
| 1490 | const pos_1 = p.i; | ||
| 1491 | const match_1 = try p.parseSuffixOpPrefix(); | ||
| 1492 | p.i = pos_1; | ||
| 1493 | break :blk_1 !match_1; | ||
| 1494 | }) break :blk_0 true; | ||
| 1495 | p.i = pos_0; | ||
| 1496 | break :blk_0 false; | ||
| 1497 | }; | ||
| 1498 | } | ||
| 1499 | pub fn parsePrimaryTypeExpr(p: *Parser) Error!bool { | ||
| 1500 | const def_index = @intFromEnum(Def.defPrimaryTypeExpr); | ||
| 1501 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1502 | p.depths[def_index] += 1; | ||
| 1503 | defer p.depths[def_index] -= 1; | ||
| 1504 | return blk_0: { | ||
| 1505 | const pos_0 = p.i; | ||
| 1506 | if (try p.parseBUILTINIDENTIFIER() and try p.parseFnCallArguments()) break :blk_0 true; | ||
| 1507 | p.i = pos_0; | ||
| 1508 | if (try p.parseCHAR_LITERAL()) break :blk_0 true; | ||
| 1509 | p.i = pos_0; | ||
| 1510 | if (try p.parseContainerType()) break :blk_0 true; | ||
| 1511 | p.i = pos_0; | ||
| 1512 | if (try p.parseDOT() and try p.parseIDENTIFIER()) break :blk_0 true; | ||
| 1513 | p.i = pos_0; | ||
| 1514 | if (try p.parseDOT() and try p.parseInitList()) break :blk_0 true; | ||
| 1515 | p.i = pos_0; | ||
| 1516 | if (try p.parseErrorSetDecl()) break :blk_0 true; | ||
| 1517 | p.i = pos_0; | ||
| 1518 | if (try p.parseFnProto()) break :blk_0 true; | ||
| 1519 | p.i = pos_0; | ||
| 1520 | if (try p.parseGroupedExpr()) break :blk_0 true; | ||
| 1521 | p.i = pos_0; | ||
| 1522 | if (try p.parseLabeledTypeExpr()) break :blk_0 true; | ||
| 1523 | p.i = pos_0; | ||
| 1524 | if (try p.parseIDENTIFIER()) break :blk_0 true; | ||
| 1525 | p.i = pos_0; | ||
| 1526 | if (try p.parseIfTypeExpr()) break :blk_0 true; | ||
| 1527 | p.i = pos_0; | ||
| 1528 | if (try p.parseKEYWORD_comptime() and try p.parseTypeExpr()) break :blk_0 true; | ||
| 1529 | p.i = pos_0; | ||
| 1530 | if (try p.parseKEYWORD_error() and try p.parseDOT() and try p.parseIDENTIFIER()) break :blk_0 true; | ||
| 1531 | p.i = pos_0; | ||
| 1532 | if (try p.parseKEYWORD_anyframe()) break :blk_0 true; | ||
| 1533 | p.i = pos_0; | ||
| 1534 | if (try p.parseKEYWORD_unreachable()) break :blk_0 true; | ||
| 1535 | p.i = pos_0; | ||
| 1536 | if (try p.parseNUMBERLITERAL()) break :blk_0 true; | ||
| 1537 | p.i = pos_0; | ||
| 1538 | if (try p.parseSTRINGLITERAL()) break :blk_0 true; | ||
| 1539 | p.i = pos_0; | ||
| 1540 | break :blk_0 false; | ||
| 1541 | }; | ||
| 1542 | } | ||
| 1543 | pub fn parseContainerType(p: *Parser) Error!bool { | ||
| 1544 | const def_index = @intFromEnum(Def.defContainerType); | ||
| 1545 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1546 | p.depths[def_index] += 1; | ||
| 1547 | defer p.depths[def_index] -= 1; | ||
| 1548 | return blk_0: { | ||
| 1549 | const pos_0 = p.i; | ||
| 1550 | if ((blk_3: { | ||
| 1551 | const pos_3 = p.i; | ||
| 1552 | if (try p.parseKEYWORD_extern()) break :blk_3 true; | ||
| 1553 | p.i = pos_3; | ||
| 1554 | if (try p.parseKEYWORD_packed()) break :blk_3 true; | ||
| 1555 | p.i = pos_3; | ||
| 1556 | break :blk_3 false; | ||
| 1557 | } or true) and try p.parseContainerTypeAuto()) break :blk_0 true; | ||
| 1558 | p.i = pos_0; | ||
| 1559 | break :blk_0 false; | ||
| 1560 | }; | ||
| 1561 | } | ||
| 1562 | pub fn parseErrorSetDecl(p: *Parser) Error!bool { | ||
| 1563 | const def_index = @intFromEnum(Def.defErrorSetDecl); | ||
| 1564 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1565 | p.depths[def_index] += 1; | ||
| 1566 | defer p.depths[def_index] -= 1; | ||
| 1567 | return blk_0: { | ||
| 1568 | const pos_0 = p.i; | ||
| 1569 | if (try p.parseKEYWORD_error() and try p.parseLBRACE() and try p.parseIdentifierList() and try p.parseRBRACE()) break :blk_0 true; | ||
| 1570 | p.i = pos_0; | ||
| 1571 | break :blk_0 false; | ||
| 1572 | }; | ||
| 1573 | } | ||
| 1574 | pub fn parseGroupedExpr(p: *Parser) Error!bool { | ||
| 1575 | const def_index = @intFromEnum(Def.defGroupedExpr); | ||
| 1576 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1577 | p.depths[def_index] += 1; | ||
| 1578 | defer p.depths[def_index] -= 1; | ||
| 1579 | return blk_0: { | ||
| 1580 | const pos_0 = p.i; | ||
| 1581 | if (try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_0 true; | ||
| 1582 | p.i = pos_0; | ||
| 1583 | break :blk_0 false; | ||
| 1584 | }; | ||
| 1585 | } | ||
| 1586 | pub fn parseIfTypeExpr(p: *Parser) Error!bool { | ||
| 1587 | const def_index = @intFromEnum(Def.defIfTypeExpr); | ||
| 1588 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1589 | p.depths[def_index] += 1; | ||
| 1590 | defer p.depths[def_index] -= 1; | ||
| 1591 | return blk_0: { | ||
| 1592 | const pos_0 = p.i; | ||
| 1593 | if (try p.parseIfPrefix() and try p.parseTypeExpr() and blk_2: { | ||
| 1594 | const pos_2 = p.i; | ||
| 1595 | if (try p.parseKEYWORD_else() and (try p.parsePayload() or true) and try p.parseTypeExpr()) break :blk_2 true; | ||
| 1596 | p.i = pos_2; | ||
| 1597 | if (blk_3: { | ||
| 1598 | const pos_3 = p.i; | ||
| 1599 | const match_3 = try p.parseKEYWORD_else(); | ||
| 1600 | p.i = pos_3; | ||
| 1601 | break :blk_3 !match_3; | ||
| 1602 | }) break :blk_2 true; | ||
| 1603 | p.i = pos_2; | ||
| 1604 | break :blk_2 false; | ||
| 1605 | }) break :blk_0 true; | ||
| 1606 | p.i = pos_0; | ||
| 1607 | break :blk_0 false; | ||
| 1608 | }; | ||
| 1609 | } | ||
| 1610 | pub fn parseLabeledTypeExpr(p: *Parser) Error!bool { | ||
| 1611 | const def_index = @intFromEnum(Def.defLabeledTypeExpr); | ||
| 1612 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1613 | p.depths[def_index] += 1; | ||
| 1614 | defer p.depths[def_index] -= 1; | ||
| 1615 | return blk_0: { | ||
| 1616 | const pos_0 = p.i; | ||
| 1617 | if (try p.parseBlockLabel() and try p.parseBlock()) break :blk_0 true; | ||
| 1618 | p.i = pos_0; | ||
| 1619 | if ((try p.parseBlockLabel() or true) and try p.parseLoopTypeExpr()) break :blk_0 true; | ||
| 1620 | p.i = pos_0; | ||
| 1621 | if ((try p.parseBlockLabel() or true) and try p.parseSwitchExpr()) break :blk_0 true; | ||
| 1622 | p.i = pos_0; | ||
| 1623 | break :blk_0 false; | ||
| 1624 | }; | ||
| 1625 | } | ||
| 1626 | pub fn parseLoopTypeExpr(p: *Parser) Error!bool { | ||
| 1627 | const def_index = @intFromEnum(Def.defLoopTypeExpr); | ||
| 1628 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1629 | p.depths[def_index] += 1; | ||
| 1630 | defer p.depths[def_index] -= 1; | ||
| 1631 | return blk_0: { | ||
| 1632 | const pos_0 = p.i; | ||
| 1633 | if ((try p.parseKEYWORD_inline() or true) and blk_2: { | ||
| 1634 | const pos_2 = p.i; | ||
| 1635 | if (try p.parseForTypeExpr()) break :blk_2 true; | ||
| 1636 | p.i = pos_2; | ||
| 1637 | if (try p.parseWhileTypeExpr()) break :blk_2 true; | ||
| 1638 | p.i = pos_2; | ||
| 1639 | break :blk_2 false; | ||
| 1640 | }) break :blk_0 true; | ||
| 1641 | p.i = pos_0; | ||
| 1642 | break :blk_0 false; | ||
| 1643 | }; | ||
| 1644 | } | ||
| 1645 | pub fn parseForTypeExpr(p: *Parser) Error!bool { | ||
| 1646 | const def_index = @intFromEnum(Def.defForTypeExpr); | ||
| 1647 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1648 | p.depths[def_index] += 1; | ||
| 1649 | defer p.depths[def_index] -= 1; | ||
| 1650 | return blk_0: { | ||
| 1651 | const pos_0 = p.i; | ||
| 1652 | if (try p.parseForPrefix() and try p.parseTypeExpr() and blk_2: { | ||
| 1653 | const pos_2 = p.i; | ||
| 1654 | if (try p.parseKEYWORD_else() and try p.parseTypeExpr()) break :blk_2 true; | ||
| 1655 | p.i = pos_2; | ||
| 1656 | if (blk_3: { | ||
| 1657 | const pos_3 = p.i; | ||
| 1658 | const match_3 = try p.parseKEYWORD_else(); | ||
| 1659 | p.i = pos_3; | ||
| 1660 | break :blk_3 !match_3; | ||
| 1661 | }) break :blk_2 true; | ||
| 1662 | p.i = pos_2; | ||
| 1663 | break :blk_2 false; | ||
| 1664 | }) break :blk_0 true; | ||
| 1665 | p.i = pos_0; | ||
| 1666 | break :blk_0 false; | ||
| 1667 | }; | ||
| 1668 | } | ||
| 1669 | pub fn parseWhileTypeExpr(p: *Parser) Error!bool { | ||
| 1670 | const def_index = @intFromEnum(Def.defWhileTypeExpr); | ||
| 1671 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1672 | p.depths[def_index] += 1; | ||
| 1673 | defer p.depths[def_index] -= 1; | ||
| 1674 | return blk_0: { | ||
| 1675 | const pos_0 = p.i; | ||
| 1676 | if (try p.parseWhilePrefix() and try p.parseTypeExpr() and blk_2: { | ||
| 1677 | const pos_2 = p.i; | ||
| 1678 | if (try p.parseKEYWORD_else() and (try p.parsePayload() or true) and try p.parseTypeExpr()) break :blk_2 true; | ||
| 1679 | p.i = pos_2; | ||
| 1680 | if (blk_3: { | ||
| 1681 | const pos_3 = p.i; | ||
| 1682 | const match_3 = try p.parseKEYWORD_else(); | ||
| 1683 | p.i = pos_3; | ||
| 1684 | break :blk_3 !match_3; | ||
| 1685 | }) break :blk_2 true; | ||
| 1686 | p.i = pos_2; | ||
| 1687 | break :blk_2 false; | ||
| 1688 | }) break :blk_0 true; | ||
| 1689 | p.i = pos_0; | ||
| 1690 | break :blk_0 false; | ||
| 1691 | }; | ||
| 1692 | } | ||
| 1693 | pub fn parseSwitchExpr(p: *Parser) Error!bool { | ||
| 1694 | const def_index = @intFromEnum(Def.defSwitchExpr); | ||
| 1695 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1696 | p.depths[def_index] += 1; | ||
| 1697 | defer p.depths[def_index] -= 1; | ||
| 1698 | return blk_0: { | ||
| 1699 | const pos_0 = p.i; | ||
| 1700 | if (try p.parseKEYWORD_switch() and try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN() and try p.parseLBRACE() and try p.parseSwitchProngList() and try p.parseRBRACE()) break :blk_0 true; | ||
| 1701 | p.i = pos_0; | ||
| 1702 | break :blk_0 false; | ||
| 1703 | }; | ||
| 1704 | } | ||
| 1705 | pub fn parseAsmExpr(p: *Parser) Error!bool { | ||
| 1706 | const def_index = @intFromEnum(Def.defAsmExpr); | ||
| 1707 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1708 | p.depths[def_index] += 1; | ||
| 1709 | defer p.depths[def_index] -= 1; | ||
| 1710 | return blk_0: { | ||
| 1711 | const pos_0 = p.i; | ||
| 1712 | if (try p.parseKEYWORD_asm() and (try p.parseKEYWORD_volatile() or true) and try p.parseLPAREN() and try p.parseExpr() and (try p.parseAsmOutput() or true) and try p.parseRPAREN()) break :blk_0 true; | ||
| 1713 | p.i = pos_0; | ||
| 1714 | break :blk_0 false; | ||
| 1715 | }; | ||
| 1716 | } | ||
| 1717 | pub fn parseAsmOutput(p: *Parser) Error!bool { | ||
| 1718 | const def_index = @intFromEnum(Def.defAsmOutput); | ||
| 1719 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1720 | p.depths[def_index] += 1; | ||
| 1721 | defer p.depths[def_index] -= 1; | ||
| 1722 | return blk_0: { | ||
| 1723 | const pos_0 = p.i; | ||
| 1724 | if (try p.parseCOLON() and try p.parseAsmOutputList() and (try p.parseAsmInput() or true)) break :blk_0 true; | ||
| 1725 | p.i = pos_0; | ||
| 1726 | break :blk_0 false; | ||
| 1727 | }; | ||
| 1728 | } | ||
| 1729 | pub fn parseAsmOutputItem(p: *Parser) Error!bool { | ||
| 1730 | const def_index = @intFromEnum(Def.defAsmOutputItem); | ||
| 1731 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1732 | p.depths[def_index] += 1; | ||
| 1733 | defer p.depths[def_index] -= 1; | ||
| 1734 | return blk_0: { | ||
| 1735 | const pos_0 = p.i; | ||
| 1736 | if (try p.parseLBRACKET() and try p.parseIDENTIFIER() and try p.parseRBRACKET() and try p.parseSTRINGLITERALSINGLE() and try p.parseLPAREN() and blk_2: { | ||
| 1737 | const pos_2 = p.i; | ||
| 1738 | if (try p.parseMINUSRARROW() and try p.parseTypeExpr()) break :blk_2 true; | ||
| 1739 | p.i = pos_2; | ||
| 1740 | if (try p.parseIDENTIFIER()) break :blk_2 true; | ||
| 1741 | p.i = pos_2; | ||
| 1742 | break :blk_2 false; | ||
| 1743 | } and try p.parseRPAREN()) break :blk_0 true; | ||
| 1744 | p.i = pos_0; | ||
| 1745 | break :blk_0 false; | ||
| 1746 | }; | ||
| 1747 | } | ||
| 1748 | pub fn parseAsmInput(p: *Parser) Error!bool { | ||
| 1749 | const def_index = @intFromEnum(Def.defAsmInput); | ||
| 1750 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1751 | p.depths[def_index] += 1; | ||
| 1752 | defer p.depths[def_index] -= 1; | ||
| 1753 | return blk_0: { | ||
| 1754 | const pos_0 = p.i; | ||
| 1755 | if (try p.parseCOLON() and try p.parseAsmInputList() and (try p.parseAsmClobbers() or true)) break :blk_0 true; | ||
| 1756 | p.i = pos_0; | ||
| 1757 | break :blk_0 false; | ||
| 1758 | }; | ||
| 1759 | } | ||
| 1760 | pub fn parseAsmInputItem(p: *Parser) Error!bool { | ||
| 1761 | const def_index = @intFromEnum(Def.defAsmInputItem); | ||
| 1762 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1763 | p.depths[def_index] += 1; | ||
| 1764 | defer p.depths[def_index] -= 1; | ||
| 1765 | return blk_0: { | ||
| 1766 | const pos_0 = p.i; | ||
| 1767 | if (try p.parseLBRACKET() and try p.parseIDENTIFIER() and try p.parseRBRACKET() and try p.parseSTRINGLITERALSINGLE() and try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_0 true; | ||
| 1768 | p.i = pos_0; | ||
| 1769 | break :blk_0 false; | ||
| 1770 | }; | ||
| 1771 | } | ||
| 1772 | pub fn parseAsmClobbers(p: *Parser) Error!bool { | ||
| 1773 | const def_index = @intFromEnum(Def.defAsmClobbers); | ||
| 1774 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1775 | p.depths[def_index] += 1; | ||
| 1776 | defer p.depths[def_index] -= 1; | ||
| 1777 | return blk_0: { | ||
| 1778 | const pos_0 = p.i; | ||
| 1779 | if (try p.parseCOLON() and try p.parseExpr()) break :blk_0 true; | ||
| 1780 | p.i = pos_0; | ||
| 1781 | break :blk_0 false; | ||
| 1782 | }; | ||
| 1783 | } | ||
| 1784 | pub fn parseBreakLabel(p: *Parser) Error!bool { | ||
| 1785 | const def_index = @intFromEnum(Def.defBreakLabel); | ||
| 1786 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1787 | p.depths[def_index] += 1; | ||
| 1788 | defer p.depths[def_index] -= 1; | ||
| 1789 | return blk_0: { | ||
| 1790 | const pos_0 = p.i; | ||
| 1791 | if (try p.parseCOLON() and try p.parseIDENTIFIER()) break :blk_0 true; | ||
| 1792 | p.i = pos_0; | ||
| 1793 | break :blk_0 false; | ||
| 1794 | }; | ||
| 1795 | } | ||
| 1796 | pub fn parseBlockLabel(p: *Parser) Error!bool { | ||
| 1797 | const def_index = @intFromEnum(Def.defBlockLabel); | ||
| 1798 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1799 | p.depths[def_index] += 1; | ||
| 1800 | defer p.depths[def_index] -= 1; | ||
| 1801 | return blk_0: { | ||
| 1802 | const pos_0 = p.i; | ||
| 1803 | if (try p.parseIDENTIFIER() and try p.parseCOLON()) break :blk_0 true; | ||
| 1804 | p.i = pos_0; | ||
| 1805 | break :blk_0 false; | ||
| 1806 | }; | ||
| 1807 | } | ||
| 1808 | pub fn parseFieldInit(p: *Parser) Error!bool { | ||
| 1809 | const def_index = @intFromEnum(Def.defFieldInit); | ||
| 1810 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1811 | p.depths[def_index] += 1; | ||
| 1812 | defer p.depths[def_index] -= 1; | ||
| 1813 | return blk_0: { | ||
| 1814 | const pos_0 = p.i; | ||
| 1815 | if (try p.parseDOT() and try p.parseIDENTIFIER() and try p.parseEQUAL() and try p.parseExpr()) break :blk_0 true; | ||
| 1816 | p.i = pos_0; | ||
| 1817 | break :blk_0 false; | ||
| 1818 | }; | ||
| 1819 | } | ||
| 1820 | pub fn parseWhileContinueExpr(p: *Parser) Error!bool { | ||
| 1821 | const def_index = @intFromEnum(Def.defWhileContinueExpr); | ||
| 1822 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1823 | p.depths[def_index] += 1; | ||
| 1824 | defer p.depths[def_index] -= 1; | ||
| 1825 | return blk_0: { | ||
| 1826 | const pos_0 = p.i; | ||
| 1827 | if (try p.parseCOLON() and try p.parseLPAREN() and try p.parseAssignExpr() and try p.parseRPAREN()) break :blk_0 true; | ||
| 1828 | p.i = pos_0; | ||
| 1829 | break :blk_0 false; | ||
| 1830 | }; | ||
| 1831 | } | ||
| 1832 | pub fn parseLinkSection(p: *Parser) Error!bool { | ||
| 1833 | const def_index = @intFromEnum(Def.defLinkSection); | ||
| 1834 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1835 | p.depths[def_index] += 1; | ||
| 1836 | defer p.depths[def_index] -= 1; | ||
| 1837 | return blk_0: { | ||
| 1838 | const pos_0 = p.i; | ||
| 1839 | if (try p.parseKEYWORD_linksection() and try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_0 true; | ||
| 1840 | p.i = pos_0; | ||
| 1841 | break :blk_0 false; | ||
| 1842 | }; | ||
| 1843 | } | ||
| 1844 | pub fn parseAddrSpace(p: *Parser) Error!bool { | ||
| 1845 | const def_index = @intFromEnum(Def.defAddrSpace); | ||
| 1846 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1847 | p.depths[def_index] += 1; | ||
| 1848 | defer p.depths[def_index] -= 1; | ||
| 1849 | return blk_0: { | ||
| 1850 | const pos_0 = p.i; | ||
| 1851 | if (try p.parseKEYWORD_addrspace() and try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_0 true; | ||
| 1852 | p.i = pos_0; | ||
| 1853 | break :blk_0 false; | ||
| 1854 | }; | ||
| 1855 | } | ||
| 1856 | pub fn parseCallConv(p: *Parser) Error!bool { | ||
| 1857 | const def_index = @intFromEnum(Def.defCallConv); | ||
| 1858 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1859 | p.depths[def_index] += 1; | ||
| 1860 | defer p.depths[def_index] -= 1; | ||
| 1861 | return blk_0: { | ||
| 1862 | const pos_0 = p.i; | ||
| 1863 | if (try p.parseKEYWORD_callconv() and try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_0 true; | ||
| 1864 | p.i = pos_0; | ||
| 1865 | break :blk_0 false; | ||
| 1866 | }; | ||
| 1867 | } | ||
| 1868 | pub fn parseParamDecl(p: *Parser) Error!bool { | ||
| 1869 | const def_index = @intFromEnum(Def.defParamDecl); | ||
| 1870 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1871 | p.depths[def_index] += 1; | ||
| 1872 | defer p.depths[def_index] -= 1; | ||
| 1873 | return blk_0: { | ||
| 1874 | const pos_0 = p.i; | ||
| 1875 | if ((try p.parsedoc_comment() or true) and blk_2: { | ||
| 1876 | const pos_2 = p.i; | ||
| 1877 | if (try p.parseKEYWORD_noalias()) break :blk_2 true; | ||
| 1878 | p.i = pos_2; | ||
| 1879 | if ((try p.parseKEYWORD_comptime() or true)) break :blk_2 true; | ||
| 1880 | p.i = pos_2; | ||
| 1881 | break :blk_2 false; | ||
| 1882 | } and (blk_3: { | ||
| 1883 | const pos_3 = p.i; | ||
| 1884 | if (try p.parseIDENTIFIER() and try p.parseCOLON()) break :blk_3 true; | ||
| 1885 | p.i = pos_3; | ||
| 1886 | break :blk_3 false; | ||
| 1887 | } or true) and try p.parseParamType()) break :blk_0 true; | ||
| 1888 | p.i = pos_0; | ||
| 1889 | break :blk_0 false; | ||
| 1890 | }; | ||
| 1891 | } | ||
| 1892 | pub fn parseParamType(p: *Parser) Error!bool { | ||
| 1893 | const def_index = @intFromEnum(Def.defParamType); | ||
| 1894 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1895 | p.depths[def_index] += 1; | ||
| 1896 | defer p.depths[def_index] -= 1; | ||
| 1897 | return blk_0: { | ||
| 1898 | const pos_0 = p.i; | ||
| 1899 | if (try p.parseKEYWORD_anytype()) break :blk_0 true; | ||
| 1900 | p.i = pos_0; | ||
| 1901 | if (try p.parseTypeExpr()) break :blk_0 true; | ||
| 1902 | p.i = pos_0; | ||
| 1903 | break :blk_0 false; | ||
| 1904 | }; | ||
| 1905 | } | ||
| 1906 | pub fn parseIfPrefix(p: *Parser) Error!bool { | ||
| 1907 | const def_index = @intFromEnum(Def.defIfPrefix); | ||
| 1908 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1909 | p.depths[def_index] += 1; | ||
| 1910 | defer p.depths[def_index] -= 1; | ||
| 1911 | return blk_0: { | ||
| 1912 | const pos_0 = p.i; | ||
| 1913 | if (try p.parseKEYWORD_if() and try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN() and (try p.parsePtrPayload() or true)) break :blk_0 true; | ||
| 1914 | p.i = pos_0; | ||
| 1915 | break :blk_0 false; | ||
| 1916 | }; | ||
| 1917 | } | ||
| 1918 | pub fn parseWhilePrefix(p: *Parser) Error!bool { | ||
| 1919 | const def_index = @intFromEnum(Def.defWhilePrefix); | ||
| 1920 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1921 | p.depths[def_index] += 1; | ||
| 1922 | defer p.depths[def_index] -= 1; | ||
| 1923 | return blk_0: { | ||
| 1924 | const pos_0 = p.i; | ||
| 1925 | if (try p.parseKEYWORD_while() and try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN() and (try p.parsePtrPayload() or true) and (try p.parseWhileContinueExpr() or true)) break :blk_0 true; | ||
| 1926 | p.i = pos_0; | ||
| 1927 | break :blk_0 false; | ||
| 1928 | }; | ||
| 1929 | } | ||
| 1930 | pub fn parseForPrefix(p: *Parser) Error!bool { | ||
| 1931 | const def_index = @intFromEnum(Def.defForPrefix); | ||
| 1932 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1933 | p.depths[def_index] += 1; | ||
| 1934 | defer p.depths[def_index] -= 1; | ||
| 1935 | return blk_0: { | ||
| 1936 | const pos_0 = p.i; | ||
| 1937 | if (try p.parseKEYWORD_for() and try p.parseLPAREN() and try p.parseForArgumentsList() and try p.parseRPAREN() and try p.parsePtrListPayload()) break :blk_0 true; | ||
| 1938 | p.i = pos_0; | ||
| 1939 | break :blk_0 false; | ||
| 1940 | }; | ||
| 1941 | } | ||
| 1942 | pub fn parsePayload(p: *Parser) Error!bool { | ||
| 1943 | const def_index = @intFromEnum(Def.defPayload); | ||
| 1944 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1945 | p.depths[def_index] += 1; | ||
| 1946 | defer p.depths[def_index] -= 1; | ||
| 1947 | return blk_0: { | ||
| 1948 | const pos_0 = p.i; | ||
| 1949 | if (try p.parsePIPE() and try p.parseIDENTIFIER() and try p.parsePIPE()) break :blk_0 true; | ||
| 1950 | p.i = pos_0; | ||
| 1951 | break :blk_0 false; | ||
| 1952 | }; | ||
| 1953 | } | ||
| 1954 | pub fn parsePtrPayload(p: *Parser) Error!bool { | ||
| 1955 | const def_index = @intFromEnum(Def.defPtrPayload); | ||
| 1956 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1957 | p.depths[def_index] += 1; | ||
| 1958 | defer p.depths[def_index] -= 1; | ||
| 1959 | return blk_0: { | ||
| 1960 | const pos_0 = p.i; | ||
| 1961 | if (try p.parsePIPE() and (try p.parseASTERISK() or true) and try p.parseIDENTIFIER() and try p.parsePIPE()) break :blk_0 true; | ||
| 1962 | p.i = pos_0; | ||
| 1963 | break :blk_0 false; | ||
| 1964 | }; | ||
| 1965 | } | ||
| 1966 | pub fn parsePtrIndexPayload(p: *Parser) Error!bool { | ||
| 1967 | const def_index = @intFromEnum(Def.defPtrIndexPayload); | ||
| 1968 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1969 | p.depths[def_index] += 1; | ||
| 1970 | defer p.depths[def_index] -= 1; | ||
| 1971 | return blk_0: { | ||
| 1972 | const pos_0 = p.i; | ||
| 1973 | if (try p.parsePIPE() and (try p.parseASTERISK() or true) and try p.parseIDENTIFIER() and (blk_3: { | ||
| 1974 | const pos_3 = p.i; | ||
| 1975 | if (try p.parseCOMMA() and try p.parseIDENTIFIER()) break :blk_3 true; | ||
| 1976 | p.i = pos_3; | ||
| 1977 | break :blk_3 false; | ||
| 1978 | } or true) and try p.parsePIPE()) break :blk_0 true; | ||
| 1979 | p.i = pos_0; | ||
| 1980 | break :blk_0 false; | ||
| 1981 | }; | ||
| 1982 | } | ||
| 1983 | pub fn parsePtrListPayload(p: *Parser) Error!bool { | ||
| 1984 | const def_index = @intFromEnum(Def.defPtrListPayload); | ||
| 1985 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 1986 | p.depths[def_index] += 1; | ||
| 1987 | defer p.depths[def_index] -= 1; | ||
| 1988 | return blk_0: { | ||
| 1989 | const pos_0 = p.i; | ||
| 1990 | if (try p.parsePIPE() and (try p.parseASTERISK() or true) and try p.parseIDENTIFIER() and blk_1: { | ||
| 1991 | var i_1: usize = 0; | ||
| 1992 | while (blk_3: { | ||
| 1993 | const pos_3 = p.i; | ||
| 1994 | if (try p.parseCOMMA() and (try p.parseASTERISK() or true) and try p.parseIDENTIFIER()) break :blk_3 true; | ||
| 1995 | p.i = pos_3; | ||
| 1996 | break :blk_3 false; | ||
| 1997 | }) { | ||
| 1998 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 1999 | i_1 += 1; | ||
| 2000 | } | ||
| 2001 | break :blk_1 true; | ||
| 2002 | } and (try p.parseCOMMA() or true) and try p.parsePIPE()) break :blk_0 true; | ||
| 2003 | p.i = pos_0; | ||
| 2004 | break :blk_0 false; | ||
| 2005 | }; | ||
| 2006 | } | ||
| 2007 | pub fn parseSwitchProng(p: *Parser) Error!bool { | ||
| 2008 | const def_index = @intFromEnum(Def.defSwitchProng); | ||
| 2009 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2010 | p.depths[def_index] += 1; | ||
| 2011 | defer p.depths[def_index] -= 1; | ||
| 2012 | return blk_0: { | ||
| 2013 | const pos_0 = p.i; | ||
| 2014 | if ((try p.parseKEYWORD_inline() or true) and try p.parseSwitchCase() and try p.parseEQUALRARROW() and (try p.parsePtrIndexPayload() or true) and try p.parseSingleAssignExpr()) break :blk_0 true; | ||
| 2015 | p.i = pos_0; | ||
| 2016 | break :blk_0 false; | ||
| 2017 | }; | ||
| 2018 | } | ||
| 2019 | pub fn parseSwitchCase(p: *Parser) Error!bool { | ||
| 2020 | const def_index = @intFromEnum(Def.defSwitchCase); | ||
| 2021 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2022 | p.depths[def_index] += 1; | ||
| 2023 | defer p.depths[def_index] -= 1; | ||
| 2024 | return blk_0: { | ||
| 2025 | const pos_0 = p.i; | ||
| 2026 | if (try p.parseSwitchItem() and blk_1: { | ||
| 2027 | var i_1: usize = 0; | ||
| 2028 | while (blk_3: { | ||
| 2029 | const pos_3 = p.i; | ||
| 2030 | if (try p.parseCOMMA() and try p.parseSwitchItem()) break :blk_3 true; | ||
| 2031 | p.i = pos_3; | ||
| 2032 | break :blk_3 false; | ||
| 2033 | }) { | ||
| 2034 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2035 | i_1 += 1; | ||
| 2036 | } | ||
| 2037 | break :blk_1 true; | ||
| 2038 | } and (try p.parseCOMMA() or true)) break :blk_0 true; | ||
| 2039 | p.i = pos_0; | ||
| 2040 | if (try p.parseKEYWORD_else()) break :blk_0 true; | ||
| 2041 | p.i = pos_0; | ||
| 2042 | break :blk_0 false; | ||
| 2043 | }; | ||
| 2044 | } | ||
| 2045 | pub fn parseSwitchItem(p: *Parser) Error!bool { | ||
| 2046 | const def_index = @intFromEnum(Def.defSwitchItem); | ||
| 2047 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2048 | p.depths[def_index] += 1; | ||
| 2049 | defer p.depths[def_index] -= 1; | ||
| 2050 | return blk_0: { | ||
| 2051 | const pos_0 = p.i; | ||
| 2052 | if (try p.parseExpr() and (blk_3: { | ||
| 2053 | const pos_3 = p.i; | ||
| 2054 | if (try p.parseDOT3() and try p.parseExpr()) break :blk_3 true; | ||
| 2055 | p.i = pos_3; | ||
| 2056 | break :blk_3 false; | ||
| 2057 | } or true)) break :blk_0 true; | ||
| 2058 | p.i = pos_0; | ||
| 2059 | break :blk_0 false; | ||
| 2060 | }; | ||
| 2061 | } | ||
| 2062 | pub fn parseForArgumentsList(p: *Parser) Error!bool { | ||
| 2063 | const def_index = @intFromEnum(Def.defForArgumentsList); | ||
| 2064 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2065 | p.depths[def_index] += 1; | ||
| 2066 | defer p.depths[def_index] -= 1; | ||
| 2067 | return blk_0: { | ||
| 2068 | const pos_0 = p.i; | ||
| 2069 | if (try p.parseForItem() and blk_1: { | ||
| 2070 | var i_1: usize = 0; | ||
| 2071 | while (blk_3: { | ||
| 2072 | const pos_3 = p.i; | ||
| 2073 | if (try p.parseCOMMA() and try p.parseForItem()) break :blk_3 true; | ||
| 2074 | p.i = pos_3; | ||
| 2075 | break :blk_3 false; | ||
| 2076 | }) { | ||
| 2077 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2078 | i_1 += 1; | ||
| 2079 | } | ||
| 2080 | break :blk_1 true; | ||
| 2081 | } and (try p.parseCOMMA() or true)) break :blk_0 true; | ||
| 2082 | p.i = pos_0; | ||
| 2083 | break :blk_0 false; | ||
| 2084 | }; | ||
| 2085 | } | ||
| 2086 | pub fn parseForItem(p: *Parser) Error!bool { | ||
| 2087 | const def_index = @intFromEnum(Def.defForItem); | ||
| 2088 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2089 | p.depths[def_index] += 1; | ||
| 2090 | defer p.depths[def_index] -= 1; | ||
| 2091 | return blk_0: { | ||
| 2092 | const pos_0 = p.i; | ||
| 2093 | if (try p.parseExpr() and blk_2: { | ||
| 2094 | const pos_2 = p.i; | ||
| 2095 | if (try p.parseDOT2() and blk_4: { | ||
| 2096 | const pos_4 = p.i; | ||
| 2097 | if (try p.parseExpr()) break :blk_4 true; | ||
| 2098 | p.i = pos_4; | ||
| 2099 | if (blk_5: { | ||
| 2100 | const pos_5 = p.i; | ||
| 2101 | const match_5 = try p.parseExprPrefix(); | ||
| 2102 | p.i = pos_5; | ||
| 2103 | break :blk_5 !match_5; | ||
| 2104 | }) break :blk_4 true; | ||
| 2105 | p.i = pos_4; | ||
| 2106 | break :blk_4 false; | ||
| 2107 | }) break :blk_2 true; | ||
| 2108 | p.i = pos_2; | ||
| 2109 | if (blk_3: { | ||
| 2110 | const pos_3 = p.i; | ||
| 2111 | const match_3 = try p.parseDOT2(); | ||
| 2112 | p.i = pos_3; | ||
| 2113 | break :blk_3 !match_3; | ||
| 2114 | }) break :blk_2 true; | ||
| 2115 | p.i = pos_2; | ||
| 2116 | break :blk_2 false; | ||
| 2117 | }) break :blk_0 true; | ||
| 2118 | p.i = pos_0; | ||
| 2119 | break :blk_0 false; | ||
| 2120 | }; | ||
| 2121 | } | ||
| 2122 | pub fn parseAssignOp(p: *Parser) Error!bool { | ||
| 2123 | const def_index = @intFromEnum(Def.defAssignOp); | ||
| 2124 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2125 | p.depths[def_index] += 1; | ||
| 2126 | defer p.depths[def_index] -= 1; | ||
| 2127 | return blk_0: { | ||
| 2128 | const pos_0 = p.i; | ||
| 2129 | if (try p.parseASTERISKEQUAL()) break :blk_0 true; | ||
| 2130 | p.i = pos_0; | ||
| 2131 | if (try p.parseASTERISKPIPEEQUAL()) break :blk_0 true; | ||
| 2132 | p.i = pos_0; | ||
| 2133 | if (try p.parseSLASHEQUAL()) break :blk_0 true; | ||
| 2134 | p.i = pos_0; | ||
| 2135 | if (try p.parsePERCENTEQUAL()) break :blk_0 true; | ||
| 2136 | p.i = pos_0; | ||
| 2137 | if (try p.parsePLUSEQUAL()) break :blk_0 true; | ||
| 2138 | p.i = pos_0; | ||
| 2139 | if (try p.parsePLUSPIPEEQUAL()) break :blk_0 true; | ||
| 2140 | p.i = pos_0; | ||
| 2141 | if (try p.parseMINUSEQUAL()) break :blk_0 true; | ||
| 2142 | p.i = pos_0; | ||
| 2143 | if (try p.parseMINUSPIPEEQUAL()) break :blk_0 true; | ||
| 2144 | p.i = pos_0; | ||
| 2145 | if (try p.parseLARROW2EQUAL()) break :blk_0 true; | ||
| 2146 | p.i = pos_0; | ||
| 2147 | if (try p.parseLARROW2PIPEEQUAL()) break :blk_0 true; | ||
| 2148 | p.i = pos_0; | ||
| 2149 | if (try p.parseRARROW2EQUAL()) break :blk_0 true; | ||
| 2150 | p.i = pos_0; | ||
| 2151 | if (try p.parseAMPERSANDEQUAL()) break :blk_0 true; | ||
| 2152 | p.i = pos_0; | ||
| 2153 | if (try p.parseCARETEQUAL()) break :blk_0 true; | ||
| 2154 | p.i = pos_0; | ||
| 2155 | if (try p.parsePIPEEQUAL()) break :blk_0 true; | ||
| 2156 | p.i = pos_0; | ||
| 2157 | if (try p.parseASTERISKPERCENTEQUAL()) break :blk_0 true; | ||
| 2158 | p.i = pos_0; | ||
| 2159 | if (try p.parsePLUSPERCENTEQUAL()) break :blk_0 true; | ||
| 2160 | p.i = pos_0; | ||
| 2161 | if (try p.parseMINUSPERCENTEQUAL()) break :blk_0 true; | ||
| 2162 | p.i = pos_0; | ||
| 2163 | if (try p.parseEQUAL()) break :blk_0 true; | ||
| 2164 | p.i = pos_0; | ||
| 2165 | break :blk_0 false; | ||
| 2166 | }; | ||
| 2167 | } | ||
| 2168 | pub fn parseOrOp(p: *Parser) Error!bool { | ||
| 2169 | const def_index = @intFromEnum(Def.defOrOp); | ||
| 2170 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2171 | p.depths[def_index] += 1; | ||
| 2172 | defer p.depths[def_index] -= 1; | ||
| 2173 | return blk_0: { | ||
| 2174 | const pos_0 = p.i; | ||
| 2175 | if (try p.parsepre_op_white() and try p.parseKEYWORD_or() and try p.parsepost_op_white()) break :blk_0 true; | ||
| 2176 | p.i = pos_0; | ||
| 2177 | if (blk_1: { | ||
| 2178 | const pos_1 = p.i; | ||
| 2179 | const match_1 = try p.parsepre_op_white(); | ||
| 2180 | p.i = pos_1; | ||
| 2181 | break :blk_1 !match_1; | ||
| 2182 | } and try p.parseKEYWORD_or() and blk_1: { | ||
| 2183 | const pos_1 = p.i; | ||
| 2184 | const match_1 = try p.parsepost_op_white(); | ||
| 2185 | p.i = pos_1; | ||
| 2186 | break :blk_1 !match_1; | ||
| 2187 | }) break :blk_0 true; | ||
| 2188 | p.i = pos_0; | ||
| 2189 | break :blk_0 false; | ||
| 2190 | }; | ||
| 2191 | } | ||
| 2192 | pub fn parseAndOp(p: *Parser) Error!bool { | ||
| 2193 | const def_index = @intFromEnum(Def.defAndOp); | ||
| 2194 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2195 | p.depths[def_index] += 1; | ||
| 2196 | defer p.depths[def_index] -= 1; | ||
| 2197 | return blk_0: { | ||
| 2198 | const pos_0 = p.i; | ||
| 2199 | if (try p.parsepre_op_white() and try p.parseKEYWORD_and() and try p.parsepost_op_white()) break :blk_0 true; | ||
| 2200 | p.i = pos_0; | ||
| 2201 | if (blk_1: { | ||
| 2202 | const pos_1 = p.i; | ||
| 2203 | const match_1 = try p.parsepre_op_white(); | ||
| 2204 | p.i = pos_1; | ||
| 2205 | break :blk_1 !match_1; | ||
| 2206 | } and try p.parseKEYWORD_and() and blk_1: { | ||
| 2207 | const pos_1 = p.i; | ||
| 2208 | const match_1 = try p.parsepost_op_white(); | ||
| 2209 | p.i = pos_1; | ||
| 2210 | break :blk_1 !match_1; | ||
| 2211 | }) break :blk_0 true; | ||
| 2212 | p.i = pos_0; | ||
| 2213 | break :blk_0 false; | ||
| 2214 | }; | ||
| 2215 | } | ||
| 2216 | pub fn parseCompareOp(p: *Parser) Error!bool { | ||
| 2217 | const def_index = @intFromEnum(Def.defCompareOp); | ||
| 2218 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2219 | p.depths[def_index] += 1; | ||
| 2220 | defer p.depths[def_index] -= 1; | ||
| 2221 | return blk_0: { | ||
| 2222 | const pos_0 = p.i; | ||
| 2223 | if (try p.parsepre_op_white() and try p.parseCompareOpTok() and try p.parsepost_op_white()) break :blk_0 true; | ||
| 2224 | p.i = pos_0; | ||
| 2225 | if (blk_1: { | ||
| 2226 | const pos_1 = p.i; | ||
| 2227 | const match_1 = try p.parsepre_op_white(); | ||
| 2228 | p.i = pos_1; | ||
| 2229 | break :blk_1 !match_1; | ||
| 2230 | } and try p.parseCompareOpTok() and blk_1: { | ||
| 2231 | const pos_1 = p.i; | ||
| 2232 | const match_1 = try p.parsepost_op_white(); | ||
| 2233 | p.i = pos_1; | ||
| 2234 | break :blk_1 !match_1; | ||
| 2235 | }) break :blk_0 true; | ||
| 2236 | p.i = pos_0; | ||
| 2237 | break :blk_0 false; | ||
| 2238 | }; | ||
| 2239 | } | ||
| 2240 | pub fn parseCompareOpTok(p: *Parser) Error!bool { | ||
| 2241 | const def_index = @intFromEnum(Def.defCompareOpTok); | ||
| 2242 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2243 | p.depths[def_index] += 1; | ||
| 2244 | defer p.depths[def_index] -= 1; | ||
| 2245 | return blk_0: { | ||
| 2246 | const pos_0 = p.i; | ||
| 2247 | if (try p.parseEQUALEQUAL()) break :blk_0 true; | ||
| 2248 | p.i = pos_0; | ||
| 2249 | if (try p.parseEXCLAMATIONMARKEQUAL()) break :blk_0 true; | ||
| 2250 | p.i = pos_0; | ||
| 2251 | if (try p.parseLARROW()) break :blk_0 true; | ||
| 2252 | p.i = pos_0; | ||
| 2253 | if (try p.parseRARROW()) break :blk_0 true; | ||
| 2254 | p.i = pos_0; | ||
| 2255 | if (try p.parseLARROWEQUAL()) break :blk_0 true; | ||
| 2256 | p.i = pos_0; | ||
| 2257 | if (try p.parseRARROWEQUAL()) break :blk_0 true; | ||
| 2258 | p.i = pos_0; | ||
| 2259 | break :blk_0 false; | ||
| 2260 | }; | ||
| 2261 | } | ||
| 2262 | pub fn parseBitwiseOp(p: *Parser) Error!bool { | ||
| 2263 | const def_index = @intFromEnum(Def.defBitwiseOp); | ||
| 2264 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2265 | p.depths[def_index] += 1; | ||
| 2266 | defer p.depths[def_index] -= 1; | ||
| 2267 | return blk_0: { | ||
| 2268 | const pos_0 = p.i; | ||
| 2269 | if (try p.parsepre_op_white() and try p.parseBitwiseOpTok() and try p.parsepost_op_white()) break :blk_0 true; | ||
| 2270 | p.i = pos_0; | ||
| 2271 | if (blk_1: { | ||
| 2272 | const pos_1 = p.i; | ||
| 2273 | const match_1 = try p.parsepre_op_white(); | ||
| 2274 | p.i = pos_1; | ||
| 2275 | break :blk_1 !match_1; | ||
| 2276 | } and try p.parseBitwiseOpTok() and blk_1: { | ||
| 2277 | const pos_1 = p.i; | ||
| 2278 | const match_1 = try p.parsepost_op_white(); | ||
| 2279 | p.i = pos_1; | ||
| 2280 | break :blk_1 !match_1; | ||
| 2281 | }) break :blk_0 true; | ||
| 2282 | p.i = pos_0; | ||
| 2283 | if (try p.parsepre_op_white() and try p.parseKEYWORD_catch() and try p.parsepost_op_white() and (try p.parsePayload() or true)) break :blk_0 true; | ||
| 2284 | p.i = pos_0; | ||
| 2285 | if (blk_1: { | ||
| 2286 | const pos_1 = p.i; | ||
| 2287 | const match_1 = try p.parsepre_op_white(); | ||
| 2288 | p.i = pos_1; | ||
| 2289 | break :blk_1 !match_1; | ||
| 2290 | } and try p.parseKEYWORD_catch() and blk_1: { | ||
| 2291 | const pos_1 = p.i; | ||
| 2292 | const match_1 = try p.parsepost_op_white(); | ||
| 2293 | p.i = pos_1; | ||
| 2294 | break :blk_1 !match_1; | ||
| 2295 | } and (try p.parsePayload() or true)) break :blk_0 true; | ||
| 2296 | p.i = pos_0; | ||
| 2297 | break :blk_0 false; | ||
| 2298 | }; | ||
| 2299 | } | ||
| 2300 | pub fn parseBitwiseOpTok(p: *Parser) Error!bool { | ||
| 2301 | const def_index = @intFromEnum(Def.defBitwiseOpTok); | ||
| 2302 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2303 | p.depths[def_index] += 1; | ||
| 2304 | defer p.depths[def_index] -= 1; | ||
| 2305 | return blk_0: { | ||
| 2306 | const pos_0 = p.i; | ||
| 2307 | if (try p.parseAMPERSAND() and blk_1: { | ||
| 2308 | const pos_1 = p.i; | ||
| 2309 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 2310 | '&'...'&', | ||
| 2311 | => blk_2: { | ||
| 2312 | p.i += 1; | ||
| 2313 | break :blk_2 true; | ||
| 2314 | }, | ||
| 2315 | else => false, | ||
| 2316 | }); | ||
| 2317 | p.i = pos_1; | ||
| 2318 | break :blk_1 !match_1; | ||
| 2319 | }) break :blk_0 true; | ||
| 2320 | p.i = pos_0; | ||
| 2321 | if (try p.parseCARET()) break :blk_0 true; | ||
| 2322 | p.i = pos_0; | ||
| 2323 | if (try p.parsePIPE()) break :blk_0 true; | ||
| 2324 | p.i = pos_0; | ||
| 2325 | if (try p.parseKEYWORD_orelse()) break :blk_0 true; | ||
| 2326 | p.i = pos_0; | ||
| 2327 | break :blk_0 false; | ||
| 2328 | }; | ||
| 2329 | } | ||
| 2330 | pub fn parseBitShiftOp(p: *Parser) Error!bool { | ||
| 2331 | const def_index = @intFromEnum(Def.defBitShiftOp); | ||
| 2332 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2333 | p.depths[def_index] += 1; | ||
| 2334 | defer p.depths[def_index] -= 1; | ||
| 2335 | return blk_0: { | ||
| 2336 | const pos_0 = p.i; | ||
| 2337 | if (try p.parsepre_op_white() and try p.parseBitShiftOpTok() and try p.parsepost_op_white()) break :blk_0 true; | ||
| 2338 | p.i = pos_0; | ||
| 2339 | if (blk_1: { | ||
| 2340 | const pos_1 = p.i; | ||
| 2341 | const match_1 = try p.parsepre_op_white(); | ||
| 2342 | p.i = pos_1; | ||
| 2343 | break :blk_1 !match_1; | ||
| 2344 | } and try p.parseBitShiftOpTok() and blk_1: { | ||
| 2345 | const pos_1 = p.i; | ||
| 2346 | const match_1 = try p.parsepost_op_white(); | ||
| 2347 | p.i = pos_1; | ||
| 2348 | break :blk_1 !match_1; | ||
| 2349 | }) break :blk_0 true; | ||
| 2350 | p.i = pos_0; | ||
| 2351 | break :blk_0 false; | ||
| 2352 | }; | ||
| 2353 | } | ||
| 2354 | pub fn parseBitShiftOpTok(p: *Parser) Error!bool { | ||
| 2355 | const def_index = @intFromEnum(Def.defBitShiftOpTok); | ||
| 2356 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2357 | p.depths[def_index] += 1; | ||
| 2358 | defer p.depths[def_index] -= 1; | ||
| 2359 | return blk_0: { | ||
| 2360 | const pos_0 = p.i; | ||
| 2361 | if (try p.parseLARROW2()) break :blk_0 true; | ||
| 2362 | p.i = pos_0; | ||
| 2363 | if (try p.parseRARROW2()) break :blk_0 true; | ||
| 2364 | p.i = pos_0; | ||
| 2365 | if (try p.parseLARROW2PIPE()) break :blk_0 true; | ||
| 2366 | p.i = pos_0; | ||
| 2367 | break :blk_0 false; | ||
| 2368 | }; | ||
| 2369 | } | ||
| 2370 | pub fn parseAdditionOp(p: *Parser) Error!bool { | ||
| 2371 | const def_index = @intFromEnum(Def.defAdditionOp); | ||
| 2372 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2373 | p.depths[def_index] += 1; | ||
| 2374 | defer p.depths[def_index] -= 1; | ||
| 2375 | return blk_0: { | ||
| 2376 | const pos_0 = p.i; | ||
| 2377 | if (try p.parsepre_op_white() and try p.parseAdditionOpTok() and try p.parsepost_op_white()) break :blk_0 true; | ||
| 2378 | p.i = pos_0; | ||
| 2379 | if (blk_1: { | ||
| 2380 | const pos_1 = p.i; | ||
| 2381 | const match_1 = try p.parsepre_op_white(); | ||
| 2382 | p.i = pos_1; | ||
| 2383 | break :blk_1 !match_1; | ||
| 2384 | } and try p.parseAdditionOpTok() and blk_1: { | ||
| 2385 | const pos_1 = p.i; | ||
| 2386 | const match_1 = try p.parsepost_op_white(); | ||
| 2387 | p.i = pos_1; | ||
| 2388 | break :blk_1 !match_1; | ||
| 2389 | }) break :blk_0 true; | ||
| 2390 | p.i = pos_0; | ||
| 2391 | break :blk_0 false; | ||
| 2392 | }; | ||
| 2393 | } | ||
| 2394 | pub fn parseAdditionOpTok(p: *Parser) Error!bool { | ||
| 2395 | const def_index = @intFromEnum(Def.defAdditionOpTok); | ||
| 2396 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2397 | p.depths[def_index] += 1; | ||
| 2398 | defer p.depths[def_index] -= 1; | ||
| 2399 | return blk_0: { | ||
| 2400 | const pos_0 = p.i; | ||
| 2401 | if (try p.parsePLUS()) break :blk_0 true; | ||
| 2402 | p.i = pos_0; | ||
| 2403 | if (try p.parseMINUS()) break :blk_0 true; | ||
| 2404 | p.i = pos_0; | ||
| 2405 | if (try p.parsePLUS2()) break :blk_0 true; | ||
| 2406 | p.i = pos_0; | ||
| 2407 | if (try p.parsePLUSPERCENT()) break :blk_0 true; | ||
| 2408 | p.i = pos_0; | ||
| 2409 | if (try p.parseMINUSPERCENT()) break :blk_0 true; | ||
| 2410 | p.i = pos_0; | ||
| 2411 | if (try p.parsePLUSPIPE()) break :blk_0 true; | ||
| 2412 | p.i = pos_0; | ||
| 2413 | if (try p.parseMINUSPIPE()) break :blk_0 true; | ||
| 2414 | p.i = pos_0; | ||
| 2415 | break :blk_0 false; | ||
| 2416 | }; | ||
| 2417 | } | ||
| 2418 | pub fn parseMultiplyOp(p: *Parser) Error!bool { | ||
| 2419 | const def_index = @intFromEnum(Def.defMultiplyOp); | ||
| 2420 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2421 | p.depths[def_index] += 1; | ||
| 2422 | defer p.depths[def_index] -= 1; | ||
| 2423 | return blk_0: { | ||
| 2424 | const pos_0 = p.i; | ||
| 2425 | if (try p.parsepre_op_white() and try p.parseMultiplyOpTok() and try p.parsepost_op_white()) break :blk_0 true; | ||
| 2426 | p.i = pos_0; | ||
| 2427 | if (blk_1: { | ||
| 2428 | const pos_1 = p.i; | ||
| 2429 | const match_1 = try p.parsepre_op_white(); | ||
| 2430 | p.i = pos_1; | ||
| 2431 | break :blk_1 !match_1; | ||
| 2432 | } and try p.parseMultiplyOpTok() and blk_1: { | ||
| 2433 | const pos_1 = p.i; | ||
| 2434 | const match_1 = try p.parsepost_op_white(); | ||
| 2435 | p.i = pos_1; | ||
| 2436 | break :blk_1 !match_1; | ||
| 2437 | }) break :blk_0 true; | ||
| 2438 | p.i = pos_0; | ||
| 2439 | break :blk_0 false; | ||
| 2440 | }; | ||
| 2441 | } | ||
| 2442 | pub fn parseMultiplyOpTok(p: *Parser) Error!bool { | ||
| 2443 | const def_index = @intFromEnum(Def.defMultiplyOpTok); | ||
| 2444 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2445 | p.depths[def_index] += 1; | ||
| 2446 | defer p.depths[def_index] -= 1; | ||
| 2447 | return blk_0: { | ||
| 2448 | const pos_0 = p.i; | ||
| 2449 | if (try p.parsePIPE2()) break :blk_0 true; | ||
| 2450 | p.i = pos_0; | ||
| 2451 | if (try p.parseASTERISK()) break :blk_0 true; | ||
| 2452 | p.i = pos_0; | ||
| 2453 | if (try p.parseSLASH()) break :blk_0 true; | ||
| 2454 | p.i = pos_0; | ||
| 2455 | if (try p.parsePERCENT()) break :blk_0 true; | ||
| 2456 | p.i = pos_0; | ||
| 2457 | if (try p.parseASTERISKPERCENT()) break :blk_0 true; | ||
| 2458 | p.i = pos_0; | ||
| 2459 | if (try p.parseASTERISKPIPE()) break :blk_0 true; | ||
| 2460 | p.i = pos_0; | ||
| 2461 | break :blk_0 false; | ||
| 2462 | }; | ||
| 2463 | } | ||
| 2464 | pub fn parsePrefixOp(p: *Parser) Error!bool { | ||
| 2465 | const def_index = @intFromEnum(Def.defPrefixOp); | ||
| 2466 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2467 | p.depths[def_index] += 1; | ||
| 2468 | defer p.depths[def_index] -= 1; | ||
| 2469 | return blk_0: { | ||
| 2470 | const pos_0 = p.i; | ||
| 2471 | if (try p.parseEXCLAMATIONMARK()) break :blk_0 true; | ||
| 2472 | p.i = pos_0; | ||
| 2473 | if (try p.parseMINUS()) break :blk_0 true; | ||
| 2474 | p.i = pos_0; | ||
| 2475 | if (try p.parseTILDE()) break :blk_0 true; | ||
| 2476 | p.i = pos_0; | ||
| 2477 | if (try p.parseMINUSPERCENT()) break :blk_0 true; | ||
| 2478 | p.i = pos_0; | ||
| 2479 | if (try p.parseAMPERSAND()) break :blk_0 true; | ||
| 2480 | p.i = pos_0; | ||
| 2481 | if (try p.parseKEYWORD_try()) break :blk_0 true; | ||
| 2482 | p.i = pos_0; | ||
| 2483 | break :blk_0 false; | ||
| 2484 | }; | ||
| 2485 | } | ||
| 2486 | pub fn parsePrefixTypeOp(p: *Parser) Error!bool { | ||
| 2487 | const def_index = @intFromEnum(Def.defPrefixTypeOp); | ||
| 2488 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2489 | p.depths[def_index] += 1; | ||
| 2490 | defer p.depths[def_index] -= 1; | ||
| 2491 | return blk_0: { | ||
| 2492 | const pos_0 = p.i; | ||
| 2493 | if (try p.parseQUESTIONMARK()) break :blk_0 true; | ||
| 2494 | p.i = pos_0; | ||
| 2495 | if (try p.parseKEYWORD_anyframe() and try p.parseMINUSRARROW()) break :blk_0 true; | ||
| 2496 | p.i = pos_0; | ||
| 2497 | if (blk_2: { | ||
| 2498 | const pos_2 = p.i; | ||
| 2499 | if (try p.parseManyPtrTypeStart()) break :blk_2 true; | ||
| 2500 | p.i = pos_2; | ||
| 2501 | if (try p.parseSliceTypeStart()) break :blk_2 true; | ||
| 2502 | p.i = pos_2; | ||
| 2503 | break :blk_2 false; | ||
| 2504 | } and try p.parsePtrMods()) break :blk_0 true; | ||
| 2505 | p.i = pos_0; | ||
| 2506 | if (try p.parseSinglePtrTypeStart() and try p.parseSinglePtrMods()) break :blk_0 true; | ||
| 2507 | p.i = pos_0; | ||
| 2508 | if (try p.parseArrayTypeStart()) break :blk_0 true; | ||
| 2509 | p.i = pos_0; | ||
| 2510 | break :blk_0 false; | ||
| 2511 | }; | ||
| 2512 | } | ||
| 2513 | pub fn parsePtrMods(p: *Parser) Error!bool { | ||
| 2514 | const def_index = @intFromEnum(Def.defPtrMods); | ||
| 2515 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2516 | p.depths[def_index] += 1; | ||
| 2517 | defer p.depths[def_index] -= 1; | ||
| 2518 | return blk_0: { | ||
| 2519 | const pos_0 = p.i; | ||
| 2520 | if (blk_1: { | ||
| 2521 | var i_1: usize = 0; | ||
| 2522 | while (try p.parsePtrMod()) { | ||
| 2523 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2524 | i_1 += 1; | ||
| 2525 | } | ||
| 2526 | break :blk_1 true; | ||
| 2527 | } and blk_1: { | ||
| 2528 | const pos_1 = p.i; | ||
| 2529 | const match_1 = try p.parseKEYWORD_addrspace(); | ||
| 2530 | p.i = pos_1; | ||
| 2531 | break :blk_1 !match_1; | ||
| 2532 | } and (try p.parseByteAlign() or true) and blk_1: { | ||
| 2533 | var i_1: usize = 0; | ||
| 2534 | while (try p.parsePtrMod()) { | ||
| 2535 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2536 | i_1 += 1; | ||
| 2537 | } | ||
| 2538 | break :blk_1 true; | ||
| 2539 | } and (try p.parseAddrSpace() or true) and blk_1: { | ||
| 2540 | var i_1: usize = 0; | ||
| 2541 | while (try p.parsePtrMod()) { | ||
| 2542 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2543 | i_1 += 1; | ||
| 2544 | } | ||
| 2545 | break :blk_1 true; | ||
| 2546 | }) break :blk_0 true; | ||
| 2547 | p.i = pos_0; | ||
| 2548 | if (blk_1: { | ||
| 2549 | var i_1: usize = 0; | ||
| 2550 | while (try p.parsePtrMod()) { | ||
| 2551 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2552 | i_1 += 1; | ||
| 2553 | } | ||
| 2554 | break :blk_1 true; | ||
| 2555 | } and blk_1: { | ||
| 2556 | const pos_1 = p.i; | ||
| 2557 | const match_1 = try p.parseKEYWORD_align(); | ||
| 2558 | p.i = pos_1; | ||
| 2559 | break :blk_1 !match_1; | ||
| 2560 | } and (try p.parseAddrSpace() or true) and blk_1: { | ||
| 2561 | var i_1: usize = 0; | ||
| 2562 | while (try p.parsePtrMod()) { | ||
| 2563 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2564 | i_1 += 1; | ||
| 2565 | } | ||
| 2566 | break :blk_1 true; | ||
| 2567 | } and (try p.parseByteAlign() or true) and blk_1: { | ||
| 2568 | var i_1: usize = 0; | ||
| 2569 | while (try p.parsePtrMod()) { | ||
| 2570 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2571 | i_1 += 1; | ||
| 2572 | } | ||
| 2573 | break :blk_1 true; | ||
| 2574 | }) break :blk_0 true; | ||
| 2575 | p.i = pos_0; | ||
| 2576 | break :blk_0 false; | ||
| 2577 | }; | ||
| 2578 | } | ||
| 2579 | pub fn parseSinglePtrMods(p: *Parser) Error!bool { | ||
| 2580 | const def_index = @intFromEnum(Def.defSinglePtrMods); | ||
| 2581 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2582 | p.depths[def_index] += 1; | ||
| 2583 | defer p.depths[def_index] -= 1; | ||
| 2584 | return blk_0: { | ||
| 2585 | const pos_0 = p.i; | ||
| 2586 | if (blk_1: { | ||
| 2587 | var i_1: usize = 0; | ||
| 2588 | while (try p.parsePtrMod()) { | ||
| 2589 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2590 | i_1 += 1; | ||
| 2591 | } | ||
| 2592 | break :blk_1 true; | ||
| 2593 | } and blk_1: { | ||
| 2594 | const pos_1 = p.i; | ||
| 2595 | const match_1 = try p.parseKEYWORD_addrspace(); | ||
| 2596 | p.i = pos_1; | ||
| 2597 | break :blk_1 !match_1; | ||
| 2598 | } and (try p.parseBitAlign() or true) and blk_1: { | ||
| 2599 | var i_1: usize = 0; | ||
| 2600 | while (try p.parsePtrMod()) { | ||
| 2601 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2602 | i_1 += 1; | ||
| 2603 | } | ||
| 2604 | break :blk_1 true; | ||
| 2605 | } and (try p.parseAddrSpace() or true) and blk_1: { | ||
| 2606 | var i_1: usize = 0; | ||
| 2607 | while (try p.parsePtrMod()) { | ||
| 2608 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2609 | i_1 += 1; | ||
| 2610 | } | ||
| 2611 | break :blk_1 true; | ||
| 2612 | }) break :blk_0 true; | ||
| 2613 | p.i = pos_0; | ||
| 2614 | if (blk_1: { | ||
| 2615 | var i_1: usize = 0; | ||
| 2616 | while (try p.parsePtrMod()) { | ||
| 2617 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2618 | i_1 += 1; | ||
| 2619 | } | ||
| 2620 | break :blk_1 true; | ||
| 2621 | } and blk_1: { | ||
| 2622 | const pos_1 = p.i; | ||
| 2623 | const match_1 = try p.parseKEYWORD_align(); | ||
| 2624 | p.i = pos_1; | ||
| 2625 | break :blk_1 !match_1; | ||
| 2626 | } and (try p.parseAddrSpace() or true) and blk_1: { | ||
| 2627 | var i_1: usize = 0; | ||
| 2628 | while (try p.parsePtrMod()) { | ||
| 2629 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2630 | i_1 += 1; | ||
| 2631 | } | ||
| 2632 | break :blk_1 true; | ||
| 2633 | } and (try p.parseBitAlign() or true) and blk_1: { | ||
| 2634 | var i_1: usize = 0; | ||
| 2635 | while (try p.parsePtrMod()) { | ||
| 2636 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 2637 | i_1 += 1; | ||
| 2638 | } | ||
| 2639 | break :blk_1 true; | ||
| 2640 | }) break :blk_0 true; | ||
| 2641 | p.i = pos_0; | ||
| 2642 | break :blk_0 false; | ||
| 2643 | }; | ||
| 2644 | } | ||
| 2645 | pub fn parsePtrMod(p: *Parser) Error!bool { | ||
| 2646 | const def_index = @intFromEnum(Def.defPtrMod); | ||
| 2647 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2648 | p.depths[def_index] += 1; | ||
| 2649 | defer p.depths[def_index] -= 1; | ||
| 2650 | return blk_0: { | ||
| 2651 | const pos_0 = p.i; | ||
| 2652 | if (try p.parseKEYWORD_allowzero()) break :blk_0 true; | ||
| 2653 | p.i = pos_0; | ||
| 2654 | if (try p.parseKEYWORD_const()) break :blk_0 true; | ||
| 2655 | p.i = pos_0; | ||
| 2656 | if (try p.parseKEYWORD_volatile()) break :blk_0 true; | ||
| 2657 | p.i = pos_0; | ||
| 2658 | break :blk_0 false; | ||
| 2659 | }; | ||
| 2660 | } | ||
| 2661 | pub fn parsePrefixTypeOpPrefix(p: *Parser) Error!bool { | ||
| 2662 | const def_index = @intFromEnum(Def.defPrefixTypeOpPrefix); | ||
| 2663 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2664 | p.depths[def_index] += 1; | ||
| 2665 | defer p.depths[def_index] -= 1; | ||
| 2666 | return blk_0: { | ||
| 2667 | const pos_0 = p.i; | ||
| 2668 | if (try p.parseQUESTIONMARK()) break :blk_0 true; | ||
| 2669 | p.i = pos_0; | ||
| 2670 | if (try p.parseKEYWORD_anyframe() and try p.parseMINUSRARROW()) break :blk_0 true; | ||
| 2671 | p.i = pos_0; | ||
| 2672 | if (try p.parseLBRACKET()) break :blk_0 true; | ||
| 2673 | p.i = pos_0; | ||
| 2674 | if (try p.parseASTERISK()) break :blk_0 true; | ||
| 2675 | p.i = pos_0; | ||
| 2676 | break :blk_0 false; | ||
| 2677 | }; | ||
| 2678 | } | ||
| 2679 | pub fn parseSuffixOp(p: *Parser) Error!bool { | ||
| 2680 | const def_index = @intFromEnum(Def.defSuffixOp); | ||
| 2681 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2682 | p.depths[def_index] += 1; | ||
| 2683 | defer p.depths[def_index] -= 1; | ||
| 2684 | return blk_0: { | ||
| 2685 | const pos_0 = p.i; | ||
| 2686 | if (try p.parseLBRACKET() and try p.parseExpr() and (blk_3: { | ||
| 2687 | const pos_3 = p.i; | ||
| 2688 | if (try p.parseDOT2() and blk_5: { | ||
| 2689 | const pos_5 = p.i; | ||
| 2690 | if (try p.parseExpr()) break :blk_5 true; | ||
| 2691 | p.i = pos_5; | ||
| 2692 | if (blk_6: { | ||
| 2693 | const pos_6 = p.i; | ||
| 2694 | const match_6 = try p.parseExprPrefix(); | ||
| 2695 | p.i = pos_6; | ||
| 2696 | break :blk_6 !match_6; | ||
| 2697 | }) break :blk_5 true; | ||
| 2698 | p.i = pos_5; | ||
| 2699 | break :blk_5 false; | ||
| 2700 | } and (blk_6: { | ||
| 2701 | const pos_6 = p.i; | ||
| 2702 | if (try p.parseCOLON() and try p.parseExpr()) break :blk_6 true; | ||
| 2703 | p.i = pos_6; | ||
| 2704 | break :blk_6 false; | ||
| 2705 | } or true)) break :blk_3 true; | ||
| 2706 | p.i = pos_3; | ||
| 2707 | break :blk_3 false; | ||
| 2708 | } or true) and try p.parseRBRACKET()) break :blk_0 true; | ||
| 2709 | p.i = pos_0; | ||
| 2710 | if (try p.parseDOT() and try p.parseIDENTIFIER()) break :blk_0 true; | ||
| 2711 | p.i = pos_0; | ||
| 2712 | if (try p.parseDOTASTERISK()) break :blk_0 true; | ||
| 2713 | p.i = pos_0; | ||
| 2714 | if (try p.parseDOT() and try p.parseQUESTIONMARK()) break :blk_0 true; | ||
| 2715 | p.i = pos_0; | ||
| 2716 | if (try p.parseFnCallArguments()) break :blk_0 true; | ||
| 2717 | p.i = pos_0; | ||
| 2718 | break :blk_0 false; | ||
| 2719 | }; | ||
| 2720 | } | ||
| 2721 | pub fn parseSuffixOpPrefix(p: *Parser) Error!bool { | ||
| 2722 | const def_index = @intFromEnum(Def.defSuffixOpPrefix); | ||
| 2723 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2724 | p.depths[def_index] += 1; | ||
| 2725 | defer p.depths[def_index] -= 1; | ||
| 2726 | return blk_0: { | ||
| 2727 | const pos_0 = p.i; | ||
| 2728 | if (try p.parseLBRACKET()) break :blk_0 true; | ||
| 2729 | p.i = pos_0; | ||
| 2730 | if (try p.parseDOT() and try p.parseIDENTIFIER()) break :blk_0 true; | ||
| 2731 | p.i = pos_0; | ||
| 2732 | if (try p.parseDOTASTERISK()) break :blk_0 true; | ||
| 2733 | p.i = pos_0; | ||
| 2734 | if (try p.parseDOT() and try p.parseQUESTIONMARK()) break :blk_0 true; | ||
| 2735 | p.i = pos_0; | ||
| 2736 | if (try p.parseLPAREN()) break :blk_0 true; | ||
| 2737 | p.i = pos_0; | ||
| 2738 | break :blk_0 false; | ||
| 2739 | }; | ||
| 2740 | } | ||
| 2741 | pub fn parseFnCallArguments(p: *Parser) Error!bool { | ||
| 2742 | const def_index = @intFromEnum(Def.defFnCallArguments); | ||
| 2743 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2744 | p.depths[def_index] += 1; | ||
| 2745 | defer p.depths[def_index] -= 1; | ||
| 2746 | return blk_0: { | ||
| 2747 | const pos_0 = p.i; | ||
| 2748 | if (try p.parseLPAREN() and try p.parseExprList() and try p.parseRPAREN()) break :blk_0 true; | ||
| 2749 | p.i = pos_0; | ||
| 2750 | break :blk_0 false; | ||
| 2751 | }; | ||
| 2752 | } | ||
| 2753 | pub fn parseSliceTypeStart(p: *Parser) Error!bool { | ||
| 2754 | const def_index = @intFromEnum(Def.defSliceTypeStart); | ||
| 2755 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2756 | p.depths[def_index] += 1; | ||
| 2757 | defer p.depths[def_index] -= 1; | ||
| 2758 | return blk_0: { | ||
| 2759 | const pos_0 = p.i; | ||
| 2760 | if (try p.parseLBRACKET() and (blk_3: { | ||
| 2761 | const pos_3 = p.i; | ||
| 2762 | if (try p.parseCOLON() and try p.parseExpr()) break :blk_3 true; | ||
| 2763 | p.i = pos_3; | ||
| 2764 | break :blk_3 false; | ||
| 2765 | } or true) and try p.parseRBRACKET()) break :blk_0 true; | ||
| 2766 | p.i = pos_0; | ||
| 2767 | break :blk_0 false; | ||
| 2768 | }; | ||
| 2769 | } | ||
| 2770 | pub fn parseSinglePtrTypeStart(p: *Parser) Error!bool { | ||
| 2771 | const def_index = @intFromEnum(Def.defSinglePtrTypeStart); | ||
| 2772 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2773 | p.depths[def_index] += 1; | ||
| 2774 | defer p.depths[def_index] -= 1; | ||
| 2775 | return blk_0: { | ||
| 2776 | const pos_0 = p.i; | ||
| 2777 | if (try p.parseASTERISK()) break :blk_0 true; | ||
| 2778 | p.i = pos_0; | ||
| 2779 | break :blk_0 false; | ||
| 2780 | }; | ||
| 2781 | } | ||
| 2782 | pub fn parseManyPtrTypeStart(p: *Parser) Error!bool { | ||
| 2783 | const def_index = @intFromEnum(Def.defManyPtrTypeStart); | ||
| 2784 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2785 | p.depths[def_index] += 1; | ||
| 2786 | defer p.depths[def_index] -= 1; | ||
| 2787 | return blk_0: { | ||
| 2788 | const pos_0 = p.i; | ||
| 2789 | if (try p.parseLBRACKET() and try p.parseASTERISK() and (blk_3: { | ||
| 2790 | const pos_3 = p.i; | ||
| 2791 | if (try p.parseLETTERC()) break :blk_3 true; | ||
| 2792 | p.i = pos_3; | ||
| 2793 | if (try p.parseCOLON() and try p.parseExpr()) break :blk_3 true; | ||
| 2794 | p.i = pos_3; | ||
| 2795 | break :blk_3 false; | ||
| 2796 | } or true) and try p.parseRBRACKET()) break :blk_0 true; | ||
| 2797 | p.i = pos_0; | ||
| 2798 | break :blk_0 false; | ||
| 2799 | }; | ||
| 2800 | } | ||
| 2801 | pub fn parseArrayTypeStart(p: *Parser) Error!bool { | ||
| 2802 | const def_index = @intFromEnum(Def.defArrayTypeStart); | ||
| 2803 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2804 | p.depths[def_index] += 1; | ||
| 2805 | defer p.depths[def_index] -= 1; | ||
| 2806 | return blk_0: { | ||
| 2807 | const pos_0 = p.i; | ||
| 2808 | if (try p.parseLBRACKET() and blk_1: { | ||
| 2809 | const pos_1 = p.i; | ||
| 2810 | const match_1 = try p.parseASTERISK(); | ||
| 2811 | p.i = pos_1; | ||
| 2812 | break :blk_1 !match_1; | ||
| 2813 | } and try p.parseExpr() and (blk_3: { | ||
| 2814 | const pos_3 = p.i; | ||
| 2815 | if (try p.parseCOLON() and try p.parseExpr()) break :blk_3 true; | ||
| 2816 | p.i = pos_3; | ||
| 2817 | break :blk_3 false; | ||
| 2818 | } or true) and try p.parseRBRACKET()) break :blk_0 true; | ||
| 2819 | p.i = pos_0; | ||
| 2820 | break :blk_0 false; | ||
| 2821 | }; | ||
| 2822 | } | ||
| 2823 | pub fn parseContainerTypeAuto(p: *Parser) Error!bool { | ||
| 2824 | const def_index = @intFromEnum(Def.defContainerTypeAuto); | ||
| 2825 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2826 | p.depths[def_index] += 1; | ||
| 2827 | defer p.depths[def_index] -= 1; | ||
| 2828 | return blk_0: { | ||
| 2829 | const pos_0 = p.i; | ||
| 2830 | if (try p.parseContainerTypeKind() and try p.parseLBRACE() and try p.parseContainerMembers() and try p.parseRBRACE()) break :blk_0 true; | ||
| 2831 | p.i = pos_0; | ||
| 2832 | break :blk_0 false; | ||
| 2833 | }; | ||
| 2834 | } | ||
| 2835 | pub fn parseContainerTypeKind(p: *Parser) Error!bool { | ||
| 2836 | const def_index = @intFromEnum(Def.defContainerTypeKind); | ||
| 2837 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2838 | p.depths[def_index] += 1; | ||
| 2839 | defer p.depths[def_index] -= 1; | ||
| 2840 | return blk_0: { | ||
| 2841 | const pos_0 = p.i; | ||
| 2842 | if (try p.parseKEYWORD_struct() and (blk_3: { | ||
| 2843 | const pos_3 = p.i; | ||
| 2844 | if (try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_3 true; | ||
| 2845 | p.i = pos_3; | ||
| 2846 | break :blk_3 false; | ||
| 2847 | } or true)) break :blk_0 true; | ||
| 2848 | p.i = pos_0; | ||
| 2849 | if (try p.parseKEYWORD_opaque()) break :blk_0 true; | ||
| 2850 | p.i = pos_0; | ||
| 2851 | if (try p.parseKEYWORD_enum() and (blk_3: { | ||
| 2852 | const pos_3 = p.i; | ||
| 2853 | if (try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_3 true; | ||
| 2854 | p.i = pos_3; | ||
| 2855 | break :blk_3 false; | ||
| 2856 | } or true)) break :blk_0 true; | ||
| 2857 | p.i = pos_0; | ||
| 2858 | if (try p.parseKEYWORD_union() and (blk_3: { | ||
| 2859 | const pos_3 = p.i; | ||
| 2860 | if (try p.parseLPAREN() and blk_5: { | ||
| 2861 | const pos_5 = p.i; | ||
| 2862 | if (try p.parseKEYWORD_enum() and (blk_8: { | ||
| 2863 | const pos_8 = p.i; | ||
| 2864 | if (try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_8 true; | ||
| 2865 | p.i = pos_8; | ||
| 2866 | break :blk_8 false; | ||
| 2867 | } or true)) break :blk_5 true; | ||
| 2868 | p.i = pos_5; | ||
| 2869 | if (try p.parseExpr()) break :blk_5 true; | ||
| 2870 | p.i = pos_5; | ||
| 2871 | break :blk_5 false; | ||
| 2872 | } and try p.parseRPAREN()) break :blk_3 true; | ||
| 2873 | p.i = pos_3; | ||
| 2874 | break :blk_3 false; | ||
| 2875 | } or true)) break :blk_0 true; | ||
| 2876 | p.i = pos_0; | ||
| 2877 | break :blk_0 false; | ||
| 2878 | }; | ||
| 2879 | } | ||
| 2880 | pub fn parseByteAlign(p: *Parser) Error!bool { | ||
| 2881 | const def_index = @intFromEnum(Def.defByteAlign); | ||
| 2882 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2883 | p.depths[def_index] += 1; | ||
| 2884 | defer p.depths[def_index] -= 1; | ||
| 2885 | return blk_0: { | ||
| 2886 | const pos_0 = p.i; | ||
| 2887 | if (try p.parseKEYWORD_align() and try p.parseLPAREN() and try p.parseExpr() and try p.parseRPAREN()) break :blk_0 true; | ||
| 2888 | p.i = pos_0; | ||
| 2889 | break :blk_0 false; | ||
| 2890 | }; | ||
| 2891 | } | ||
| 2892 | pub fn parseBitAlign(p: *Parser) Error!bool { | ||
| 2893 | const def_index = @intFromEnum(Def.defBitAlign); | ||
| 2894 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2895 | p.depths[def_index] += 1; | ||
| 2896 | defer p.depths[def_index] -= 1; | ||
| 2897 | return blk_0: { | ||
| 2898 | const pos_0 = p.i; | ||
| 2899 | if (try p.parseKEYWORD_align() and try p.parseLPAREN() and try p.parseExpr() and (blk_3: { | ||
| 2900 | const pos_3 = p.i; | ||
| 2901 | if (try p.parseCOLON() and try p.parseExpr() and try p.parseCOLON() and try p.parseExpr()) break :blk_3 true; | ||
| 2902 | p.i = pos_3; | ||
| 2903 | break :blk_3 false; | ||
| 2904 | } or true) and try p.parseRPAREN()) break :blk_0 true; | ||
| 2905 | p.i = pos_0; | ||
| 2906 | break :blk_0 false; | ||
| 2907 | }; | ||
| 2908 | } | ||
| 2909 | pub fn parseIdentifierList(p: *Parser) Error!bool { | ||
| 2910 | const def_index = @intFromEnum(Def.defIdentifierList); | ||
| 2911 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2912 | p.depths[def_index] += 1; | ||
| 2913 | defer p.depths[def_index] -= 1; | ||
| 2914 | return blk_0: { | ||
| 2915 | const pos_0 = p.i; | ||
| 2916 | if ((blk_3: { | ||
| 2917 | const pos_3 = p.i; | ||
| 2918 | if ((try p.parsedoc_comment() or true) and try p.parseIDENTIFIER() and (blk_6: { | ||
| 2919 | const pos_6 = p.i; | ||
| 2920 | if (try p.parseCOMMA() and try p.parseIdentifierList()) break :blk_6 true; | ||
| 2921 | p.i = pos_6; | ||
| 2922 | break :blk_6 false; | ||
| 2923 | } or true)) break :blk_3 true; | ||
| 2924 | p.i = pos_3; | ||
| 2925 | break :blk_3 false; | ||
| 2926 | } or true)) break :blk_0 true; | ||
| 2927 | p.i = pos_0; | ||
| 2928 | break :blk_0 false; | ||
| 2929 | }; | ||
| 2930 | } | ||
| 2931 | pub fn parseSwitchProngList(p: *Parser) Error!bool { | ||
| 2932 | const def_index = @intFromEnum(Def.defSwitchProngList); | ||
| 2933 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2934 | p.depths[def_index] += 1; | ||
| 2935 | defer p.depths[def_index] -= 1; | ||
| 2936 | return blk_0: { | ||
| 2937 | const pos_0 = p.i; | ||
| 2938 | if ((blk_3: { | ||
| 2939 | const pos_3 = p.i; | ||
| 2940 | if (try p.parseSwitchProng() and (blk_6: { | ||
| 2941 | const pos_6 = p.i; | ||
| 2942 | if (try p.parseCOMMA() and try p.parseSwitchProngList()) break :blk_6 true; | ||
| 2943 | p.i = pos_6; | ||
| 2944 | break :blk_6 false; | ||
| 2945 | } or true)) break :blk_3 true; | ||
| 2946 | p.i = pos_3; | ||
| 2947 | break :blk_3 false; | ||
| 2948 | } or true)) break :blk_0 true; | ||
| 2949 | p.i = pos_0; | ||
| 2950 | break :blk_0 false; | ||
| 2951 | }; | ||
| 2952 | } | ||
| 2953 | pub fn parseAsmOutputList(p: *Parser) Error!bool { | ||
| 2954 | const def_index = @intFromEnum(Def.defAsmOutputList); | ||
| 2955 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2956 | p.depths[def_index] += 1; | ||
| 2957 | defer p.depths[def_index] -= 1; | ||
| 2958 | return blk_0: { | ||
| 2959 | const pos_0 = p.i; | ||
| 2960 | if ((blk_3: { | ||
| 2961 | const pos_3 = p.i; | ||
| 2962 | if (try p.parseAsmOutputItem() and (blk_6: { | ||
| 2963 | const pos_6 = p.i; | ||
| 2964 | if (try p.parseCOMMA() and try p.parseAsmOutputList()) break :blk_6 true; | ||
| 2965 | p.i = pos_6; | ||
| 2966 | break :blk_6 false; | ||
| 2967 | } or true)) break :blk_3 true; | ||
| 2968 | p.i = pos_3; | ||
| 2969 | break :blk_3 false; | ||
| 2970 | } or true)) break :blk_0 true; | ||
| 2971 | p.i = pos_0; | ||
| 2972 | break :blk_0 false; | ||
| 2973 | }; | ||
| 2974 | } | ||
| 2975 | pub fn parseAsmInputList(p: *Parser) Error!bool { | ||
| 2976 | const def_index = @intFromEnum(Def.defAsmInputList); | ||
| 2977 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 2978 | p.depths[def_index] += 1; | ||
| 2979 | defer p.depths[def_index] -= 1; | ||
| 2980 | return blk_0: { | ||
| 2981 | const pos_0 = p.i; | ||
| 2982 | if ((blk_3: { | ||
| 2983 | const pos_3 = p.i; | ||
| 2984 | if (try p.parseAsmInputItem() and (blk_6: { | ||
| 2985 | const pos_6 = p.i; | ||
| 2986 | if (try p.parseCOMMA() and try p.parseAsmInputList()) break :blk_6 true; | ||
| 2987 | p.i = pos_6; | ||
| 2988 | break :blk_6 false; | ||
| 2989 | } or true)) break :blk_3 true; | ||
| 2990 | p.i = pos_3; | ||
| 2991 | break :blk_3 false; | ||
| 2992 | } or true)) break :blk_0 true; | ||
| 2993 | p.i = pos_0; | ||
| 2994 | break :blk_0 false; | ||
| 2995 | }; | ||
| 2996 | } | ||
| 2997 | pub fn parseParamDeclList(p: *Parser) Error!bool { | ||
| 2998 | const def_index = @intFromEnum(Def.defParamDeclList); | ||
| 2999 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3000 | p.depths[def_index] += 1; | ||
| 3001 | defer p.depths[def_index] -= 1; | ||
| 3002 | return blk_0: { | ||
| 3003 | const pos_0 = p.i; | ||
| 3004 | if (try p.parseLPAREN() and try p.parseParamDeclListRest()) break :blk_0 true; | ||
| 3005 | p.i = pos_0; | ||
| 3006 | break :blk_0 false; | ||
| 3007 | }; | ||
| 3008 | } | ||
| 3009 | pub fn parseParamDeclListRest(p: *Parser) Error!bool { | ||
| 3010 | const def_index = @intFromEnum(Def.defParamDeclListRest); | ||
| 3011 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3012 | p.depths[def_index] += 1; | ||
| 3013 | defer p.depths[def_index] -= 1; | ||
| 3014 | return blk_0: { | ||
| 3015 | const pos_0 = p.i; | ||
| 3016 | if (try p.parseRPAREN()) break :blk_0 true; | ||
| 3017 | p.i = pos_0; | ||
| 3018 | if (try p.parseDOT3() and (try p.parseCOMMA() or true) and try p.parseRPAREN()) break :blk_0 true; | ||
| 3019 | p.i = pos_0; | ||
| 3020 | if (try p.parseParamDecl() and blk_2: { | ||
| 3021 | const pos_2 = p.i; | ||
| 3022 | if (try p.parseCOMMA() and try p.parseParamDeclListRest()) break :blk_2 true; | ||
| 3023 | p.i = pos_2; | ||
| 3024 | if (try p.parseRPAREN()) break :blk_2 true; | ||
| 3025 | p.i = pos_2; | ||
| 3026 | break :blk_2 false; | ||
| 3027 | }) break :blk_0 true; | ||
| 3028 | p.i = pos_0; | ||
| 3029 | break :blk_0 false; | ||
| 3030 | }; | ||
| 3031 | } | ||
| 3032 | pub fn parseExprList(p: *Parser) Error!bool { | ||
| 3033 | const def_index = @intFromEnum(Def.defExprList); | ||
| 3034 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3035 | p.depths[def_index] += 1; | ||
| 3036 | defer p.depths[def_index] -= 1; | ||
| 3037 | return blk_0: { | ||
| 3038 | const pos_0 = p.i; | ||
| 3039 | if (try p.parseExpr() and (blk_3: { | ||
| 3040 | const pos_3 = p.i; | ||
| 3041 | if (try p.parseCOMMA() and try p.parseExprList()) break :blk_3 true; | ||
| 3042 | p.i = pos_3; | ||
| 3043 | break :blk_3 false; | ||
| 3044 | } or true)) break :blk_0 true; | ||
| 3045 | p.i = pos_0; | ||
| 3046 | if (blk_1: { | ||
| 3047 | const pos_1 = p.i; | ||
| 3048 | const match_1 = try p.parseExprPrefix(); | ||
| 3049 | p.i = pos_1; | ||
| 3050 | break :blk_1 !match_1; | ||
| 3051 | }) break :blk_0 true; | ||
| 3052 | p.i = pos_0; | ||
| 3053 | break :blk_0 false; | ||
| 3054 | }; | ||
| 3055 | } | ||
| 3056 | pub fn parseExprPrefix(p: *Parser) Error!bool { | ||
| 3057 | const def_index = @intFromEnum(Def.defExprPrefix); | ||
| 3058 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3059 | p.depths[def_index] += 1; | ||
| 3060 | defer p.depths[def_index] -= 1; | ||
| 3061 | return blk_0: { | ||
| 3062 | const pos_0 = p.i; | ||
| 3063 | if (try p.parseASTERISK()) break :blk_0 true; | ||
| 3064 | p.i = pos_0; | ||
| 3065 | break :blk_0 false; | ||
| 3066 | }; | ||
| 3067 | } | ||
| 3068 | pub fn parsebyte_order_mark(p: *Parser) Error!bool { | ||
| 3069 | const def_index = @intFromEnum(Def.defbyte_order_mark); | ||
| 3070 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3071 | p.depths[def_index] += 1; | ||
| 3072 | defer p.depths[def_index] -= 1; | ||
| 3073 | return blk_0: { | ||
| 3074 | const pos_0 = p.i; | ||
| 3075 | if (blk_1: { | ||
| 3076 | if (std.mem.startsWith(u8, p.source[p.i..], "\xef\xbb\xbf")) { | ||
| 3077 | p.i += 3; | ||
| 3078 | break :blk_1 true; | ||
| 3079 | } | ||
| 3080 | break :blk_1 false; | ||
| 3081 | }) break :blk_0 true; | ||
| 3082 | p.i = pos_0; | ||
| 3083 | break :blk_0 false; | ||
| 3084 | }; | ||
| 3085 | } | ||
| 3086 | pub fn parsesof(p: *Parser) Error!bool { | ||
| 3087 | const def_index = @intFromEnum(Def.defsof); | ||
| 3088 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3089 | p.depths[def_index] += 1; | ||
| 3090 | defer p.depths[def_index] -= 1; | ||
| 3091 | return blk_0: { | ||
| 3092 | const pos_0 = p.i; | ||
| 3093 | if ((p.i == 0) and (try p.parsebyte_order_mark() or true)) break :blk_0 true; | ||
| 3094 | p.i = pos_0; | ||
| 3095 | break :blk_0 false; | ||
| 3096 | }; | ||
| 3097 | } | ||
| 3098 | pub fn parseeof(p: *Parser) Error!bool { | ||
| 3099 | const def_index = @intFromEnum(Def.defeof); | ||
| 3100 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3101 | p.depths[def_index] += 1; | ||
| 3102 | defer p.depths[def_index] -= 1; | ||
| 3103 | return blk_0: { | ||
| 3104 | const pos_0 = p.i; | ||
| 3105 | if (blk_1: { | ||
| 3106 | const pos_1 = p.i; | ||
| 3107 | const match_1 = blk_2: { | ||
| 3108 | if (p.i < p.source.len) { | ||
| 3109 | p.i += 1; | ||
| 3110 | break :blk_2 true; | ||
| 3111 | } | ||
| 3112 | break :blk_2 false; | ||
| 3113 | }; | ||
| 3114 | p.i = pos_1; | ||
| 3115 | break :blk_1 !match_1; | ||
| 3116 | }) break :blk_0 true; | ||
| 3117 | p.i = pos_0; | ||
| 3118 | break :blk_0 false; | ||
| 3119 | }; | ||
| 3120 | } | ||
| 3121 | pub fn parseox80_oxBF(p: *Parser) Error!bool { | ||
| 3122 | const def_index = @intFromEnum(Def.defox80_oxBF); | ||
| 3123 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3124 | p.depths[def_index] += 1; | ||
| 3125 | defer p.depths[def_index] -= 1; | ||
| 3126 | return blk_0: { | ||
| 3127 | const pos_0 = p.i; | ||
| 3128 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3129 | '\x80'...'\xbf', | ||
| 3130 | => blk_1: { | ||
| 3131 | p.i += 1; | ||
| 3132 | break :blk_1 true; | ||
| 3133 | }, | ||
| 3134 | else => false, | ||
| 3135 | })) break :blk_0 true; | ||
| 3136 | p.i = pos_0; | ||
| 3137 | break :blk_0 false; | ||
| 3138 | }; | ||
| 3139 | } | ||
| 3140 | pub fn parseoxF4(p: *Parser) Error!bool { | ||
| 3141 | const def_index = @intFromEnum(Def.defoxF4); | ||
| 3142 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3143 | p.depths[def_index] += 1; | ||
| 3144 | defer p.depths[def_index] -= 1; | ||
| 3145 | return blk_0: { | ||
| 3146 | const pos_0 = p.i; | ||
| 3147 | if (blk_1: { | ||
| 3148 | if (std.mem.startsWith(u8, p.source[p.i..], "\xf4")) { | ||
| 3149 | p.i += 1; | ||
| 3150 | break :blk_1 true; | ||
| 3151 | } | ||
| 3152 | break :blk_1 false; | ||
| 3153 | }) break :blk_0 true; | ||
| 3154 | p.i = pos_0; | ||
| 3155 | break :blk_0 false; | ||
| 3156 | }; | ||
| 3157 | } | ||
| 3158 | pub fn parseox80_ox8F(p: *Parser) Error!bool { | ||
| 3159 | const def_index = @intFromEnum(Def.defox80_ox8F); | ||
| 3160 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3161 | p.depths[def_index] += 1; | ||
| 3162 | defer p.depths[def_index] -= 1; | ||
| 3163 | return blk_0: { | ||
| 3164 | const pos_0 = p.i; | ||
| 3165 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3166 | '\x80'...'\x8f', | ||
| 3167 | => blk_1: { | ||
| 3168 | p.i += 1; | ||
| 3169 | break :blk_1 true; | ||
| 3170 | }, | ||
| 3171 | else => false, | ||
| 3172 | })) break :blk_0 true; | ||
| 3173 | p.i = pos_0; | ||
| 3174 | break :blk_0 false; | ||
| 3175 | }; | ||
| 3176 | } | ||
| 3177 | pub fn parseoxF1_oxF3(p: *Parser) Error!bool { | ||
| 3178 | const def_index = @intFromEnum(Def.defoxF1_oxF3); | ||
| 3179 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3180 | p.depths[def_index] += 1; | ||
| 3181 | defer p.depths[def_index] -= 1; | ||
| 3182 | return blk_0: { | ||
| 3183 | const pos_0 = p.i; | ||
| 3184 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3185 | '\xf1'...'\xf3', | ||
| 3186 | => blk_1: { | ||
| 3187 | p.i += 1; | ||
| 3188 | break :blk_1 true; | ||
| 3189 | }, | ||
| 3190 | else => false, | ||
| 3191 | })) break :blk_0 true; | ||
| 3192 | p.i = pos_0; | ||
| 3193 | break :blk_0 false; | ||
| 3194 | }; | ||
| 3195 | } | ||
| 3196 | pub fn parseoxF0(p: *Parser) Error!bool { | ||
| 3197 | const def_index = @intFromEnum(Def.defoxF0); | ||
| 3198 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3199 | p.depths[def_index] += 1; | ||
| 3200 | defer p.depths[def_index] -= 1; | ||
| 3201 | return blk_0: { | ||
| 3202 | const pos_0 = p.i; | ||
| 3203 | if (blk_1: { | ||
| 3204 | if (std.mem.startsWith(u8, p.source[p.i..], "\xf0")) { | ||
| 3205 | p.i += 1; | ||
| 3206 | break :blk_1 true; | ||
| 3207 | } | ||
| 3208 | break :blk_1 false; | ||
| 3209 | }) break :blk_0 true; | ||
| 3210 | p.i = pos_0; | ||
| 3211 | break :blk_0 false; | ||
| 3212 | }; | ||
| 3213 | } | ||
| 3214 | pub fn parseox90_0xBF(p: *Parser) Error!bool { | ||
| 3215 | const def_index = @intFromEnum(Def.defox90_0xBF); | ||
| 3216 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3217 | p.depths[def_index] += 1; | ||
| 3218 | defer p.depths[def_index] -= 1; | ||
| 3219 | return blk_0: { | ||
| 3220 | const pos_0 = p.i; | ||
| 3221 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3222 | '\x90'...'\xbf', | ||
| 3223 | => blk_1: { | ||
| 3224 | p.i += 1; | ||
| 3225 | break :blk_1 true; | ||
| 3226 | }, | ||
| 3227 | else => false, | ||
| 3228 | })) break :blk_0 true; | ||
| 3229 | p.i = pos_0; | ||
| 3230 | break :blk_0 false; | ||
| 3231 | }; | ||
| 3232 | } | ||
| 3233 | pub fn parseoxEE_oxEF(p: *Parser) Error!bool { | ||
| 3234 | const def_index = @intFromEnum(Def.defoxEE_oxEF); | ||
| 3235 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3236 | p.depths[def_index] += 1; | ||
| 3237 | defer p.depths[def_index] -= 1; | ||
| 3238 | return blk_0: { | ||
| 3239 | const pos_0 = p.i; | ||
| 3240 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3241 | '\xee'...'\xef', | ||
| 3242 | => blk_1: { | ||
| 3243 | p.i += 1; | ||
| 3244 | break :blk_1 true; | ||
| 3245 | }, | ||
| 3246 | else => false, | ||
| 3247 | })) break :blk_0 true; | ||
| 3248 | p.i = pos_0; | ||
| 3249 | break :blk_0 false; | ||
| 3250 | }; | ||
| 3251 | } | ||
| 3252 | pub fn parseoxED(p: *Parser) Error!bool { | ||
| 3253 | const def_index = @intFromEnum(Def.defoxED); | ||
| 3254 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3255 | p.depths[def_index] += 1; | ||
| 3256 | defer p.depths[def_index] -= 1; | ||
| 3257 | return blk_0: { | ||
| 3258 | const pos_0 = p.i; | ||
| 3259 | if (blk_1: { | ||
| 3260 | if (std.mem.startsWith(u8, p.source[p.i..], "\xed")) { | ||
| 3261 | p.i += 1; | ||
| 3262 | break :blk_1 true; | ||
| 3263 | } | ||
| 3264 | break :blk_1 false; | ||
| 3265 | }) break :blk_0 true; | ||
| 3266 | p.i = pos_0; | ||
| 3267 | break :blk_0 false; | ||
| 3268 | }; | ||
| 3269 | } | ||
| 3270 | pub fn parseox80_ox9F(p: *Parser) Error!bool { | ||
| 3271 | const def_index = @intFromEnum(Def.defox80_ox9F); | ||
| 3272 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3273 | p.depths[def_index] += 1; | ||
| 3274 | defer p.depths[def_index] -= 1; | ||
| 3275 | return blk_0: { | ||
| 3276 | const pos_0 = p.i; | ||
| 3277 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3278 | '\x80'...'\x9f', | ||
| 3279 | => blk_1: { | ||
| 3280 | p.i += 1; | ||
| 3281 | break :blk_1 true; | ||
| 3282 | }, | ||
| 3283 | else => false, | ||
| 3284 | })) break :blk_0 true; | ||
| 3285 | p.i = pos_0; | ||
| 3286 | break :blk_0 false; | ||
| 3287 | }; | ||
| 3288 | } | ||
| 3289 | pub fn parseoxE1_oxEC(p: *Parser) Error!bool { | ||
| 3290 | const def_index = @intFromEnum(Def.defoxE1_oxEC); | ||
| 3291 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3292 | p.depths[def_index] += 1; | ||
| 3293 | defer p.depths[def_index] -= 1; | ||
| 3294 | return blk_0: { | ||
| 3295 | const pos_0 = p.i; | ||
| 3296 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3297 | '\xe1'...'\xec', | ||
| 3298 | => blk_1: { | ||
| 3299 | p.i += 1; | ||
| 3300 | break :blk_1 true; | ||
| 3301 | }, | ||
| 3302 | else => false, | ||
| 3303 | })) break :blk_0 true; | ||
| 3304 | p.i = pos_0; | ||
| 3305 | break :blk_0 false; | ||
| 3306 | }; | ||
| 3307 | } | ||
| 3308 | pub fn parseoxE0(p: *Parser) Error!bool { | ||
| 3309 | const def_index = @intFromEnum(Def.defoxE0); | ||
| 3310 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3311 | p.depths[def_index] += 1; | ||
| 3312 | defer p.depths[def_index] -= 1; | ||
| 3313 | return blk_0: { | ||
| 3314 | const pos_0 = p.i; | ||
| 3315 | if (blk_1: { | ||
| 3316 | if (std.mem.startsWith(u8, p.source[p.i..], "\xe0")) { | ||
| 3317 | p.i += 1; | ||
| 3318 | break :blk_1 true; | ||
| 3319 | } | ||
| 3320 | break :blk_1 false; | ||
| 3321 | }) break :blk_0 true; | ||
| 3322 | p.i = pos_0; | ||
| 3323 | break :blk_0 false; | ||
| 3324 | }; | ||
| 3325 | } | ||
| 3326 | pub fn parseoxA0_oxBF(p: *Parser) Error!bool { | ||
| 3327 | const def_index = @intFromEnum(Def.defoxA0_oxBF); | ||
| 3328 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3329 | p.depths[def_index] += 1; | ||
| 3330 | defer p.depths[def_index] -= 1; | ||
| 3331 | return blk_0: { | ||
| 3332 | const pos_0 = p.i; | ||
| 3333 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3334 | '\xa0'...'\xbf', | ||
| 3335 | => blk_1: { | ||
| 3336 | p.i += 1; | ||
| 3337 | break :blk_1 true; | ||
| 3338 | }, | ||
| 3339 | else => false, | ||
| 3340 | })) break :blk_0 true; | ||
| 3341 | p.i = pos_0; | ||
| 3342 | break :blk_0 false; | ||
| 3343 | }; | ||
| 3344 | } | ||
| 3345 | pub fn parseoxC2_oxDF(p: *Parser) Error!bool { | ||
| 3346 | const def_index = @intFromEnum(Def.defoxC2_oxDF); | ||
| 3347 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3348 | p.depths[def_index] += 1; | ||
| 3349 | defer p.depths[def_index] -= 1; | ||
| 3350 | return blk_0: { | ||
| 3351 | const pos_0 = p.i; | ||
| 3352 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3353 | '\xc2'...'\xdf', | ||
| 3354 | => blk_1: { | ||
| 3355 | p.i += 1; | ||
| 3356 | break :blk_1 true; | ||
| 3357 | }, | ||
| 3358 | else => false, | ||
| 3359 | })) break :blk_0 true; | ||
| 3360 | p.i = pos_0; | ||
| 3361 | break :blk_0 false; | ||
| 3362 | }; | ||
| 3363 | } | ||
| 3364 | pub fn parsemultibyte_utf8(p: *Parser) Error!bool { | ||
| 3365 | const def_index = @intFromEnum(Def.defmultibyte_utf8); | ||
| 3366 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3367 | p.depths[def_index] += 1; | ||
| 3368 | defer p.depths[def_index] -= 1; | ||
| 3369 | return blk_0: { | ||
| 3370 | const pos_0 = p.i; | ||
| 3371 | if (try p.parseoxF4() and try p.parseox80_ox8F() and try p.parseox80_oxBF() and try p.parseox80_oxBF()) break :blk_0 true; | ||
| 3372 | p.i = pos_0; | ||
| 3373 | if (try p.parseoxF1_oxF3() and try p.parseox80_oxBF() and try p.parseox80_oxBF() and try p.parseox80_oxBF()) break :blk_0 true; | ||
| 3374 | p.i = pos_0; | ||
| 3375 | if (try p.parseoxF0() and try p.parseox90_0xBF() and try p.parseox80_oxBF() and try p.parseox80_oxBF()) break :blk_0 true; | ||
| 3376 | p.i = pos_0; | ||
| 3377 | if (try p.parseoxEE_oxEF() and try p.parseox80_oxBF() and try p.parseox80_oxBF()) break :blk_0 true; | ||
| 3378 | p.i = pos_0; | ||
| 3379 | if (try p.parseoxED() and try p.parseox80_ox9F() and try p.parseox80_oxBF()) break :blk_0 true; | ||
| 3380 | p.i = pos_0; | ||
| 3381 | if (try p.parseoxE1_oxEC() and try p.parseox80_oxBF() and try p.parseox80_oxBF()) break :blk_0 true; | ||
| 3382 | p.i = pos_0; | ||
| 3383 | if (try p.parseoxE0() and try p.parseoxA0_oxBF() and try p.parseox80_oxBF()) break :blk_0 true; | ||
| 3384 | p.i = pos_0; | ||
| 3385 | if (try p.parseoxC2_oxDF() and try p.parseox80_oxBF()) break :blk_0 true; | ||
| 3386 | p.i = pos_0; | ||
| 3387 | break :blk_0 false; | ||
| 3388 | }; | ||
| 3389 | } | ||
| 3390 | pub fn parsenon_control_ascii(p: *Parser) Error!bool { | ||
| 3391 | const def_index = @intFromEnum(Def.defnon_control_ascii); | ||
| 3392 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3393 | p.depths[def_index] += 1; | ||
| 3394 | defer p.depths[def_index] -= 1; | ||
| 3395 | return blk_0: { | ||
| 3396 | const pos_0 = p.i; | ||
| 3397 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3398 | ' '...'~', | ||
| 3399 | => blk_1: { | ||
| 3400 | p.i += 1; | ||
| 3401 | break :blk_1 true; | ||
| 3402 | }, | ||
| 3403 | else => false, | ||
| 3404 | })) break :blk_0 true; | ||
| 3405 | p.i = pos_0; | ||
| 3406 | break :blk_0 false; | ||
| 3407 | }; | ||
| 3408 | } | ||
| 3409 | pub fn parsenon_control_utf8(p: *Parser) Error!bool { | ||
| 3410 | const def_index = @intFromEnum(Def.defnon_control_utf8); | ||
| 3411 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3412 | p.depths[def_index] += 1; | ||
| 3413 | defer p.depths[def_index] -= 1; | ||
| 3414 | return blk_0: { | ||
| 3415 | const pos_0 = p.i; | ||
| 3416 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3417 | ' '...'~', | ||
| 3418 | '\x80'...'\xff', | ||
| 3419 | => blk_1: { | ||
| 3420 | p.i += 1; | ||
| 3421 | break :blk_1 true; | ||
| 3422 | }, | ||
| 3423 | else => false, | ||
| 3424 | })) break :blk_0 true; | ||
| 3425 | p.i = pos_0; | ||
| 3426 | break :blk_0 false; | ||
| 3427 | }; | ||
| 3428 | } | ||
| 3429 | pub fn parsechar_char(p: *Parser) Error!bool { | ||
| 3430 | const def_index = @intFromEnum(Def.defchar_char); | ||
| 3431 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3432 | p.depths[def_index] += 1; | ||
| 3433 | defer p.depths[def_index] -= 1; | ||
| 3434 | return blk_0: { | ||
| 3435 | const pos_0 = p.i; | ||
| 3436 | if (blk_1: { | ||
| 3437 | if (std.mem.startsWith(u8, p.source[p.i..], "\\\\")) { | ||
| 3438 | p.i += 2; | ||
| 3439 | break :blk_1 true; | ||
| 3440 | } | ||
| 3441 | break :blk_1 false; | ||
| 3442 | }) break :blk_0 true; | ||
| 3443 | p.i = pos_0; | ||
| 3444 | if (blk_1: { | ||
| 3445 | if (std.mem.startsWith(u8, p.source[p.i..], "\\'")) { | ||
| 3446 | p.i += 2; | ||
| 3447 | break :blk_1 true; | ||
| 3448 | } | ||
| 3449 | break :blk_1 false; | ||
| 3450 | }) break :blk_0 true; | ||
| 3451 | p.i = pos_0; | ||
| 3452 | if (blk_1: { | ||
| 3453 | const pos_1 = p.i; | ||
| 3454 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3455 | '\''...'\'', | ||
| 3456 | => blk_2: { | ||
| 3457 | p.i += 1; | ||
| 3458 | break :blk_2 true; | ||
| 3459 | }, | ||
| 3460 | else => false, | ||
| 3461 | }); | ||
| 3462 | p.i = pos_1; | ||
| 3463 | break :blk_1 !match_1; | ||
| 3464 | } and try p.parsenon_control_utf8()) break :blk_0 true; | ||
| 3465 | p.i = pos_0; | ||
| 3466 | break :blk_0 false; | ||
| 3467 | }; | ||
| 3468 | } | ||
| 3469 | pub fn parsestring_char(p: *Parser) Error!bool { | ||
| 3470 | const def_index = @intFromEnum(Def.defstring_char); | ||
| 3471 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3472 | p.depths[def_index] += 1; | ||
| 3473 | defer p.depths[def_index] -= 1; | ||
| 3474 | return blk_0: { | ||
| 3475 | const pos_0 = p.i; | ||
| 3476 | if (blk_1: { | ||
| 3477 | if (std.mem.startsWith(u8, p.source[p.i..], "\\\\")) { | ||
| 3478 | p.i += 2; | ||
| 3479 | break :blk_1 true; | ||
| 3480 | } | ||
| 3481 | break :blk_1 false; | ||
| 3482 | }) break :blk_0 true; | ||
| 3483 | p.i = pos_0; | ||
| 3484 | if (blk_1: { | ||
| 3485 | if (std.mem.startsWith(u8, p.source[p.i..], "\\\"")) { | ||
| 3486 | p.i += 2; | ||
| 3487 | break :blk_1 true; | ||
| 3488 | } | ||
| 3489 | break :blk_1 false; | ||
| 3490 | }) break :blk_0 true; | ||
| 3491 | p.i = pos_0; | ||
| 3492 | if (blk_1: { | ||
| 3493 | const pos_1 = p.i; | ||
| 3494 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3495 | '"'...'"', | ||
| 3496 | => blk_2: { | ||
| 3497 | p.i += 1; | ||
| 3498 | break :blk_2 true; | ||
| 3499 | }, | ||
| 3500 | else => false, | ||
| 3501 | }); | ||
| 3502 | p.i = pos_1; | ||
| 3503 | break :blk_1 !match_1; | ||
| 3504 | } and try p.parsenon_control_utf8()) break :blk_0 true; | ||
| 3505 | p.i = pos_0; | ||
| 3506 | break :blk_0 false; | ||
| 3507 | }; | ||
| 3508 | } | ||
| 3509 | pub fn parsecontainer_doc_comment(p: *Parser) Error!bool { | ||
| 3510 | const def_index = @intFromEnum(Def.defcontainer_doc_comment); | ||
| 3511 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3512 | p.depths[def_index] += 1; | ||
| 3513 | defer p.depths[def_index] -= 1; | ||
| 3514 | return blk_0: { | ||
| 3515 | const pos_0 = p.i; | ||
| 3516 | if (blk_1: { | ||
| 3517 | var match_1 = false; | ||
| 3518 | var i_1: usize = 0; | ||
| 3519 | while (blk_3: { | ||
| 3520 | const pos_3 = p.i; | ||
| 3521 | if (try p.parseskip() and blk_4: { | ||
| 3522 | if (std.mem.startsWith(u8, p.source[p.i..], "//!")) { | ||
| 3523 | p.i += 3; | ||
| 3524 | break :blk_4 true; | ||
| 3525 | } | ||
| 3526 | break :blk_4 false; | ||
| 3527 | } and blk_4: { | ||
| 3528 | var i_4: usize = 0; | ||
| 3529 | while (try p.parsenon_control_utf8()) { | ||
| 3530 | if (i_4 > max_depth) return error.MaxDepth; | ||
| 3531 | i_4 += 1; | ||
| 3532 | } | ||
| 3533 | break :blk_4 true; | ||
| 3534 | } and try p.parsenewline()) break :blk_3 true; | ||
| 3535 | p.i = pos_3; | ||
| 3536 | break :blk_3 false; | ||
| 3537 | }) { | ||
| 3538 | match_1 = true; | ||
| 3539 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3540 | i_1 += 1; | ||
| 3541 | } | ||
| 3542 | break :blk_1 match_1; | ||
| 3543 | }) break :blk_0 true; | ||
| 3544 | p.i = pos_0; | ||
| 3545 | break :blk_0 false; | ||
| 3546 | }; | ||
| 3547 | } | ||
| 3548 | pub fn parsedoc_comment(p: *Parser) Error!bool { | ||
| 3549 | const def_index = @intFromEnum(Def.defdoc_comment); | ||
| 3550 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3551 | p.depths[def_index] += 1; | ||
| 3552 | defer p.depths[def_index] -= 1; | ||
| 3553 | return blk_0: { | ||
| 3554 | const pos_0 = p.i; | ||
| 3555 | if (blk_2: { | ||
| 3556 | const pos_2 = p.i; | ||
| 3557 | if (try p.parsesof()) break :blk_2 true; | ||
| 3558 | p.i = pos_2; | ||
| 3559 | if (try p.parseskip_require_newline()) break :blk_2 true; | ||
| 3560 | p.i = pos_2; | ||
| 3561 | break :blk_2 false; | ||
| 3562 | } and blk_1: { | ||
| 3563 | var match_1 = false; | ||
| 3564 | var i_1: usize = 0; | ||
| 3565 | while (blk_3: { | ||
| 3566 | const pos_3 = p.i; | ||
| 3567 | if (try p.parseskip() and blk_4: { | ||
| 3568 | if (std.mem.startsWith(u8, p.source[p.i..], "///")) { | ||
| 3569 | p.i += 3; | ||
| 3570 | break :blk_4 true; | ||
| 3571 | } | ||
| 3572 | break :blk_4 false; | ||
| 3573 | } and blk_4: { | ||
| 3574 | var i_4: usize = 0; | ||
| 3575 | while (try p.parsenon_control_utf8()) { | ||
| 3576 | if (i_4 > max_depth) return error.MaxDepth; | ||
| 3577 | i_4 += 1; | ||
| 3578 | } | ||
| 3579 | break :blk_4 true; | ||
| 3580 | } and try p.parsenewline()) break :blk_3 true; | ||
| 3581 | p.i = pos_3; | ||
| 3582 | break :blk_3 false; | ||
| 3583 | }) { | ||
| 3584 | match_1 = true; | ||
| 3585 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3586 | i_1 += 1; | ||
| 3587 | } | ||
| 3588 | break :blk_1 match_1; | ||
| 3589 | }) break :blk_0 true; | ||
| 3590 | p.i = pos_0; | ||
| 3591 | break :blk_0 false; | ||
| 3592 | }; | ||
| 3593 | } | ||
| 3594 | pub fn parseline_comment(p: *Parser) Error!bool { | ||
| 3595 | const def_index = @intFromEnum(Def.defline_comment); | ||
| 3596 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3597 | p.depths[def_index] += 1; | ||
| 3598 | defer p.depths[def_index] -= 1; | ||
| 3599 | return blk_0: { | ||
| 3600 | const pos_0 = p.i; | ||
| 3601 | if (blk_1: { | ||
| 3602 | if (std.mem.startsWith(u8, p.source[p.i..], "//")) { | ||
| 3603 | p.i += 2; | ||
| 3604 | break :blk_1 true; | ||
| 3605 | } | ||
| 3606 | break :blk_1 false; | ||
| 3607 | } and blk_1: { | ||
| 3608 | const pos_1 = p.i; | ||
| 3609 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3610 | '!'...'!', | ||
| 3611 | '/'...'/', | ||
| 3612 | => blk_2: { | ||
| 3613 | p.i += 1; | ||
| 3614 | break :blk_2 true; | ||
| 3615 | }, | ||
| 3616 | else => false, | ||
| 3617 | }); | ||
| 3618 | p.i = pos_1; | ||
| 3619 | break :blk_1 !match_1; | ||
| 3620 | } and blk_1: { | ||
| 3621 | var i_1: usize = 0; | ||
| 3622 | while (try p.parsenon_control_utf8()) { | ||
| 3623 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3624 | i_1 += 1; | ||
| 3625 | } | ||
| 3626 | break :blk_1 true; | ||
| 3627 | } and try p.parsenewline()) break :blk_0 true; | ||
| 3628 | p.i = pos_0; | ||
| 3629 | if (blk_1: { | ||
| 3630 | if (std.mem.startsWith(u8, p.source[p.i..], "////")) { | ||
| 3631 | p.i += 4; | ||
| 3632 | break :blk_1 true; | ||
| 3633 | } | ||
| 3634 | break :blk_1 false; | ||
| 3635 | } and blk_1: { | ||
| 3636 | var i_1: usize = 0; | ||
| 3637 | while (try p.parsenon_control_utf8()) { | ||
| 3638 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3639 | i_1 += 1; | ||
| 3640 | } | ||
| 3641 | break :blk_1 true; | ||
| 3642 | } and try p.parsenewline()) break :blk_0 true; | ||
| 3643 | p.i = pos_0; | ||
| 3644 | break :blk_0 false; | ||
| 3645 | }; | ||
| 3646 | } | ||
| 3647 | pub fn parseline_string(p: *Parser) Error!bool { | ||
| 3648 | const def_index = @intFromEnum(Def.defline_string); | ||
| 3649 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3650 | p.depths[def_index] += 1; | ||
| 3651 | defer p.depths[def_index] -= 1; | ||
| 3652 | return blk_0: { | ||
| 3653 | const pos_0 = p.i; | ||
| 3654 | if (blk_1: { | ||
| 3655 | if (std.mem.startsWith(u8, p.source[p.i..], "\\\\")) { | ||
| 3656 | p.i += 2; | ||
| 3657 | break :blk_1 true; | ||
| 3658 | } | ||
| 3659 | break :blk_1 false; | ||
| 3660 | } and blk_1: { | ||
| 3661 | var i_1: usize = 0; | ||
| 3662 | while (try p.parsenon_control_utf8()) { | ||
| 3663 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3664 | i_1 += 1; | ||
| 3665 | } | ||
| 3666 | break :blk_1 true; | ||
| 3667 | } and try p.parsenewline()) break :blk_0 true; | ||
| 3668 | p.i = pos_0; | ||
| 3669 | break :blk_0 false; | ||
| 3670 | }; | ||
| 3671 | } | ||
| 3672 | pub fn parsenewline(p: *Parser) Error!bool { | ||
| 3673 | const def_index = @intFromEnum(Def.defnewline); | ||
| 3674 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3675 | p.depths[def_index] += 1; | ||
| 3676 | defer p.depths[def_index] -= 1; | ||
| 3677 | return blk_0: { | ||
| 3678 | const pos_0 = p.i; | ||
| 3679 | if (blk_1: { | ||
| 3680 | const pos_1 = p.i; | ||
| 3681 | const match_1 = blk_3: { | ||
| 3682 | const pos_3 = p.i; | ||
| 3683 | if (blk_4: { | ||
| 3684 | if (std.mem.startsWith(u8, p.source[p.i..], "\n")) { | ||
| 3685 | p.i += 1; | ||
| 3686 | break :blk_4 true; | ||
| 3687 | } | ||
| 3688 | break :blk_4 false; | ||
| 3689 | }) break :blk_3 true; | ||
| 3690 | p.i = pos_3; | ||
| 3691 | if (blk_4: { | ||
| 3692 | if (std.mem.startsWith(u8, p.source[p.i..], "\r\n")) { | ||
| 3693 | p.i += 2; | ||
| 3694 | break :blk_4 true; | ||
| 3695 | } | ||
| 3696 | break :blk_4 false; | ||
| 3697 | }) break :blk_3 true; | ||
| 3698 | p.i = pos_3; | ||
| 3699 | if (try p.parseeof()) break :blk_3 true; | ||
| 3700 | p.i = pos_3; | ||
| 3701 | break :blk_3 false; | ||
| 3702 | }; | ||
| 3703 | p.i = pos_1; | ||
| 3704 | break :blk_1 match_1; | ||
| 3705 | }) break :blk_0 true; | ||
| 3706 | p.i = pos_0; | ||
| 3707 | break :blk_0 false; | ||
| 3708 | }; | ||
| 3709 | } | ||
| 3710 | pub fn parseskip(p: *Parser) Error!bool { | ||
| 3711 | const def_index = @intFromEnum(Def.defskip); | ||
| 3712 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3713 | p.depths[def_index] += 1; | ||
| 3714 | defer p.depths[def_index] -= 1; | ||
| 3715 | return blk_0: { | ||
| 3716 | const pos_0 = p.i; | ||
| 3717 | if ((try p.parsesof() or true) and blk_1: { | ||
| 3718 | var i_1: usize = 0; | ||
| 3719 | while (blk_3: { | ||
| 3720 | const pos_3 = p.i; | ||
| 3721 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3722 | ' '...' ', | ||
| 3723 | '\n'...'\n', | ||
| 3724 | '\t'...'\t', | ||
| 3725 | '\r'...'\r', | ||
| 3726 | => blk_4: { | ||
| 3727 | p.i += 1; | ||
| 3728 | break :blk_4 true; | ||
| 3729 | }, | ||
| 3730 | else => false, | ||
| 3731 | })) break :blk_3 true; | ||
| 3732 | p.i = pos_3; | ||
| 3733 | if (try p.parseline_comment()) break :blk_3 true; | ||
| 3734 | p.i = pos_3; | ||
| 3735 | break :blk_3 false; | ||
| 3736 | }) { | ||
| 3737 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3738 | i_1 += 1; | ||
| 3739 | } | ||
| 3740 | break :blk_1 true; | ||
| 3741 | }) break :blk_0 true; | ||
| 3742 | p.i = pos_0; | ||
| 3743 | break :blk_0 false; | ||
| 3744 | }; | ||
| 3745 | } | ||
| 3746 | pub fn parseskip_require_newline(p: *Parser) Error!bool { | ||
| 3747 | const def_index = @intFromEnum(Def.defskip_require_newline); | ||
| 3748 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3749 | p.depths[def_index] += 1; | ||
| 3750 | defer p.depths[def_index] -= 1; | ||
| 3751 | return blk_0: { | ||
| 3752 | const pos_0 = p.i; | ||
| 3753 | if (blk_1: { | ||
| 3754 | var i_1: usize = 0; | ||
| 3755 | while ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3756 | ' '...' ', | ||
| 3757 | '\t'...'\t', | ||
| 3758 | '\r'...'\r', | ||
| 3759 | => blk_2: { | ||
| 3760 | p.i += 1; | ||
| 3761 | break :blk_2 true; | ||
| 3762 | }, | ||
| 3763 | else => false, | ||
| 3764 | })) { | ||
| 3765 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3766 | i_1 += 1; | ||
| 3767 | } | ||
| 3768 | break :blk_1 true; | ||
| 3769 | } and blk_2: { | ||
| 3770 | const pos_2 = p.i; | ||
| 3771 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3772 | '\n'...'\n', | ||
| 3773 | => blk_3: { | ||
| 3774 | p.i += 1; | ||
| 3775 | break :blk_3 true; | ||
| 3776 | }, | ||
| 3777 | else => false, | ||
| 3778 | })) break :blk_2 true; | ||
| 3779 | p.i = pos_2; | ||
| 3780 | if (try p.parseline_comment()) break :blk_2 true; | ||
| 3781 | p.i = pos_2; | ||
| 3782 | break :blk_2 false; | ||
| 3783 | } and try p.parseskip()) break :blk_0 true; | ||
| 3784 | p.i = pos_0; | ||
| 3785 | break :blk_0 false; | ||
| 3786 | }; | ||
| 3787 | } | ||
| 3788 | pub fn parsepre_op_white(p: *Parser) Error!bool { | ||
| 3789 | const def_index = @intFromEnum(Def.defpre_op_white); | ||
| 3790 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3791 | p.depths[def_index] += 1; | ||
| 3792 | defer p.depths[def_index] -= 1; | ||
| 3793 | return blk_0: { | ||
| 3794 | const pos_0 = p.i; | ||
| 3795 | if (blk_1: { | ||
| 3796 | var match_1 = false; | ||
| 3797 | var i_1: usize = 0; | ||
| 3798 | while (blk_3: { | ||
| 3799 | const pos_3 = p.i; | ||
| 3800 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3801 | ' '...' ', | ||
| 3802 | '\n'...'\n', | ||
| 3803 | '\t'...'\t', | ||
| 3804 | '\r'...'\r', | ||
| 3805 | => blk_4: { | ||
| 3806 | p.i += 1; | ||
| 3807 | break :blk_4 true; | ||
| 3808 | }, | ||
| 3809 | else => false, | ||
| 3810 | })) break :blk_3 true; | ||
| 3811 | p.i = pos_3; | ||
| 3812 | if (try p.parseline_comment()) break :blk_3 true; | ||
| 3813 | p.i = pos_3; | ||
| 3814 | break :blk_3 false; | ||
| 3815 | }) { | ||
| 3816 | match_1 = true; | ||
| 3817 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3818 | i_1 += 1; | ||
| 3819 | } | ||
| 3820 | break :blk_1 match_1; | ||
| 3821 | }) break :blk_0 true; | ||
| 3822 | p.i = pos_0; | ||
| 3823 | break :blk_0 false; | ||
| 3824 | }; | ||
| 3825 | } | ||
| 3826 | pub fn parsepost_op_white(p: *Parser) Error!bool { | ||
| 3827 | const def_index = @intFromEnum(Def.defpost_op_white); | ||
| 3828 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3829 | p.depths[def_index] += 1; | ||
| 3830 | defer p.depths[def_index] -= 1; | ||
| 3831 | return blk_0: { | ||
| 3832 | const pos_0 = p.i; | ||
| 3833 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3834 | ' '...' ', | ||
| 3835 | '\n'...'\n', | ||
| 3836 | '\t'...'\t', | ||
| 3837 | '\r'...'\r', | ||
| 3838 | => blk_1: { | ||
| 3839 | p.i += 1; | ||
| 3840 | break :blk_1 true; | ||
| 3841 | }, | ||
| 3842 | else => false, | ||
| 3843 | }) and try p.parseskip()) break :blk_0 true; | ||
| 3844 | p.i = pos_0; | ||
| 3845 | break :blk_0 false; | ||
| 3846 | }; | ||
| 3847 | } | ||
| 3848 | pub fn parseCHAR_LITERAL(p: *Parser) Error!bool { | ||
| 3849 | const def_index = @intFromEnum(Def.defCHAR_LITERAL); | ||
| 3850 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3851 | p.depths[def_index] += 1; | ||
| 3852 | defer p.depths[def_index] -= 1; | ||
| 3853 | return blk_0: { | ||
| 3854 | const pos_0 = p.i; | ||
| 3855 | if (try p.parseskip() and (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3856 | '\''...'\'', | ||
| 3857 | => blk_1: { | ||
| 3858 | p.i += 1; | ||
| 3859 | break :blk_1 true; | ||
| 3860 | }, | ||
| 3861 | else => false, | ||
| 3862 | }) and blk_1: { | ||
| 3863 | var i_1: usize = 0; | ||
| 3864 | while (try p.parsechar_char()) { | ||
| 3865 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3866 | i_1 += 1; | ||
| 3867 | } | ||
| 3868 | break :blk_1 true; | ||
| 3869 | } and (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3870 | '\''...'\'', | ||
| 3871 | => blk_1: { | ||
| 3872 | p.i += 1; | ||
| 3873 | break :blk_1 true; | ||
| 3874 | }, | ||
| 3875 | else => false, | ||
| 3876 | })) break :blk_0 true; | ||
| 3877 | p.i = pos_0; | ||
| 3878 | break :blk_0 false; | ||
| 3879 | }; | ||
| 3880 | } | ||
| 3881 | pub fn parsedigit(p: *Parser) Error!bool { | ||
| 3882 | const def_index = @intFromEnum(Def.defdigit); | ||
| 3883 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3884 | p.depths[def_index] += 1; | ||
| 3885 | defer p.depths[def_index] -= 1; | ||
| 3886 | return blk_0: { | ||
| 3887 | const pos_0 = p.i; | ||
| 3888 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3889 | '_'...'_', | ||
| 3890 | '0'...'9', | ||
| 3891 | 'A'...'D', | ||
| 3892 | 'F'...'O', | ||
| 3893 | 'Q'...'Z', | ||
| 3894 | 'a'...'d', | ||
| 3895 | 'f'...'o', | ||
| 3896 | 'q'...'z', | ||
| 3897 | => blk_1: { | ||
| 3898 | p.i += 1; | ||
| 3899 | break :blk_1 true; | ||
| 3900 | }, | ||
| 3901 | else => false, | ||
| 3902 | })) break :blk_0 true; | ||
| 3903 | p.i = pos_0; | ||
| 3904 | break :blk_0 false; | ||
| 3905 | }; | ||
| 3906 | } | ||
| 3907 | pub fn parsedigit_int(p: *Parser) Error!bool { | ||
| 3908 | const def_index = @intFromEnum(Def.defdigit_int); | ||
| 3909 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3910 | p.depths[def_index] += 1; | ||
| 3911 | defer p.depths[def_index] -= 1; | ||
| 3912 | return blk_0: { | ||
| 3913 | const pos_0 = p.i; | ||
| 3914 | if (try p.parsedigit()) break :blk_0 true; | ||
| 3915 | p.i = pos_0; | ||
| 3916 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3917 | 'e'...'e', | ||
| 3918 | 'E'...'E', | ||
| 3919 | 'p'...'p', | ||
| 3920 | 'P'...'P', | ||
| 3921 | => blk_1: { | ||
| 3922 | p.i += 1; | ||
| 3923 | break :blk_1 true; | ||
| 3924 | }, | ||
| 3925 | else => false, | ||
| 3926 | })) break :blk_0 true; | ||
| 3927 | p.i = pos_0; | ||
| 3928 | break :blk_0 false; | ||
| 3929 | }; | ||
| 3930 | } | ||
| 3931 | pub fn parsedigit_float(p: *Parser) Error!bool { | ||
| 3932 | const def_index = @intFromEnum(Def.defdigit_float); | ||
| 3933 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3934 | p.depths[def_index] += 1; | ||
| 3935 | defer p.depths[def_index] -= 1; | ||
| 3936 | return blk_0: { | ||
| 3937 | const pos_0 = p.i; | ||
| 3938 | if (try p.parsedigit()) break :blk_0 true; | ||
| 3939 | p.i = pos_0; | ||
| 3940 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3941 | 'e'...'e', | ||
| 3942 | 'E'...'E', | ||
| 3943 | 'p'...'p', | ||
| 3944 | 'P'...'P', | ||
| 3945 | => blk_1: { | ||
| 3946 | p.i += 1; | ||
| 3947 | break :blk_1 true; | ||
| 3948 | }, | ||
| 3949 | else => false, | ||
| 3950 | }) and ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3951 | '-'...'-', | ||
| 3952 | '+'...'+', | ||
| 3953 | => blk_2: { | ||
| 3954 | p.i += 1; | ||
| 3955 | break :blk_2 true; | ||
| 3956 | }, | ||
| 3957 | else => false, | ||
| 3958 | }) or true)) break :blk_0 true; | ||
| 3959 | p.i = pos_0; | ||
| 3960 | break :blk_0 false; | ||
| 3961 | }; | ||
| 3962 | } | ||
| 3963 | pub fn parseNUMBERLITERAL(p: *Parser) Error!bool { | ||
| 3964 | const def_index = @intFromEnum(Def.defNUMBERLITERAL); | ||
| 3965 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 3966 | p.depths[def_index] += 1; | ||
| 3967 | defer p.depths[def_index] -= 1; | ||
| 3968 | return blk_0: { | ||
| 3969 | const pos_0 = p.i; | ||
| 3970 | if (try p.parseskip() and (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 3971 | '0'...'9', | ||
| 3972 | => blk_1: { | ||
| 3973 | p.i += 1; | ||
| 3974 | break :blk_1 true; | ||
| 3975 | }, | ||
| 3976 | else => false, | ||
| 3977 | }) and blk_1: { | ||
| 3978 | var i_1: usize = 0; | ||
| 3979 | while (try p.parsedigit_int()) { | ||
| 3980 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3981 | i_1 += 1; | ||
| 3982 | } | ||
| 3983 | break :blk_1 true; | ||
| 3984 | } and blk_1: { | ||
| 3985 | if (std.mem.startsWith(u8, p.source[p.i..], ".")) { | ||
| 3986 | p.i += 1; | ||
| 3987 | break :blk_1 true; | ||
| 3988 | } | ||
| 3989 | break :blk_1 false; | ||
| 3990 | } and blk_1: { | ||
| 3991 | var match_1 = false; | ||
| 3992 | var i_1: usize = 0; | ||
| 3993 | while (try p.parsedigit_float()) { | ||
| 3994 | match_1 = true; | ||
| 3995 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 3996 | i_1 += 1; | ||
| 3997 | } | ||
| 3998 | break :blk_1 match_1; | ||
| 3999 | }) break :blk_0 true; | ||
| 4000 | p.i = pos_0; | ||
| 4001 | if (try p.parseskip() and (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4002 | '0'...'9', | ||
| 4003 | => blk_1: { | ||
| 4004 | p.i += 1; | ||
| 4005 | break :blk_1 true; | ||
| 4006 | }, | ||
| 4007 | else => false, | ||
| 4008 | }) and blk_1: { | ||
| 4009 | var i_1: usize = 0; | ||
| 4010 | while (try p.parsedigit_float()) { | ||
| 4011 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 4012 | i_1 += 1; | ||
| 4013 | } | ||
| 4014 | break :blk_1 true; | ||
| 4015 | }) break :blk_0 true; | ||
| 4016 | p.i = pos_0; | ||
| 4017 | break :blk_0 false; | ||
| 4018 | }; | ||
| 4019 | } | ||
| 4020 | pub fn parsestring(p: *Parser) Error!bool { | ||
| 4021 | const def_index = @intFromEnum(Def.defstring); | ||
| 4022 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4023 | p.depths[def_index] += 1; | ||
| 4024 | defer p.depths[def_index] -= 1; | ||
| 4025 | return blk_0: { | ||
| 4026 | const pos_0 = p.i; | ||
| 4027 | if ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4028 | '"'...'"', | ||
| 4029 | => blk_1: { | ||
| 4030 | p.i += 1; | ||
| 4031 | break :blk_1 true; | ||
| 4032 | }, | ||
| 4033 | else => false, | ||
| 4034 | }) and blk_1: { | ||
| 4035 | var i_1: usize = 0; | ||
| 4036 | while (try p.parsestring_char()) { | ||
| 4037 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 4038 | i_1 += 1; | ||
| 4039 | } | ||
| 4040 | break :blk_1 true; | ||
| 4041 | } and (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4042 | '"'...'"', | ||
| 4043 | => blk_1: { | ||
| 4044 | p.i += 1; | ||
| 4045 | break :blk_1 true; | ||
| 4046 | }, | ||
| 4047 | else => false, | ||
| 4048 | })) break :blk_0 true; | ||
| 4049 | p.i = pos_0; | ||
| 4050 | break :blk_0 false; | ||
| 4051 | }; | ||
| 4052 | } | ||
| 4053 | pub fn parseSTRINGLITERALSINGLE(p: *Parser) Error!bool { | ||
| 4054 | const def_index = @intFromEnum(Def.defSTRINGLITERALSINGLE); | ||
| 4055 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4056 | p.depths[def_index] += 1; | ||
| 4057 | defer p.depths[def_index] -= 1; | ||
| 4058 | return blk_0: { | ||
| 4059 | const pos_0 = p.i; | ||
| 4060 | if (try p.parseskip() and try p.parsestring()) break :blk_0 true; | ||
| 4061 | p.i = pos_0; | ||
| 4062 | break :blk_0 false; | ||
| 4063 | }; | ||
| 4064 | } | ||
| 4065 | pub fn parseSTRINGLITERAL(p: *Parser) Error!bool { | ||
| 4066 | const def_index = @intFromEnum(Def.defSTRINGLITERAL); | ||
| 4067 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4068 | p.depths[def_index] += 1; | ||
| 4069 | defer p.depths[def_index] -= 1; | ||
| 4070 | return blk_0: { | ||
| 4071 | const pos_0 = p.i; | ||
| 4072 | if (try p.parseskip() and try p.parsestring()) break :blk_0 true; | ||
| 4073 | p.i = pos_0; | ||
| 4074 | if (blk_1: { | ||
| 4075 | var match_1 = false; | ||
| 4076 | var i_1: usize = 0; | ||
| 4077 | while (blk_3: { | ||
| 4078 | const pos_3 = p.i; | ||
| 4079 | if (try p.parseskip() and try p.parseline_string()) break :blk_3 true; | ||
| 4080 | p.i = pos_3; | ||
| 4081 | break :blk_3 false; | ||
| 4082 | }) { | ||
| 4083 | match_1 = true; | ||
| 4084 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 4085 | i_1 += 1; | ||
| 4086 | } | ||
| 4087 | break :blk_1 match_1; | ||
| 4088 | }) break :blk_0 true; | ||
| 4089 | p.i = pos_0; | ||
| 4090 | break :blk_0 false; | ||
| 4091 | }; | ||
| 4092 | } | ||
| 4093 | pub fn parseIDENTIFIER(p: *Parser) Error!bool { | ||
| 4094 | const def_index = @intFromEnum(Def.defIDENTIFIER); | ||
| 4095 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4096 | p.depths[def_index] += 1; | ||
| 4097 | defer p.depths[def_index] -= 1; | ||
| 4098 | return blk_0: { | ||
| 4099 | const pos_0 = p.i; | ||
| 4100 | if (try p.parseskip() and blk_1: { | ||
| 4101 | const pos_1 = p.i; | ||
| 4102 | const match_1 = try p.parsekeyword(); | ||
| 4103 | p.i = pos_1; | ||
| 4104 | break :blk_1 !match_1; | ||
| 4105 | } and (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4106 | 'A'...'Z', | ||
| 4107 | 'a'...'z', | ||
| 4108 | '_'...'_', | ||
| 4109 | => blk_1: { | ||
| 4110 | p.i += 1; | ||
| 4111 | break :blk_1 true; | ||
| 4112 | }, | ||
| 4113 | else => false, | ||
| 4114 | }) and blk_1: { | ||
| 4115 | var i_1: usize = 0; | ||
| 4116 | while ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4117 | 'A'...'Z', | ||
| 4118 | 'a'...'z', | ||
| 4119 | '0'...'9', | ||
| 4120 | '_'...'_', | ||
| 4121 | => blk_2: { | ||
| 4122 | p.i += 1; | ||
| 4123 | break :blk_2 true; | ||
| 4124 | }, | ||
| 4125 | else => false, | ||
| 4126 | })) { | ||
| 4127 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 4128 | i_1 += 1; | ||
| 4129 | } | ||
| 4130 | break :blk_1 true; | ||
| 4131 | }) break :blk_0 true; | ||
| 4132 | p.i = pos_0; | ||
| 4133 | if (try p.parseskip() and blk_1: { | ||
| 4134 | if (std.mem.startsWith(u8, p.source[p.i..], "@")) { | ||
| 4135 | p.i += 1; | ||
| 4136 | break :blk_1 true; | ||
| 4137 | } | ||
| 4138 | break :blk_1 false; | ||
| 4139 | } and try p.parsestring()) break :blk_0 true; | ||
| 4140 | p.i = pos_0; | ||
| 4141 | break :blk_0 false; | ||
| 4142 | }; | ||
| 4143 | } | ||
| 4144 | pub fn parseBUILTINIDENTIFIER(p: *Parser) Error!bool { | ||
| 4145 | const def_index = @intFromEnum(Def.defBUILTINIDENTIFIER); | ||
| 4146 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4147 | p.depths[def_index] += 1; | ||
| 4148 | defer p.depths[def_index] -= 1; | ||
| 4149 | return blk_0: { | ||
| 4150 | const pos_0 = p.i; | ||
| 4151 | if (try p.parseskip() and blk_1: { | ||
| 4152 | if (std.mem.startsWith(u8, p.source[p.i..], "@")) { | ||
| 4153 | p.i += 1; | ||
| 4154 | break :blk_1 true; | ||
| 4155 | } | ||
| 4156 | break :blk_1 false; | ||
| 4157 | } and (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4158 | 'A'...'Z', | ||
| 4159 | 'a'...'z', | ||
| 4160 | '_'...'_', | ||
| 4161 | => blk_1: { | ||
| 4162 | p.i += 1; | ||
| 4163 | break :blk_1 true; | ||
| 4164 | }, | ||
| 4165 | else => false, | ||
| 4166 | }) and blk_1: { | ||
| 4167 | var i_1: usize = 0; | ||
| 4168 | while ((p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4169 | 'A'...'Z', | ||
| 4170 | 'a'...'z', | ||
| 4171 | '0'...'9', | ||
| 4172 | '_'...'_', | ||
| 4173 | => blk_2: { | ||
| 4174 | p.i += 1; | ||
| 4175 | break :blk_2 true; | ||
| 4176 | }, | ||
| 4177 | else => false, | ||
| 4178 | })) { | ||
| 4179 | if (i_1 > max_depth) return error.MaxDepth; | ||
| 4180 | i_1 += 1; | ||
| 4181 | } | ||
| 4182 | break :blk_1 true; | ||
| 4183 | }) break :blk_0 true; | ||
| 4184 | p.i = pos_0; | ||
| 4185 | break :blk_0 false; | ||
| 4186 | }; | ||
| 4187 | } | ||
| 4188 | pub fn parseAMPERSAND(p: *Parser) Error!bool { | ||
| 4189 | const def_index = @intFromEnum(Def.defAMPERSAND); | ||
| 4190 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4191 | p.depths[def_index] += 1; | ||
| 4192 | defer p.depths[def_index] -= 1; | ||
| 4193 | return blk_0: { | ||
| 4194 | const pos_0 = p.i; | ||
| 4195 | if (try p.parseskip() and blk_1: { | ||
| 4196 | if (std.mem.startsWith(u8, p.source[p.i..], "&")) { | ||
| 4197 | p.i += 1; | ||
| 4198 | break :blk_1 true; | ||
| 4199 | } | ||
| 4200 | break :blk_1 false; | ||
| 4201 | } and blk_1: { | ||
| 4202 | const pos_1 = p.i; | ||
| 4203 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4204 | '='...'=', | ||
| 4205 | => blk_2: { | ||
| 4206 | p.i += 1; | ||
| 4207 | break :blk_2 true; | ||
| 4208 | }, | ||
| 4209 | else => false, | ||
| 4210 | }); | ||
| 4211 | p.i = pos_1; | ||
| 4212 | break :blk_1 !match_1; | ||
| 4213 | }) break :blk_0 true; | ||
| 4214 | p.i = pos_0; | ||
| 4215 | break :blk_0 false; | ||
| 4216 | }; | ||
| 4217 | } | ||
| 4218 | pub fn parseAMPERSANDEQUAL(p: *Parser) Error!bool { | ||
| 4219 | const def_index = @intFromEnum(Def.defAMPERSANDEQUAL); | ||
| 4220 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4221 | p.depths[def_index] += 1; | ||
| 4222 | defer p.depths[def_index] -= 1; | ||
| 4223 | return blk_0: { | ||
| 4224 | const pos_0 = p.i; | ||
| 4225 | if (try p.parseskip() and blk_1: { | ||
| 4226 | if (std.mem.startsWith(u8, p.source[p.i..], "&=")) { | ||
| 4227 | p.i += 2; | ||
| 4228 | break :blk_1 true; | ||
| 4229 | } | ||
| 4230 | break :blk_1 false; | ||
| 4231 | }) break :blk_0 true; | ||
| 4232 | p.i = pos_0; | ||
| 4233 | break :blk_0 false; | ||
| 4234 | }; | ||
| 4235 | } | ||
| 4236 | pub fn parseASTERISK(p: *Parser) Error!bool { | ||
| 4237 | const def_index = @intFromEnum(Def.defASTERISK); | ||
| 4238 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4239 | p.depths[def_index] += 1; | ||
| 4240 | defer p.depths[def_index] -= 1; | ||
| 4241 | return blk_0: { | ||
| 4242 | const pos_0 = p.i; | ||
| 4243 | if (try p.parseskip() and blk_1: { | ||
| 4244 | if (std.mem.startsWith(u8, p.source[p.i..], "*")) { | ||
| 4245 | p.i += 1; | ||
| 4246 | break :blk_1 true; | ||
| 4247 | } | ||
| 4248 | break :blk_1 false; | ||
| 4249 | } and blk_1: { | ||
| 4250 | const pos_1 = p.i; | ||
| 4251 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4252 | '%'...'%', | ||
| 4253 | '='...'=', | ||
| 4254 | '|'...'|', | ||
| 4255 | => blk_2: { | ||
| 4256 | p.i += 1; | ||
| 4257 | break :blk_2 true; | ||
| 4258 | }, | ||
| 4259 | else => false, | ||
| 4260 | }); | ||
| 4261 | p.i = pos_1; | ||
| 4262 | break :blk_1 !match_1; | ||
| 4263 | }) break :blk_0 true; | ||
| 4264 | p.i = pos_0; | ||
| 4265 | break :blk_0 false; | ||
| 4266 | }; | ||
| 4267 | } | ||
| 4268 | pub fn parseASTERISKEQUAL(p: *Parser) Error!bool { | ||
| 4269 | const def_index = @intFromEnum(Def.defASTERISKEQUAL); | ||
| 4270 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4271 | p.depths[def_index] += 1; | ||
| 4272 | defer p.depths[def_index] -= 1; | ||
| 4273 | return blk_0: { | ||
| 4274 | const pos_0 = p.i; | ||
| 4275 | if (try p.parseskip() and blk_1: { | ||
| 4276 | if (std.mem.startsWith(u8, p.source[p.i..], "*=")) { | ||
| 4277 | p.i += 2; | ||
| 4278 | break :blk_1 true; | ||
| 4279 | } | ||
| 4280 | break :blk_1 false; | ||
| 4281 | }) break :blk_0 true; | ||
| 4282 | p.i = pos_0; | ||
| 4283 | break :blk_0 false; | ||
| 4284 | }; | ||
| 4285 | } | ||
| 4286 | pub fn parseASTERISKPERCENT(p: *Parser) Error!bool { | ||
| 4287 | const def_index = @intFromEnum(Def.defASTERISKPERCENT); | ||
| 4288 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4289 | p.depths[def_index] += 1; | ||
| 4290 | defer p.depths[def_index] -= 1; | ||
| 4291 | return blk_0: { | ||
| 4292 | const pos_0 = p.i; | ||
| 4293 | if (try p.parseskip() and blk_1: { | ||
| 4294 | if (std.mem.startsWith(u8, p.source[p.i..], "*%")) { | ||
| 4295 | p.i += 2; | ||
| 4296 | break :blk_1 true; | ||
| 4297 | } | ||
| 4298 | break :blk_1 false; | ||
| 4299 | } and blk_1: { | ||
| 4300 | const pos_1 = p.i; | ||
| 4301 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4302 | '='...'=', | ||
| 4303 | => blk_2: { | ||
| 4304 | p.i += 1; | ||
| 4305 | break :blk_2 true; | ||
| 4306 | }, | ||
| 4307 | else => false, | ||
| 4308 | }); | ||
| 4309 | p.i = pos_1; | ||
| 4310 | break :blk_1 !match_1; | ||
| 4311 | }) break :blk_0 true; | ||
| 4312 | p.i = pos_0; | ||
| 4313 | break :blk_0 false; | ||
| 4314 | }; | ||
| 4315 | } | ||
| 4316 | pub fn parseASTERISKPERCENTEQUAL(p: *Parser) Error!bool { | ||
| 4317 | const def_index = @intFromEnum(Def.defASTERISKPERCENTEQUAL); | ||
| 4318 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4319 | p.depths[def_index] += 1; | ||
| 4320 | defer p.depths[def_index] -= 1; | ||
| 4321 | return blk_0: { | ||
| 4322 | const pos_0 = p.i; | ||
| 4323 | if (try p.parseskip() and blk_1: { | ||
| 4324 | if (std.mem.startsWith(u8, p.source[p.i..], "*%=")) { | ||
| 4325 | p.i += 3; | ||
| 4326 | break :blk_1 true; | ||
| 4327 | } | ||
| 4328 | break :blk_1 false; | ||
| 4329 | }) break :blk_0 true; | ||
| 4330 | p.i = pos_0; | ||
| 4331 | break :blk_0 false; | ||
| 4332 | }; | ||
| 4333 | } | ||
| 4334 | pub fn parseASTERISKPIPE(p: *Parser) Error!bool { | ||
| 4335 | const def_index = @intFromEnum(Def.defASTERISKPIPE); | ||
| 4336 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4337 | p.depths[def_index] += 1; | ||
| 4338 | defer p.depths[def_index] -= 1; | ||
| 4339 | return blk_0: { | ||
| 4340 | const pos_0 = p.i; | ||
| 4341 | if (try p.parseskip() and blk_1: { | ||
| 4342 | if (std.mem.startsWith(u8, p.source[p.i..], "*|")) { | ||
| 4343 | p.i += 2; | ||
| 4344 | break :blk_1 true; | ||
| 4345 | } | ||
| 4346 | break :blk_1 false; | ||
| 4347 | } and blk_1: { | ||
| 4348 | const pos_1 = p.i; | ||
| 4349 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4350 | '='...'=', | ||
| 4351 | => blk_2: { | ||
| 4352 | p.i += 1; | ||
| 4353 | break :blk_2 true; | ||
| 4354 | }, | ||
| 4355 | else => false, | ||
| 4356 | }); | ||
| 4357 | p.i = pos_1; | ||
| 4358 | break :blk_1 !match_1; | ||
| 4359 | }) break :blk_0 true; | ||
| 4360 | p.i = pos_0; | ||
| 4361 | break :blk_0 false; | ||
| 4362 | }; | ||
| 4363 | } | ||
| 4364 | pub fn parseASTERISKPIPEEQUAL(p: *Parser) Error!bool { | ||
| 4365 | const def_index = @intFromEnum(Def.defASTERISKPIPEEQUAL); | ||
| 4366 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4367 | p.depths[def_index] += 1; | ||
| 4368 | defer p.depths[def_index] -= 1; | ||
| 4369 | return blk_0: { | ||
| 4370 | const pos_0 = p.i; | ||
| 4371 | if (try p.parseskip() and blk_1: { | ||
| 4372 | if (std.mem.startsWith(u8, p.source[p.i..], "*|=")) { | ||
| 4373 | p.i += 3; | ||
| 4374 | break :blk_1 true; | ||
| 4375 | } | ||
| 4376 | break :blk_1 false; | ||
| 4377 | }) break :blk_0 true; | ||
| 4378 | p.i = pos_0; | ||
| 4379 | break :blk_0 false; | ||
| 4380 | }; | ||
| 4381 | } | ||
| 4382 | pub fn parseCARET(p: *Parser) Error!bool { | ||
| 4383 | const def_index = @intFromEnum(Def.defCARET); | ||
| 4384 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4385 | p.depths[def_index] += 1; | ||
| 4386 | defer p.depths[def_index] -= 1; | ||
| 4387 | return blk_0: { | ||
| 4388 | const pos_0 = p.i; | ||
| 4389 | if (try p.parseskip() and blk_1: { | ||
| 4390 | if (std.mem.startsWith(u8, p.source[p.i..], "^")) { | ||
| 4391 | p.i += 1; | ||
| 4392 | break :blk_1 true; | ||
| 4393 | } | ||
| 4394 | break :blk_1 false; | ||
| 4395 | } and blk_1: { | ||
| 4396 | const pos_1 = p.i; | ||
| 4397 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4398 | '='...'=', | ||
| 4399 | => blk_2: { | ||
| 4400 | p.i += 1; | ||
| 4401 | break :blk_2 true; | ||
| 4402 | }, | ||
| 4403 | else => false, | ||
| 4404 | }); | ||
| 4405 | p.i = pos_1; | ||
| 4406 | break :blk_1 !match_1; | ||
| 4407 | }) break :blk_0 true; | ||
| 4408 | p.i = pos_0; | ||
| 4409 | break :blk_0 false; | ||
| 4410 | }; | ||
| 4411 | } | ||
| 4412 | pub fn parseCARETEQUAL(p: *Parser) Error!bool { | ||
| 4413 | const def_index = @intFromEnum(Def.defCARETEQUAL); | ||
| 4414 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4415 | p.depths[def_index] += 1; | ||
| 4416 | defer p.depths[def_index] -= 1; | ||
| 4417 | return blk_0: { | ||
| 4418 | const pos_0 = p.i; | ||
| 4419 | if (try p.parseskip() and blk_1: { | ||
| 4420 | if (std.mem.startsWith(u8, p.source[p.i..], "^=")) { | ||
| 4421 | p.i += 2; | ||
| 4422 | break :blk_1 true; | ||
| 4423 | } | ||
| 4424 | break :blk_1 false; | ||
| 4425 | }) break :blk_0 true; | ||
| 4426 | p.i = pos_0; | ||
| 4427 | break :blk_0 false; | ||
| 4428 | }; | ||
| 4429 | } | ||
| 4430 | pub fn parseCOLON(p: *Parser) Error!bool { | ||
| 4431 | const def_index = @intFromEnum(Def.defCOLON); | ||
| 4432 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4433 | p.depths[def_index] += 1; | ||
| 4434 | defer p.depths[def_index] -= 1; | ||
| 4435 | return blk_0: { | ||
| 4436 | const pos_0 = p.i; | ||
| 4437 | if (try p.parseskip() and blk_1: { | ||
| 4438 | if (std.mem.startsWith(u8, p.source[p.i..], ":")) { | ||
| 4439 | p.i += 1; | ||
| 4440 | break :blk_1 true; | ||
| 4441 | } | ||
| 4442 | break :blk_1 false; | ||
| 4443 | }) break :blk_0 true; | ||
| 4444 | p.i = pos_0; | ||
| 4445 | break :blk_0 false; | ||
| 4446 | }; | ||
| 4447 | } | ||
| 4448 | pub fn parseCOMMA(p: *Parser) Error!bool { | ||
| 4449 | const def_index = @intFromEnum(Def.defCOMMA); | ||
| 4450 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4451 | p.depths[def_index] += 1; | ||
| 4452 | defer p.depths[def_index] -= 1; | ||
| 4453 | return blk_0: { | ||
| 4454 | const pos_0 = p.i; | ||
| 4455 | if (try p.parseskip() and blk_1: { | ||
| 4456 | if (std.mem.startsWith(u8, p.source[p.i..], ",")) { | ||
| 4457 | p.i += 1; | ||
| 4458 | break :blk_1 true; | ||
| 4459 | } | ||
| 4460 | break :blk_1 false; | ||
| 4461 | }) break :blk_0 true; | ||
| 4462 | p.i = pos_0; | ||
| 4463 | break :blk_0 false; | ||
| 4464 | }; | ||
| 4465 | } | ||
| 4466 | pub fn parseDOT(p: *Parser) Error!bool { | ||
| 4467 | const def_index = @intFromEnum(Def.defDOT); | ||
| 4468 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4469 | p.depths[def_index] += 1; | ||
| 4470 | defer p.depths[def_index] -= 1; | ||
| 4471 | return blk_0: { | ||
| 4472 | const pos_0 = p.i; | ||
| 4473 | if (try p.parseskip() and blk_1: { | ||
| 4474 | if (std.mem.startsWith(u8, p.source[p.i..], ".")) { | ||
| 4475 | p.i += 1; | ||
| 4476 | break :blk_1 true; | ||
| 4477 | } | ||
| 4478 | break :blk_1 false; | ||
| 4479 | } and blk_1: { | ||
| 4480 | const pos_1 = p.i; | ||
| 4481 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4482 | '*'...'*', | ||
| 4483 | '.'...'.', | ||
| 4484 | => blk_2: { | ||
| 4485 | p.i += 1; | ||
| 4486 | break :blk_2 true; | ||
| 4487 | }, | ||
| 4488 | else => false, | ||
| 4489 | }); | ||
| 4490 | p.i = pos_1; | ||
| 4491 | break :blk_1 !match_1; | ||
| 4492 | }) break :blk_0 true; | ||
| 4493 | p.i = pos_0; | ||
| 4494 | break :blk_0 false; | ||
| 4495 | }; | ||
| 4496 | } | ||
| 4497 | pub fn parseDOT2(p: *Parser) Error!bool { | ||
| 4498 | const def_index = @intFromEnum(Def.defDOT2); | ||
| 4499 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4500 | p.depths[def_index] += 1; | ||
| 4501 | defer p.depths[def_index] -= 1; | ||
| 4502 | return blk_0: { | ||
| 4503 | const pos_0 = p.i; | ||
| 4504 | if (try p.parseskip() and blk_1: { | ||
| 4505 | if (std.mem.startsWith(u8, p.source[p.i..], "..")) { | ||
| 4506 | p.i += 2; | ||
| 4507 | break :blk_1 true; | ||
| 4508 | } | ||
| 4509 | break :blk_1 false; | ||
| 4510 | } and blk_1: { | ||
| 4511 | const pos_1 = p.i; | ||
| 4512 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4513 | '.'...'.', | ||
| 4514 | => blk_2: { | ||
| 4515 | p.i += 1; | ||
| 4516 | break :blk_2 true; | ||
| 4517 | }, | ||
| 4518 | else => false, | ||
| 4519 | }); | ||
| 4520 | p.i = pos_1; | ||
| 4521 | break :blk_1 !match_1; | ||
| 4522 | }) break :blk_0 true; | ||
| 4523 | p.i = pos_0; | ||
| 4524 | break :blk_0 false; | ||
| 4525 | }; | ||
| 4526 | } | ||
| 4527 | pub fn parseDOT3(p: *Parser) Error!bool { | ||
| 4528 | const def_index = @intFromEnum(Def.defDOT3); | ||
| 4529 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4530 | p.depths[def_index] += 1; | ||
| 4531 | defer p.depths[def_index] -= 1; | ||
| 4532 | return blk_0: { | ||
| 4533 | const pos_0 = p.i; | ||
| 4534 | if (try p.parseskip() and blk_1: { | ||
| 4535 | if (std.mem.startsWith(u8, p.source[p.i..], "...")) { | ||
| 4536 | p.i += 3; | ||
| 4537 | break :blk_1 true; | ||
| 4538 | } | ||
| 4539 | break :blk_1 false; | ||
| 4540 | }) break :blk_0 true; | ||
| 4541 | p.i = pos_0; | ||
| 4542 | break :blk_0 false; | ||
| 4543 | }; | ||
| 4544 | } | ||
| 4545 | pub fn parseDOTASTERISK(p: *Parser) Error!bool { | ||
| 4546 | const def_index = @intFromEnum(Def.defDOTASTERISK); | ||
| 4547 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4548 | p.depths[def_index] += 1; | ||
| 4549 | defer p.depths[def_index] -= 1; | ||
| 4550 | return blk_0: { | ||
| 4551 | const pos_0 = p.i; | ||
| 4552 | if (try p.parseskip() and blk_1: { | ||
| 4553 | if (std.mem.startsWith(u8, p.source[p.i..], ".*")) { | ||
| 4554 | p.i += 2; | ||
| 4555 | break :blk_1 true; | ||
| 4556 | } | ||
| 4557 | break :blk_1 false; | ||
| 4558 | }) break :blk_0 true; | ||
| 4559 | p.i = pos_0; | ||
| 4560 | break :blk_0 false; | ||
| 4561 | }; | ||
| 4562 | } | ||
| 4563 | pub fn parseEQUAL(p: *Parser) Error!bool { | ||
| 4564 | const def_index = @intFromEnum(Def.defEQUAL); | ||
| 4565 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4566 | p.depths[def_index] += 1; | ||
| 4567 | defer p.depths[def_index] -= 1; | ||
| 4568 | return blk_0: { | ||
| 4569 | const pos_0 = p.i; | ||
| 4570 | if (try p.parseskip() and blk_1: { | ||
| 4571 | if (std.mem.startsWith(u8, p.source[p.i..], "=")) { | ||
| 4572 | p.i += 1; | ||
| 4573 | break :blk_1 true; | ||
| 4574 | } | ||
| 4575 | break :blk_1 false; | ||
| 4576 | } and blk_1: { | ||
| 4577 | const pos_1 = p.i; | ||
| 4578 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4579 | '>'...'>', | ||
| 4580 | '='...'=', | ||
| 4581 | => blk_2: { | ||
| 4582 | p.i += 1; | ||
| 4583 | break :blk_2 true; | ||
| 4584 | }, | ||
| 4585 | else => false, | ||
| 4586 | }); | ||
| 4587 | p.i = pos_1; | ||
| 4588 | break :blk_1 !match_1; | ||
| 4589 | }) break :blk_0 true; | ||
| 4590 | p.i = pos_0; | ||
| 4591 | break :blk_0 false; | ||
| 4592 | }; | ||
| 4593 | } | ||
| 4594 | pub fn parseEQUALEQUAL(p: *Parser) Error!bool { | ||
| 4595 | const def_index = @intFromEnum(Def.defEQUALEQUAL); | ||
| 4596 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4597 | p.depths[def_index] += 1; | ||
| 4598 | defer p.depths[def_index] -= 1; | ||
| 4599 | return blk_0: { | ||
| 4600 | const pos_0 = p.i; | ||
| 4601 | if (try p.parseskip() and blk_1: { | ||
| 4602 | if (std.mem.startsWith(u8, p.source[p.i..], "==")) { | ||
| 4603 | p.i += 2; | ||
| 4604 | break :blk_1 true; | ||
| 4605 | } | ||
| 4606 | break :blk_1 false; | ||
| 4607 | }) break :blk_0 true; | ||
| 4608 | p.i = pos_0; | ||
| 4609 | break :blk_0 false; | ||
| 4610 | }; | ||
| 4611 | } | ||
| 4612 | pub fn parseEQUALRARROW(p: *Parser) Error!bool { | ||
| 4613 | const def_index = @intFromEnum(Def.defEQUALRARROW); | ||
| 4614 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4615 | p.depths[def_index] += 1; | ||
| 4616 | defer p.depths[def_index] -= 1; | ||
| 4617 | return blk_0: { | ||
| 4618 | const pos_0 = p.i; | ||
| 4619 | if (try p.parseskip() and blk_1: { | ||
| 4620 | if (std.mem.startsWith(u8, p.source[p.i..], "=>")) { | ||
| 4621 | p.i += 2; | ||
| 4622 | break :blk_1 true; | ||
| 4623 | } | ||
| 4624 | break :blk_1 false; | ||
| 4625 | }) break :blk_0 true; | ||
| 4626 | p.i = pos_0; | ||
| 4627 | break :blk_0 false; | ||
| 4628 | }; | ||
| 4629 | } | ||
| 4630 | pub fn parseEXCLAMATIONMARK(p: *Parser) Error!bool { | ||
| 4631 | const def_index = @intFromEnum(Def.defEXCLAMATIONMARK); | ||
| 4632 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4633 | p.depths[def_index] += 1; | ||
| 4634 | defer p.depths[def_index] -= 1; | ||
| 4635 | return blk_0: { | ||
| 4636 | const pos_0 = p.i; | ||
| 4637 | if (try p.parseskip() and blk_1: { | ||
| 4638 | if (std.mem.startsWith(u8, p.source[p.i..], "!")) { | ||
| 4639 | p.i += 1; | ||
| 4640 | break :blk_1 true; | ||
| 4641 | } | ||
| 4642 | break :blk_1 false; | ||
| 4643 | } and blk_1: { | ||
| 4644 | const pos_1 = p.i; | ||
| 4645 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4646 | '='...'=', | ||
| 4647 | => blk_2: { | ||
| 4648 | p.i += 1; | ||
| 4649 | break :blk_2 true; | ||
| 4650 | }, | ||
| 4651 | else => false, | ||
| 4652 | }); | ||
| 4653 | p.i = pos_1; | ||
| 4654 | break :blk_1 !match_1; | ||
| 4655 | }) break :blk_0 true; | ||
| 4656 | p.i = pos_0; | ||
| 4657 | break :blk_0 false; | ||
| 4658 | }; | ||
| 4659 | } | ||
| 4660 | pub fn parseEXCLAMATIONMARKEQUAL(p: *Parser) Error!bool { | ||
| 4661 | const def_index = @intFromEnum(Def.defEXCLAMATIONMARKEQUAL); | ||
| 4662 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4663 | p.depths[def_index] += 1; | ||
| 4664 | defer p.depths[def_index] -= 1; | ||
| 4665 | return blk_0: { | ||
| 4666 | const pos_0 = p.i; | ||
| 4667 | if (try p.parseskip() and blk_1: { | ||
| 4668 | if (std.mem.startsWith(u8, p.source[p.i..], "!=")) { | ||
| 4669 | p.i += 2; | ||
| 4670 | break :blk_1 true; | ||
| 4671 | } | ||
| 4672 | break :blk_1 false; | ||
| 4673 | }) break :blk_0 true; | ||
| 4674 | p.i = pos_0; | ||
| 4675 | break :blk_0 false; | ||
| 4676 | }; | ||
| 4677 | } | ||
| 4678 | pub fn parseLARROW(p: *Parser) Error!bool { | ||
| 4679 | const def_index = @intFromEnum(Def.defLARROW); | ||
| 4680 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4681 | p.depths[def_index] += 1; | ||
| 4682 | defer p.depths[def_index] -= 1; | ||
| 4683 | return blk_0: { | ||
| 4684 | const pos_0 = p.i; | ||
| 4685 | if (try p.parseskip() and blk_1: { | ||
| 4686 | if (std.mem.startsWith(u8, p.source[p.i..], "<")) { | ||
| 4687 | p.i += 1; | ||
| 4688 | break :blk_1 true; | ||
| 4689 | } | ||
| 4690 | break :blk_1 false; | ||
| 4691 | } and blk_1: { | ||
| 4692 | const pos_1 = p.i; | ||
| 4693 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4694 | '<'...'<', | ||
| 4695 | '='...'=', | ||
| 4696 | => blk_2: { | ||
| 4697 | p.i += 1; | ||
| 4698 | break :blk_2 true; | ||
| 4699 | }, | ||
| 4700 | else => false, | ||
| 4701 | }); | ||
| 4702 | p.i = pos_1; | ||
| 4703 | break :blk_1 !match_1; | ||
| 4704 | }) break :blk_0 true; | ||
| 4705 | p.i = pos_0; | ||
| 4706 | break :blk_0 false; | ||
| 4707 | }; | ||
| 4708 | } | ||
| 4709 | pub fn parseLARROW2(p: *Parser) Error!bool { | ||
| 4710 | const def_index = @intFromEnum(Def.defLARROW2); | ||
| 4711 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4712 | p.depths[def_index] += 1; | ||
| 4713 | defer p.depths[def_index] -= 1; | ||
| 4714 | return blk_0: { | ||
| 4715 | const pos_0 = p.i; | ||
| 4716 | if (try p.parseskip() and blk_1: { | ||
| 4717 | if (std.mem.startsWith(u8, p.source[p.i..], "<<")) { | ||
| 4718 | p.i += 2; | ||
| 4719 | break :blk_1 true; | ||
| 4720 | } | ||
| 4721 | break :blk_1 false; | ||
| 4722 | } and blk_1: { | ||
| 4723 | const pos_1 = p.i; | ||
| 4724 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4725 | '='...'=', | ||
| 4726 | '|'...'|', | ||
| 4727 | => blk_2: { | ||
| 4728 | p.i += 1; | ||
| 4729 | break :blk_2 true; | ||
| 4730 | }, | ||
| 4731 | else => false, | ||
| 4732 | }); | ||
| 4733 | p.i = pos_1; | ||
| 4734 | break :blk_1 !match_1; | ||
| 4735 | }) break :blk_0 true; | ||
| 4736 | p.i = pos_0; | ||
| 4737 | break :blk_0 false; | ||
| 4738 | }; | ||
| 4739 | } | ||
| 4740 | pub fn parseLARROW2EQUAL(p: *Parser) Error!bool { | ||
| 4741 | const def_index = @intFromEnum(Def.defLARROW2EQUAL); | ||
| 4742 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4743 | p.depths[def_index] += 1; | ||
| 4744 | defer p.depths[def_index] -= 1; | ||
| 4745 | return blk_0: { | ||
| 4746 | const pos_0 = p.i; | ||
| 4747 | if (try p.parseskip() and blk_1: { | ||
| 4748 | if (std.mem.startsWith(u8, p.source[p.i..], "<<=")) { | ||
| 4749 | p.i += 3; | ||
| 4750 | break :blk_1 true; | ||
| 4751 | } | ||
| 4752 | break :blk_1 false; | ||
| 4753 | }) break :blk_0 true; | ||
| 4754 | p.i = pos_0; | ||
| 4755 | break :blk_0 false; | ||
| 4756 | }; | ||
| 4757 | } | ||
| 4758 | pub fn parseLARROW2PIPE(p: *Parser) Error!bool { | ||
| 4759 | const def_index = @intFromEnum(Def.defLARROW2PIPE); | ||
| 4760 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4761 | p.depths[def_index] += 1; | ||
| 4762 | defer p.depths[def_index] -= 1; | ||
| 4763 | return blk_0: { | ||
| 4764 | const pos_0 = p.i; | ||
| 4765 | if (try p.parseskip() and blk_1: { | ||
| 4766 | if (std.mem.startsWith(u8, p.source[p.i..], "<<|")) { | ||
| 4767 | p.i += 3; | ||
| 4768 | break :blk_1 true; | ||
| 4769 | } | ||
| 4770 | break :blk_1 false; | ||
| 4771 | } and blk_1: { | ||
| 4772 | const pos_1 = p.i; | ||
| 4773 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4774 | '='...'=', | ||
| 4775 | => blk_2: { | ||
| 4776 | p.i += 1; | ||
| 4777 | break :blk_2 true; | ||
| 4778 | }, | ||
| 4779 | else => false, | ||
| 4780 | }); | ||
| 4781 | p.i = pos_1; | ||
| 4782 | break :blk_1 !match_1; | ||
| 4783 | }) break :blk_0 true; | ||
| 4784 | p.i = pos_0; | ||
| 4785 | break :blk_0 false; | ||
| 4786 | }; | ||
| 4787 | } | ||
| 4788 | pub fn parseLARROW2PIPEEQUAL(p: *Parser) Error!bool { | ||
| 4789 | const def_index = @intFromEnum(Def.defLARROW2PIPEEQUAL); | ||
| 4790 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4791 | p.depths[def_index] += 1; | ||
| 4792 | defer p.depths[def_index] -= 1; | ||
| 4793 | return blk_0: { | ||
| 4794 | const pos_0 = p.i; | ||
| 4795 | if (try p.parseskip() and blk_1: { | ||
| 4796 | if (std.mem.startsWith(u8, p.source[p.i..], "<<|=")) { | ||
| 4797 | p.i += 4; | ||
| 4798 | break :blk_1 true; | ||
| 4799 | } | ||
| 4800 | break :blk_1 false; | ||
| 4801 | }) break :blk_0 true; | ||
| 4802 | p.i = pos_0; | ||
| 4803 | break :blk_0 false; | ||
| 4804 | }; | ||
| 4805 | } | ||
| 4806 | pub fn parseLARROWEQUAL(p: *Parser) Error!bool { | ||
| 4807 | const def_index = @intFromEnum(Def.defLARROWEQUAL); | ||
| 4808 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4809 | p.depths[def_index] += 1; | ||
| 4810 | defer p.depths[def_index] -= 1; | ||
| 4811 | return blk_0: { | ||
| 4812 | const pos_0 = p.i; | ||
| 4813 | if (try p.parseskip() and blk_1: { | ||
| 4814 | if (std.mem.startsWith(u8, p.source[p.i..], "<=")) { | ||
| 4815 | p.i += 2; | ||
| 4816 | break :blk_1 true; | ||
| 4817 | } | ||
| 4818 | break :blk_1 false; | ||
| 4819 | }) break :blk_0 true; | ||
| 4820 | p.i = pos_0; | ||
| 4821 | break :blk_0 false; | ||
| 4822 | }; | ||
| 4823 | } | ||
| 4824 | pub fn parseLBRACE(p: *Parser) Error!bool { | ||
| 4825 | const def_index = @intFromEnum(Def.defLBRACE); | ||
| 4826 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4827 | p.depths[def_index] += 1; | ||
| 4828 | defer p.depths[def_index] -= 1; | ||
| 4829 | return blk_0: { | ||
| 4830 | const pos_0 = p.i; | ||
| 4831 | if (try p.parseskip() and blk_1: { | ||
| 4832 | if (std.mem.startsWith(u8, p.source[p.i..], "{")) { | ||
| 4833 | p.i += 1; | ||
| 4834 | break :blk_1 true; | ||
| 4835 | } | ||
| 4836 | break :blk_1 false; | ||
| 4837 | }) break :blk_0 true; | ||
| 4838 | p.i = pos_0; | ||
| 4839 | break :blk_0 false; | ||
| 4840 | }; | ||
| 4841 | } | ||
| 4842 | pub fn parseLBRACKET(p: *Parser) Error!bool { | ||
| 4843 | const def_index = @intFromEnum(Def.defLBRACKET); | ||
| 4844 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4845 | p.depths[def_index] += 1; | ||
| 4846 | defer p.depths[def_index] -= 1; | ||
| 4847 | return blk_0: { | ||
| 4848 | const pos_0 = p.i; | ||
| 4849 | if (try p.parseskip() and blk_1: { | ||
| 4850 | if (std.mem.startsWith(u8, p.source[p.i..], "[")) { | ||
| 4851 | p.i += 1; | ||
| 4852 | break :blk_1 true; | ||
| 4853 | } | ||
| 4854 | break :blk_1 false; | ||
| 4855 | }) break :blk_0 true; | ||
| 4856 | p.i = pos_0; | ||
| 4857 | break :blk_0 false; | ||
| 4858 | }; | ||
| 4859 | } | ||
| 4860 | pub fn parseLPAREN(p: *Parser) Error!bool { | ||
| 4861 | const def_index = @intFromEnum(Def.defLPAREN); | ||
| 4862 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4863 | p.depths[def_index] += 1; | ||
| 4864 | defer p.depths[def_index] -= 1; | ||
| 4865 | return blk_0: { | ||
| 4866 | const pos_0 = p.i; | ||
| 4867 | if (try p.parseskip() and blk_1: { | ||
| 4868 | if (std.mem.startsWith(u8, p.source[p.i..], "(")) { | ||
| 4869 | p.i += 1; | ||
| 4870 | break :blk_1 true; | ||
| 4871 | } | ||
| 4872 | break :blk_1 false; | ||
| 4873 | }) break :blk_0 true; | ||
| 4874 | p.i = pos_0; | ||
| 4875 | break :blk_0 false; | ||
| 4876 | }; | ||
| 4877 | } | ||
| 4878 | pub fn parseMINUS(p: *Parser) Error!bool { | ||
| 4879 | const def_index = @intFromEnum(Def.defMINUS); | ||
| 4880 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4881 | p.depths[def_index] += 1; | ||
| 4882 | defer p.depths[def_index] -= 1; | ||
| 4883 | return blk_0: { | ||
| 4884 | const pos_0 = p.i; | ||
| 4885 | if (try p.parseskip() and blk_1: { | ||
| 4886 | if (std.mem.startsWith(u8, p.source[p.i..], "-")) { | ||
| 4887 | p.i += 1; | ||
| 4888 | break :blk_1 true; | ||
| 4889 | } | ||
| 4890 | break :blk_1 false; | ||
| 4891 | } and blk_1: { | ||
| 4892 | const pos_1 = p.i; | ||
| 4893 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4894 | '%'...'%', | ||
| 4895 | '='...'=', | ||
| 4896 | '>'...'>', | ||
| 4897 | '|'...'|', | ||
| 4898 | => blk_2: { | ||
| 4899 | p.i += 1; | ||
| 4900 | break :blk_2 true; | ||
| 4901 | }, | ||
| 4902 | else => false, | ||
| 4903 | }); | ||
| 4904 | p.i = pos_1; | ||
| 4905 | break :blk_1 !match_1; | ||
| 4906 | }) break :blk_0 true; | ||
| 4907 | p.i = pos_0; | ||
| 4908 | break :blk_0 false; | ||
| 4909 | }; | ||
| 4910 | } | ||
| 4911 | pub fn parseMINUSEQUAL(p: *Parser) Error!bool { | ||
| 4912 | const def_index = @intFromEnum(Def.defMINUSEQUAL); | ||
| 4913 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4914 | p.depths[def_index] += 1; | ||
| 4915 | defer p.depths[def_index] -= 1; | ||
| 4916 | return blk_0: { | ||
| 4917 | const pos_0 = p.i; | ||
| 4918 | if (try p.parseskip() and blk_1: { | ||
| 4919 | if (std.mem.startsWith(u8, p.source[p.i..], "-=")) { | ||
| 4920 | p.i += 2; | ||
| 4921 | break :blk_1 true; | ||
| 4922 | } | ||
| 4923 | break :blk_1 false; | ||
| 4924 | }) break :blk_0 true; | ||
| 4925 | p.i = pos_0; | ||
| 4926 | break :blk_0 false; | ||
| 4927 | }; | ||
| 4928 | } | ||
| 4929 | pub fn parseMINUSPERCENT(p: *Parser) Error!bool { | ||
| 4930 | const def_index = @intFromEnum(Def.defMINUSPERCENT); | ||
| 4931 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4932 | p.depths[def_index] += 1; | ||
| 4933 | defer p.depths[def_index] -= 1; | ||
| 4934 | return blk_0: { | ||
| 4935 | const pos_0 = p.i; | ||
| 4936 | if (try p.parseskip() and blk_1: { | ||
| 4937 | if (std.mem.startsWith(u8, p.source[p.i..], "-%")) { | ||
| 4938 | p.i += 2; | ||
| 4939 | break :blk_1 true; | ||
| 4940 | } | ||
| 4941 | break :blk_1 false; | ||
| 4942 | } and blk_1: { | ||
| 4943 | const pos_1 = p.i; | ||
| 4944 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4945 | '='...'=', | ||
| 4946 | => blk_2: { | ||
| 4947 | p.i += 1; | ||
| 4948 | break :blk_2 true; | ||
| 4949 | }, | ||
| 4950 | else => false, | ||
| 4951 | }); | ||
| 4952 | p.i = pos_1; | ||
| 4953 | break :blk_1 !match_1; | ||
| 4954 | }) break :blk_0 true; | ||
| 4955 | p.i = pos_0; | ||
| 4956 | break :blk_0 false; | ||
| 4957 | }; | ||
| 4958 | } | ||
| 4959 | pub fn parseMINUSPERCENTEQUAL(p: *Parser) Error!bool { | ||
| 4960 | const def_index = @intFromEnum(Def.defMINUSPERCENTEQUAL); | ||
| 4961 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4962 | p.depths[def_index] += 1; | ||
| 4963 | defer p.depths[def_index] -= 1; | ||
| 4964 | return blk_0: { | ||
| 4965 | const pos_0 = p.i; | ||
| 4966 | if (try p.parseskip() and blk_1: { | ||
| 4967 | if (std.mem.startsWith(u8, p.source[p.i..], "-%=")) { | ||
| 4968 | p.i += 3; | ||
| 4969 | break :blk_1 true; | ||
| 4970 | } | ||
| 4971 | break :blk_1 false; | ||
| 4972 | }) break :blk_0 true; | ||
| 4973 | p.i = pos_0; | ||
| 4974 | break :blk_0 false; | ||
| 4975 | }; | ||
| 4976 | } | ||
| 4977 | pub fn parseMINUSPIPE(p: *Parser) Error!bool { | ||
| 4978 | const def_index = @intFromEnum(Def.defMINUSPIPE); | ||
| 4979 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 4980 | p.depths[def_index] += 1; | ||
| 4981 | defer p.depths[def_index] -= 1; | ||
| 4982 | return blk_0: { | ||
| 4983 | const pos_0 = p.i; | ||
| 4984 | if (try p.parseskip() and blk_1: { | ||
| 4985 | if (std.mem.startsWith(u8, p.source[p.i..], "-|")) { | ||
| 4986 | p.i += 2; | ||
| 4987 | break :blk_1 true; | ||
| 4988 | } | ||
| 4989 | break :blk_1 false; | ||
| 4990 | } and blk_1: { | ||
| 4991 | const pos_1 = p.i; | ||
| 4992 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 4993 | '='...'=', | ||
| 4994 | => blk_2: { | ||
| 4995 | p.i += 1; | ||
| 4996 | break :blk_2 true; | ||
| 4997 | }, | ||
| 4998 | else => false, | ||
| 4999 | }); | ||
| 5000 | p.i = pos_1; | ||
| 5001 | break :blk_1 !match_1; | ||
| 5002 | }) break :blk_0 true; | ||
| 5003 | p.i = pos_0; | ||
| 5004 | break :blk_0 false; | ||
| 5005 | }; | ||
| 5006 | } | ||
| 5007 | pub fn parseMINUSPIPEEQUAL(p: *Parser) Error!bool { | ||
| 5008 | const def_index = @intFromEnum(Def.defMINUSPIPEEQUAL); | ||
| 5009 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5010 | p.depths[def_index] += 1; | ||
| 5011 | defer p.depths[def_index] -= 1; | ||
| 5012 | return blk_0: { | ||
| 5013 | const pos_0 = p.i; | ||
| 5014 | if (try p.parseskip() and blk_1: { | ||
| 5015 | if (std.mem.startsWith(u8, p.source[p.i..], "-|=")) { | ||
| 5016 | p.i += 3; | ||
| 5017 | break :blk_1 true; | ||
| 5018 | } | ||
| 5019 | break :blk_1 false; | ||
| 5020 | }) break :blk_0 true; | ||
| 5021 | p.i = pos_0; | ||
| 5022 | break :blk_0 false; | ||
| 5023 | }; | ||
| 5024 | } | ||
| 5025 | pub fn parseMINUSRARROW(p: *Parser) Error!bool { | ||
| 5026 | const def_index = @intFromEnum(Def.defMINUSRARROW); | ||
| 5027 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5028 | p.depths[def_index] += 1; | ||
| 5029 | defer p.depths[def_index] -= 1; | ||
| 5030 | return blk_0: { | ||
| 5031 | const pos_0 = p.i; | ||
| 5032 | if (try p.parseskip() and blk_1: { | ||
| 5033 | if (std.mem.startsWith(u8, p.source[p.i..], "->")) { | ||
| 5034 | p.i += 2; | ||
| 5035 | break :blk_1 true; | ||
| 5036 | } | ||
| 5037 | break :blk_1 false; | ||
| 5038 | }) break :blk_0 true; | ||
| 5039 | p.i = pos_0; | ||
| 5040 | break :blk_0 false; | ||
| 5041 | }; | ||
| 5042 | } | ||
| 5043 | pub fn parsePERCENT(p: *Parser) Error!bool { | ||
| 5044 | const def_index = @intFromEnum(Def.defPERCENT); | ||
| 5045 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5046 | p.depths[def_index] += 1; | ||
| 5047 | defer p.depths[def_index] -= 1; | ||
| 5048 | return blk_0: { | ||
| 5049 | const pos_0 = p.i; | ||
| 5050 | if (try p.parseskip() and blk_1: { | ||
| 5051 | if (std.mem.startsWith(u8, p.source[p.i..], "%")) { | ||
| 5052 | p.i += 1; | ||
| 5053 | break :blk_1 true; | ||
| 5054 | } | ||
| 5055 | break :blk_1 false; | ||
| 5056 | } and blk_1: { | ||
| 5057 | const pos_1 = p.i; | ||
| 5058 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5059 | '='...'=', | ||
| 5060 | => blk_2: { | ||
| 5061 | p.i += 1; | ||
| 5062 | break :blk_2 true; | ||
| 5063 | }, | ||
| 5064 | else => false, | ||
| 5065 | }); | ||
| 5066 | p.i = pos_1; | ||
| 5067 | break :blk_1 !match_1; | ||
| 5068 | }) break :blk_0 true; | ||
| 5069 | p.i = pos_0; | ||
| 5070 | break :blk_0 false; | ||
| 5071 | }; | ||
| 5072 | } | ||
| 5073 | pub fn parsePERCENTEQUAL(p: *Parser) Error!bool { | ||
| 5074 | const def_index = @intFromEnum(Def.defPERCENTEQUAL); | ||
| 5075 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5076 | p.depths[def_index] += 1; | ||
| 5077 | defer p.depths[def_index] -= 1; | ||
| 5078 | return blk_0: { | ||
| 5079 | const pos_0 = p.i; | ||
| 5080 | if (try p.parseskip() and blk_1: { | ||
| 5081 | if (std.mem.startsWith(u8, p.source[p.i..], "%=")) { | ||
| 5082 | p.i += 2; | ||
| 5083 | break :blk_1 true; | ||
| 5084 | } | ||
| 5085 | break :blk_1 false; | ||
| 5086 | }) break :blk_0 true; | ||
| 5087 | p.i = pos_0; | ||
| 5088 | break :blk_0 false; | ||
| 5089 | }; | ||
| 5090 | } | ||
| 5091 | pub fn parsePIPE(p: *Parser) Error!bool { | ||
| 5092 | const def_index = @intFromEnum(Def.defPIPE); | ||
| 5093 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5094 | p.depths[def_index] += 1; | ||
| 5095 | defer p.depths[def_index] -= 1; | ||
| 5096 | return blk_0: { | ||
| 5097 | const pos_0 = p.i; | ||
| 5098 | if (try p.parseskip() and blk_1: { | ||
| 5099 | if (std.mem.startsWith(u8, p.source[p.i..], "|")) { | ||
| 5100 | p.i += 1; | ||
| 5101 | break :blk_1 true; | ||
| 5102 | } | ||
| 5103 | break :blk_1 false; | ||
| 5104 | } and blk_1: { | ||
| 5105 | const pos_1 = p.i; | ||
| 5106 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5107 | '|'...'|', | ||
| 5108 | '='...'=', | ||
| 5109 | => blk_2: { | ||
| 5110 | p.i += 1; | ||
| 5111 | break :blk_2 true; | ||
| 5112 | }, | ||
| 5113 | else => false, | ||
| 5114 | }); | ||
| 5115 | p.i = pos_1; | ||
| 5116 | break :blk_1 !match_1; | ||
| 5117 | }) break :blk_0 true; | ||
| 5118 | p.i = pos_0; | ||
| 5119 | break :blk_0 false; | ||
| 5120 | }; | ||
| 5121 | } | ||
| 5122 | pub fn parsePIPE2(p: *Parser) Error!bool { | ||
| 5123 | const def_index = @intFromEnum(Def.defPIPE2); | ||
| 5124 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5125 | p.depths[def_index] += 1; | ||
| 5126 | defer p.depths[def_index] -= 1; | ||
| 5127 | return blk_0: { | ||
| 5128 | const pos_0 = p.i; | ||
| 5129 | if (try p.parseskip() and blk_1: { | ||
| 5130 | if (std.mem.startsWith(u8, p.source[p.i..], "||")) { | ||
| 5131 | p.i += 2; | ||
| 5132 | break :blk_1 true; | ||
| 5133 | } | ||
| 5134 | break :blk_1 false; | ||
| 5135 | }) break :blk_0 true; | ||
| 5136 | p.i = pos_0; | ||
| 5137 | break :blk_0 false; | ||
| 5138 | }; | ||
| 5139 | } | ||
| 5140 | pub fn parsePIPEEQUAL(p: *Parser) Error!bool { | ||
| 5141 | const def_index = @intFromEnum(Def.defPIPEEQUAL); | ||
| 5142 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5143 | p.depths[def_index] += 1; | ||
| 5144 | defer p.depths[def_index] -= 1; | ||
| 5145 | return blk_0: { | ||
| 5146 | const pos_0 = p.i; | ||
| 5147 | if (try p.parseskip() and blk_1: { | ||
| 5148 | if (std.mem.startsWith(u8, p.source[p.i..], "|=")) { | ||
| 5149 | p.i += 2; | ||
| 5150 | break :blk_1 true; | ||
| 5151 | } | ||
| 5152 | break :blk_1 false; | ||
| 5153 | }) break :blk_0 true; | ||
| 5154 | p.i = pos_0; | ||
| 5155 | break :blk_0 false; | ||
| 5156 | }; | ||
| 5157 | } | ||
| 5158 | pub fn parsePLUS(p: *Parser) Error!bool { | ||
| 5159 | const def_index = @intFromEnum(Def.defPLUS); | ||
| 5160 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5161 | p.depths[def_index] += 1; | ||
| 5162 | defer p.depths[def_index] -= 1; | ||
| 5163 | return blk_0: { | ||
| 5164 | const pos_0 = p.i; | ||
| 5165 | if (try p.parseskip() and blk_1: { | ||
| 5166 | if (std.mem.startsWith(u8, p.source[p.i..], "+")) { | ||
| 5167 | p.i += 1; | ||
| 5168 | break :blk_1 true; | ||
| 5169 | } | ||
| 5170 | break :blk_1 false; | ||
| 5171 | } and blk_1: { | ||
| 5172 | const pos_1 = p.i; | ||
| 5173 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5174 | '%'...'%', | ||
| 5175 | '+'...'+', | ||
| 5176 | '='...'=', | ||
| 5177 | '|'...'|', | ||
| 5178 | => blk_2: { | ||
| 5179 | p.i += 1; | ||
| 5180 | break :blk_2 true; | ||
| 5181 | }, | ||
| 5182 | else => false, | ||
| 5183 | }); | ||
| 5184 | p.i = pos_1; | ||
| 5185 | break :blk_1 !match_1; | ||
| 5186 | }) break :blk_0 true; | ||
| 5187 | p.i = pos_0; | ||
| 5188 | break :blk_0 false; | ||
| 5189 | }; | ||
| 5190 | } | ||
| 5191 | pub fn parsePLUS2(p: *Parser) Error!bool { | ||
| 5192 | const def_index = @intFromEnum(Def.defPLUS2); | ||
| 5193 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5194 | p.depths[def_index] += 1; | ||
| 5195 | defer p.depths[def_index] -= 1; | ||
| 5196 | return blk_0: { | ||
| 5197 | const pos_0 = p.i; | ||
| 5198 | if (try p.parseskip() and blk_1: { | ||
| 5199 | if (std.mem.startsWith(u8, p.source[p.i..], "++")) { | ||
| 5200 | p.i += 2; | ||
| 5201 | break :blk_1 true; | ||
| 5202 | } | ||
| 5203 | break :blk_1 false; | ||
| 5204 | }) break :blk_0 true; | ||
| 5205 | p.i = pos_0; | ||
| 5206 | break :blk_0 false; | ||
| 5207 | }; | ||
| 5208 | } | ||
| 5209 | pub fn parsePLUSEQUAL(p: *Parser) Error!bool { | ||
| 5210 | const def_index = @intFromEnum(Def.defPLUSEQUAL); | ||
| 5211 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5212 | p.depths[def_index] += 1; | ||
| 5213 | defer p.depths[def_index] -= 1; | ||
| 5214 | return blk_0: { | ||
| 5215 | const pos_0 = p.i; | ||
| 5216 | if (try p.parseskip() and blk_1: { | ||
| 5217 | if (std.mem.startsWith(u8, p.source[p.i..], "+=")) { | ||
| 5218 | p.i += 2; | ||
| 5219 | break :blk_1 true; | ||
| 5220 | } | ||
| 5221 | break :blk_1 false; | ||
| 5222 | }) break :blk_0 true; | ||
| 5223 | p.i = pos_0; | ||
| 5224 | break :blk_0 false; | ||
| 5225 | }; | ||
| 5226 | } | ||
| 5227 | pub fn parsePLUSPERCENT(p: *Parser) Error!bool { | ||
| 5228 | const def_index = @intFromEnum(Def.defPLUSPERCENT); | ||
| 5229 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5230 | p.depths[def_index] += 1; | ||
| 5231 | defer p.depths[def_index] -= 1; | ||
| 5232 | return blk_0: { | ||
| 5233 | const pos_0 = p.i; | ||
| 5234 | if (try p.parseskip() and blk_1: { | ||
| 5235 | if (std.mem.startsWith(u8, p.source[p.i..], "+%")) { | ||
| 5236 | p.i += 2; | ||
| 5237 | break :blk_1 true; | ||
| 5238 | } | ||
| 5239 | break :blk_1 false; | ||
| 5240 | } and blk_1: { | ||
| 5241 | const pos_1 = p.i; | ||
| 5242 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5243 | '='...'=', | ||
| 5244 | => blk_2: { | ||
| 5245 | p.i += 1; | ||
| 5246 | break :blk_2 true; | ||
| 5247 | }, | ||
| 5248 | else => false, | ||
| 5249 | }); | ||
| 5250 | p.i = pos_1; | ||
| 5251 | break :blk_1 !match_1; | ||
| 5252 | }) break :blk_0 true; | ||
| 5253 | p.i = pos_0; | ||
| 5254 | break :blk_0 false; | ||
| 5255 | }; | ||
| 5256 | } | ||
| 5257 | pub fn parsePLUSPERCENTEQUAL(p: *Parser) Error!bool { | ||
| 5258 | const def_index = @intFromEnum(Def.defPLUSPERCENTEQUAL); | ||
| 5259 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5260 | p.depths[def_index] += 1; | ||
| 5261 | defer p.depths[def_index] -= 1; | ||
| 5262 | return blk_0: { | ||
| 5263 | const pos_0 = p.i; | ||
| 5264 | if (try p.parseskip() and blk_1: { | ||
| 5265 | if (std.mem.startsWith(u8, p.source[p.i..], "+%=")) { | ||
| 5266 | p.i += 3; | ||
| 5267 | break :blk_1 true; | ||
| 5268 | } | ||
| 5269 | break :blk_1 false; | ||
| 5270 | }) break :blk_0 true; | ||
| 5271 | p.i = pos_0; | ||
| 5272 | break :blk_0 false; | ||
| 5273 | }; | ||
| 5274 | } | ||
| 5275 | pub fn parsePLUSPIPE(p: *Parser) Error!bool { | ||
| 5276 | const def_index = @intFromEnum(Def.defPLUSPIPE); | ||
| 5277 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5278 | p.depths[def_index] += 1; | ||
| 5279 | defer p.depths[def_index] -= 1; | ||
| 5280 | return blk_0: { | ||
| 5281 | const pos_0 = p.i; | ||
| 5282 | if (try p.parseskip() and blk_1: { | ||
| 5283 | if (std.mem.startsWith(u8, p.source[p.i..], "+|")) { | ||
| 5284 | p.i += 2; | ||
| 5285 | break :blk_1 true; | ||
| 5286 | } | ||
| 5287 | break :blk_1 false; | ||
| 5288 | } and blk_1: { | ||
| 5289 | const pos_1 = p.i; | ||
| 5290 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5291 | '='...'=', | ||
| 5292 | => blk_2: { | ||
| 5293 | p.i += 1; | ||
| 5294 | break :blk_2 true; | ||
| 5295 | }, | ||
| 5296 | else => false, | ||
| 5297 | }); | ||
| 5298 | p.i = pos_1; | ||
| 5299 | break :blk_1 !match_1; | ||
| 5300 | }) break :blk_0 true; | ||
| 5301 | p.i = pos_0; | ||
| 5302 | break :blk_0 false; | ||
| 5303 | }; | ||
| 5304 | } | ||
| 5305 | pub fn parsePLUSPIPEEQUAL(p: *Parser) Error!bool { | ||
| 5306 | const def_index = @intFromEnum(Def.defPLUSPIPEEQUAL); | ||
| 5307 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5308 | p.depths[def_index] += 1; | ||
| 5309 | defer p.depths[def_index] -= 1; | ||
| 5310 | return blk_0: { | ||
| 5311 | const pos_0 = p.i; | ||
| 5312 | if (try p.parseskip() and blk_1: { | ||
| 5313 | if (std.mem.startsWith(u8, p.source[p.i..], "+|=")) { | ||
| 5314 | p.i += 3; | ||
| 5315 | break :blk_1 true; | ||
| 5316 | } | ||
| 5317 | break :blk_1 false; | ||
| 5318 | }) break :blk_0 true; | ||
| 5319 | p.i = pos_0; | ||
| 5320 | break :blk_0 false; | ||
| 5321 | }; | ||
| 5322 | } | ||
| 5323 | pub fn parseLETTERC(p: *Parser) Error!bool { | ||
| 5324 | const def_index = @intFromEnum(Def.defLETTERC); | ||
| 5325 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5326 | p.depths[def_index] += 1; | ||
| 5327 | defer p.depths[def_index] -= 1; | ||
| 5328 | return blk_0: { | ||
| 5329 | const pos_0 = p.i; | ||
| 5330 | if (try p.parseskip() and blk_1: { | ||
| 5331 | if (std.mem.startsWith(u8, p.source[p.i..], "c")) { | ||
| 5332 | p.i += 1; | ||
| 5333 | break :blk_1 true; | ||
| 5334 | } | ||
| 5335 | break :blk_1 false; | ||
| 5336 | }) break :blk_0 true; | ||
| 5337 | p.i = pos_0; | ||
| 5338 | break :blk_0 false; | ||
| 5339 | }; | ||
| 5340 | } | ||
| 5341 | pub fn parseQUESTIONMARK(p: *Parser) Error!bool { | ||
| 5342 | const def_index = @intFromEnum(Def.defQUESTIONMARK); | ||
| 5343 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5344 | p.depths[def_index] += 1; | ||
| 5345 | defer p.depths[def_index] -= 1; | ||
| 5346 | return blk_0: { | ||
| 5347 | const pos_0 = p.i; | ||
| 5348 | if (try p.parseskip() and blk_1: { | ||
| 5349 | if (std.mem.startsWith(u8, p.source[p.i..], "?")) { | ||
| 5350 | p.i += 1; | ||
| 5351 | break :blk_1 true; | ||
| 5352 | } | ||
| 5353 | break :blk_1 false; | ||
| 5354 | }) break :blk_0 true; | ||
| 5355 | p.i = pos_0; | ||
| 5356 | break :blk_0 false; | ||
| 5357 | }; | ||
| 5358 | } | ||
| 5359 | pub fn parseRARROW(p: *Parser) Error!bool { | ||
| 5360 | const def_index = @intFromEnum(Def.defRARROW); | ||
| 5361 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5362 | p.depths[def_index] += 1; | ||
| 5363 | defer p.depths[def_index] -= 1; | ||
| 5364 | return blk_0: { | ||
| 5365 | const pos_0 = p.i; | ||
| 5366 | if (try p.parseskip() and blk_1: { | ||
| 5367 | if (std.mem.startsWith(u8, p.source[p.i..], ">")) { | ||
| 5368 | p.i += 1; | ||
| 5369 | break :blk_1 true; | ||
| 5370 | } | ||
| 5371 | break :blk_1 false; | ||
| 5372 | } and blk_1: { | ||
| 5373 | const pos_1 = p.i; | ||
| 5374 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5375 | '>'...'>', | ||
| 5376 | '='...'=', | ||
| 5377 | => blk_2: { | ||
| 5378 | p.i += 1; | ||
| 5379 | break :blk_2 true; | ||
| 5380 | }, | ||
| 5381 | else => false, | ||
| 5382 | }); | ||
| 5383 | p.i = pos_1; | ||
| 5384 | break :blk_1 !match_1; | ||
| 5385 | }) break :blk_0 true; | ||
| 5386 | p.i = pos_0; | ||
| 5387 | break :blk_0 false; | ||
| 5388 | }; | ||
| 5389 | } | ||
| 5390 | pub fn parseRARROW2(p: *Parser) Error!bool { | ||
| 5391 | const def_index = @intFromEnum(Def.defRARROW2); | ||
| 5392 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5393 | p.depths[def_index] += 1; | ||
| 5394 | defer p.depths[def_index] -= 1; | ||
| 5395 | return blk_0: { | ||
| 5396 | const pos_0 = p.i; | ||
| 5397 | if (try p.parseskip() and blk_1: { | ||
| 5398 | if (std.mem.startsWith(u8, p.source[p.i..], ">>")) { | ||
| 5399 | p.i += 2; | ||
| 5400 | break :blk_1 true; | ||
| 5401 | } | ||
| 5402 | break :blk_1 false; | ||
| 5403 | } and blk_1: { | ||
| 5404 | const pos_1 = p.i; | ||
| 5405 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5406 | '='...'=', | ||
| 5407 | => blk_2: { | ||
| 5408 | p.i += 1; | ||
| 5409 | break :blk_2 true; | ||
| 5410 | }, | ||
| 5411 | else => false, | ||
| 5412 | }); | ||
| 5413 | p.i = pos_1; | ||
| 5414 | break :blk_1 !match_1; | ||
| 5415 | }) break :blk_0 true; | ||
| 5416 | p.i = pos_0; | ||
| 5417 | break :blk_0 false; | ||
| 5418 | }; | ||
| 5419 | } | ||
| 5420 | pub fn parseRARROW2EQUAL(p: *Parser) Error!bool { | ||
| 5421 | const def_index = @intFromEnum(Def.defRARROW2EQUAL); | ||
| 5422 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5423 | p.depths[def_index] += 1; | ||
| 5424 | defer p.depths[def_index] -= 1; | ||
| 5425 | return blk_0: { | ||
| 5426 | const pos_0 = p.i; | ||
| 5427 | if (try p.parseskip() and blk_1: { | ||
| 5428 | if (std.mem.startsWith(u8, p.source[p.i..], ">>=")) { | ||
| 5429 | p.i += 3; | ||
| 5430 | break :blk_1 true; | ||
| 5431 | } | ||
| 5432 | break :blk_1 false; | ||
| 5433 | }) break :blk_0 true; | ||
| 5434 | p.i = pos_0; | ||
| 5435 | break :blk_0 false; | ||
| 5436 | }; | ||
| 5437 | } | ||
| 5438 | pub fn parseRARROWEQUAL(p: *Parser) Error!bool { | ||
| 5439 | const def_index = @intFromEnum(Def.defRARROWEQUAL); | ||
| 5440 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5441 | p.depths[def_index] += 1; | ||
| 5442 | defer p.depths[def_index] -= 1; | ||
| 5443 | return blk_0: { | ||
| 5444 | const pos_0 = p.i; | ||
| 5445 | if (try p.parseskip() and blk_1: { | ||
| 5446 | if (std.mem.startsWith(u8, p.source[p.i..], ">=")) { | ||
| 5447 | p.i += 2; | ||
| 5448 | break :blk_1 true; | ||
| 5449 | } | ||
| 5450 | break :blk_1 false; | ||
| 5451 | }) break :blk_0 true; | ||
| 5452 | p.i = pos_0; | ||
| 5453 | break :blk_0 false; | ||
| 5454 | }; | ||
| 5455 | } | ||
| 5456 | pub fn parseRBRACE(p: *Parser) Error!bool { | ||
| 5457 | const def_index = @intFromEnum(Def.defRBRACE); | ||
| 5458 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5459 | p.depths[def_index] += 1; | ||
| 5460 | defer p.depths[def_index] -= 1; | ||
| 5461 | return blk_0: { | ||
| 5462 | const pos_0 = p.i; | ||
| 5463 | if (try p.parseskip() and blk_1: { | ||
| 5464 | if (std.mem.startsWith(u8, p.source[p.i..], "}")) { | ||
| 5465 | p.i += 1; | ||
| 5466 | break :blk_1 true; | ||
| 5467 | } | ||
| 5468 | break :blk_1 false; | ||
| 5469 | }) break :blk_0 true; | ||
| 5470 | p.i = pos_0; | ||
| 5471 | break :blk_0 false; | ||
| 5472 | }; | ||
| 5473 | } | ||
| 5474 | pub fn parseRBRACKET(p: *Parser) Error!bool { | ||
| 5475 | const def_index = @intFromEnum(Def.defRBRACKET); | ||
| 5476 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5477 | p.depths[def_index] += 1; | ||
| 5478 | defer p.depths[def_index] -= 1; | ||
| 5479 | return blk_0: { | ||
| 5480 | const pos_0 = p.i; | ||
| 5481 | if (try p.parseskip() and blk_1: { | ||
| 5482 | if (std.mem.startsWith(u8, p.source[p.i..], "]")) { | ||
| 5483 | p.i += 1; | ||
| 5484 | break :blk_1 true; | ||
| 5485 | } | ||
| 5486 | break :blk_1 false; | ||
| 5487 | }) break :blk_0 true; | ||
| 5488 | p.i = pos_0; | ||
| 5489 | break :blk_0 false; | ||
| 5490 | }; | ||
| 5491 | } | ||
| 5492 | pub fn parseRPAREN(p: *Parser) Error!bool { | ||
| 5493 | const def_index = @intFromEnum(Def.defRPAREN); | ||
| 5494 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5495 | p.depths[def_index] += 1; | ||
| 5496 | defer p.depths[def_index] -= 1; | ||
| 5497 | return blk_0: { | ||
| 5498 | const pos_0 = p.i; | ||
| 5499 | if (try p.parseskip() and blk_1: { | ||
| 5500 | if (std.mem.startsWith(u8, p.source[p.i..], ")")) { | ||
| 5501 | p.i += 1; | ||
| 5502 | break :blk_1 true; | ||
| 5503 | } | ||
| 5504 | break :blk_1 false; | ||
| 5505 | }) break :blk_0 true; | ||
| 5506 | p.i = pos_0; | ||
| 5507 | break :blk_0 false; | ||
| 5508 | }; | ||
| 5509 | } | ||
| 5510 | pub fn parseSEMICOLON(p: *Parser) Error!bool { | ||
| 5511 | const def_index = @intFromEnum(Def.defSEMICOLON); | ||
| 5512 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5513 | p.depths[def_index] += 1; | ||
| 5514 | defer p.depths[def_index] -= 1; | ||
| 5515 | return blk_0: { | ||
| 5516 | const pos_0 = p.i; | ||
| 5517 | if (try p.parseskip() and blk_1: { | ||
| 5518 | if (std.mem.startsWith(u8, p.source[p.i..], ";")) { | ||
| 5519 | p.i += 1; | ||
| 5520 | break :blk_1 true; | ||
| 5521 | } | ||
| 5522 | break :blk_1 false; | ||
| 5523 | }) break :blk_0 true; | ||
| 5524 | p.i = pos_0; | ||
| 5525 | break :blk_0 false; | ||
| 5526 | }; | ||
| 5527 | } | ||
| 5528 | pub fn parseSLASH(p: *Parser) Error!bool { | ||
| 5529 | const def_index = @intFromEnum(Def.defSLASH); | ||
| 5530 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5531 | p.depths[def_index] += 1; | ||
| 5532 | defer p.depths[def_index] -= 1; | ||
| 5533 | return blk_0: { | ||
| 5534 | const pos_0 = p.i; | ||
| 5535 | if (try p.parseskip() and blk_1: { | ||
| 5536 | if (std.mem.startsWith(u8, p.source[p.i..], "/")) { | ||
| 5537 | p.i += 1; | ||
| 5538 | break :blk_1 true; | ||
| 5539 | } | ||
| 5540 | break :blk_1 false; | ||
| 5541 | } and blk_1: { | ||
| 5542 | const pos_1 = p.i; | ||
| 5543 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5544 | '='...'=', | ||
| 5545 | '/'...'/', | ||
| 5546 | => blk_2: { | ||
| 5547 | p.i += 1; | ||
| 5548 | break :blk_2 true; | ||
| 5549 | }, | ||
| 5550 | else => false, | ||
| 5551 | }); | ||
| 5552 | p.i = pos_1; | ||
| 5553 | break :blk_1 !match_1; | ||
| 5554 | }) break :blk_0 true; | ||
| 5555 | p.i = pos_0; | ||
| 5556 | break :blk_0 false; | ||
| 5557 | }; | ||
| 5558 | } | ||
| 5559 | pub fn parseSLASHEQUAL(p: *Parser) Error!bool { | ||
| 5560 | const def_index = @intFromEnum(Def.defSLASHEQUAL); | ||
| 5561 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5562 | p.depths[def_index] += 1; | ||
| 5563 | defer p.depths[def_index] -= 1; | ||
| 5564 | return blk_0: { | ||
| 5565 | const pos_0 = p.i; | ||
| 5566 | if (try p.parseskip() and blk_1: { | ||
| 5567 | if (std.mem.startsWith(u8, p.source[p.i..], "/=")) { | ||
| 5568 | p.i += 2; | ||
| 5569 | break :blk_1 true; | ||
| 5570 | } | ||
| 5571 | break :blk_1 false; | ||
| 5572 | }) break :blk_0 true; | ||
| 5573 | p.i = pos_0; | ||
| 5574 | break :blk_0 false; | ||
| 5575 | }; | ||
| 5576 | } | ||
| 5577 | pub fn parseTILDE(p: *Parser) Error!bool { | ||
| 5578 | const def_index = @intFromEnum(Def.defTILDE); | ||
| 5579 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5580 | p.depths[def_index] += 1; | ||
| 5581 | defer p.depths[def_index] -= 1; | ||
| 5582 | return blk_0: { | ||
| 5583 | const pos_0 = p.i; | ||
| 5584 | if (try p.parseskip() and blk_1: { | ||
| 5585 | if (std.mem.startsWith(u8, p.source[p.i..], "~")) { | ||
| 5586 | p.i += 1; | ||
| 5587 | break :blk_1 true; | ||
| 5588 | } | ||
| 5589 | break :blk_1 false; | ||
| 5590 | }) break :blk_0 true; | ||
| 5591 | p.i = pos_0; | ||
| 5592 | break :blk_0 false; | ||
| 5593 | }; | ||
| 5594 | } | ||
| 5595 | pub fn parseend_of_word(p: *Parser) Error!bool { | ||
| 5596 | const def_index = @intFromEnum(Def.defend_of_word); | ||
| 5597 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5598 | p.depths[def_index] += 1; | ||
| 5599 | defer p.depths[def_index] -= 1; | ||
| 5600 | return blk_0: { | ||
| 5601 | const pos_0 = p.i; | ||
| 5602 | if (blk_1: { | ||
| 5603 | const pos_1 = p.i; | ||
| 5604 | const match_1 = (p.i < p.source.len and switch (p.source[p.i]) { | ||
| 5605 | 'a'...'z', | ||
| 5606 | 'A'...'Z', | ||
| 5607 | '0'...'9', | ||
| 5608 | '_'...'_', | ||
| 5609 | => blk_2: { | ||
| 5610 | p.i += 1; | ||
| 5611 | break :blk_2 true; | ||
| 5612 | }, | ||
| 5613 | else => false, | ||
| 5614 | }); | ||
| 5615 | p.i = pos_1; | ||
| 5616 | break :blk_1 !match_1; | ||
| 5617 | }) break :blk_0 true; | ||
| 5618 | p.i = pos_0; | ||
| 5619 | break :blk_0 false; | ||
| 5620 | }; | ||
| 5621 | } | ||
| 5622 | pub fn parseKEYWORD_addrspace(p: *Parser) Error!bool { | ||
| 5623 | const def_index = @intFromEnum(Def.defKEYWORD_addrspace); | ||
| 5624 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5625 | p.depths[def_index] += 1; | ||
| 5626 | defer p.depths[def_index] -= 1; | ||
| 5627 | return blk_0: { | ||
| 5628 | const pos_0 = p.i; | ||
| 5629 | if (try p.parseskip() and blk_1: { | ||
| 5630 | if (std.mem.startsWith(u8, p.source[p.i..], "addrspace")) { | ||
| 5631 | p.i += 9; | ||
| 5632 | break :blk_1 true; | ||
| 5633 | } | ||
| 5634 | break :blk_1 false; | ||
| 5635 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5636 | p.i = pos_0; | ||
| 5637 | break :blk_0 false; | ||
| 5638 | }; | ||
| 5639 | } | ||
| 5640 | pub fn parseKEYWORD_align(p: *Parser) Error!bool { | ||
| 5641 | const def_index = @intFromEnum(Def.defKEYWORD_align); | ||
| 5642 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5643 | p.depths[def_index] += 1; | ||
| 5644 | defer p.depths[def_index] -= 1; | ||
| 5645 | return blk_0: { | ||
| 5646 | const pos_0 = p.i; | ||
| 5647 | if (try p.parseskip() and blk_1: { | ||
| 5648 | if (std.mem.startsWith(u8, p.source[p.i..], "align")) { | ||
| 5649 | p.i += 5; | ||
| 5650 | break :blk_1 true; | ||
| 5651 | } | ||
| 5652 | break :blk_1 false; | ||
| 5653 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5654 | p.i = pos_0; | ||
| 5655 | break :blk_0 false; | ||
| 5656 | }; | ||
| 5657 | } | ||
| 5658 | pub fn parseKEYWORD_allowzero(p: *Parser) Error!bool { | ||
| 5659 | const def_index = @intFromEnum(Def.defKEYWORD_allowzero); | ||
| 5660 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5661 | p.depths[def_index] += 1; | ||
| 5662 | defer p.depths[def_index] -= 1; | ||
| 5663 | return blk_0: { | ||
| 5664 | const pos_0 = p.i; | ||
| 5665 | if (try p.parseskip() and blk_1: { | ||
| 5666 | if (std.mem.startsWith(u8, p.source[p.i..], "allowzero")) { | ||
| 5667 | p.i += 9; | ||
| 5668 | break :blk_1 true; | ||
| 5669 | } | ||
| 5670 | break :blk_1 false; | ||
| 5671 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5672 | p.i = pos_0; | ||
| 5673 | break :blk_0 false; | ||
| 5674 | }; | ||
| 5675 | } | ||
| 5676 | pub fn parseKEYWORD_and(p: *Parser) Error!bool { | ||
| 5677 | const def_index = @intFromEnum(Def.defKEYWORD_and); | ||
| 5678 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5679 | p.depths[def_index] += 1; | ||
| 5680 | defer p.depths[def_index] -= 1; | ||
| 5681 | return blk_0: { | ||
| 5682 | const pos_0 = p.i; | ||
| 5683 | if (try p.parseskip() and blk_1: { | ||
| 5684 | if (std.mem.startsWith(u8, p.source[p.i..], "and")) { | ||
| 5685 | p.i += 3; | ||
| 5686 | break :blk_1 true; | ||
| 5687 | } | ||
| 5688 | break :blk_1 false; | ||
| 5689 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5690 | p.i = pos_0; | ||
| 5691 | break :blk_0 false; | ||
| 5692 | }; | ||
| 5693 | } | ||
| 5694 | pub fn parseKEYWORD_anyframe(p: *Parser) Error!bool { | ||
| 5695 | const def_index = @intFromEnum(Def.defKEYWORD_anyframe); | ||
| 5696 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5697 | p.depths[def_index] += 1; | ||
| 5698 | defer p.depths[def_index] -= 1; | ||
| 5699 | return blk_0: { | ||
| 5700 | const pos_0 = p.i; | ||
| 5701 | if (try p.parseskip() and blk_1: { | ||
| 5702 | if (std.mem.startsWith(u8, p.source[p.i..], "anyframe")) { | ||
| 5703 | p.i += 8; | ||
| 5704 | break :blk_1 true; | ||
| 5705 | } | ||
| 5706 | break :blk_1 false; | ||
| 5707 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5708 | p.i = pos_0; | ||
| 5709 | break :blk_0 false; | ||
| 5710 | }; | ||
| 5711 | } | ||
| 5712 | pub fn parseKEYWORD_anytype(p: *Parser) Error!bool { | ||
| 5713 | const def_index = @intFromEnum(Def.defKEYWORD_anytype); | ||
| 5714 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5715 | p.depths[def_index] += 1; | ||
| 5716 | defer p.depths[def_index] -= 1; | ||
| 5717 | return blk_0: { | ||
| 5718 | const pos_0 = p.i; | ||
| 5719 | if (try p.parseskip() and blk_1: { | ||
| 5720 | if (std.mem.startsWith(u8, p.source[p.i..], "anytype")) { | ||
| 5721 | p.i += 7; | ||
| 5722 | break :blk_1 true; | ||
| 5723 | } | ||
| 5724 | break :blk_1 false; | ||
| 5725 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5726 | p.i = pos_0; | ||
| 5727 | break :blk_0 false; | ||
| 5728 | }; | ||
| 5729 | } | ||
| 5730 | pub fn parseKEYWORD_asm(p: *Parser) Error!bool { | ||
| 5731 | const def_index = @intFromEnum(Def.defKEYWORD_asm); | ||
| 5732 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5733 | p.depths[def_index] += 1; | ||
| 5734 | defer p.depths[def_index] -= 1; | ||
| 5735 | return blk_0: { | ||
| 5736 | const pos_0 = p.i; | ||
| 5737 | if (try p.parseskip() and blk_1: { | ||
| 5738 | if (std.mem.startsWith(u8, p.source[p.i..], "asm")) { | ||
| 5739 | p.i += 3; | ||
| 5740 | break :blk_1 true; | ||
| 5741 | } | ||
| 5742 | break :blk_1 false; | ||
| 5743 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5744 | p.i = pos_0; | ||
| 5745 | break :blk_0 false; | ||
| 5746 | }; | ||
| 5747 | } | ||
| 5748 | pub fn parseKEYWORD_break(p: *Parser) Error!bool { | ||
| 5749 | const def_index = @intFromEnum(Def.defKEYWORD_break); | ||
| 5750 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5751 | p.depths[def_index] += 1; | ||
| 5752 | defer p.depths[def_index] -= 1; | ||
| 5753 | return blk_0: { | ||
| 5754 | const pos_0 = p.i; | ||
| 5755 | if (try p.parseskip() and blk_1: { | ||
| 5756 | if (std.mem.startsWith(u8, p.source[p.i..], "break")) { | ||
| 5757 | p.i += 5; | ||
| 5758 | break :blk_1 true; | ||
| 5759 | } | ||
| 5760 | break :blk_1 false; | ||
| 5761 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5762 | p.i = pos_0; | ||
| 5763 | break :blk_0 false; | ||
| 5764 | }; | ||
| 5765 | } | ||
| 5766 | pub fn parseKEYWORD_callconv(p: *Parser) Error!bool { | ||
| 5767 | const def_index = @intFromEnum(Def.defKEYWORD_callconv); | ||
| 5768 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5769 | p.depths[def_index] += 1; | ||
| 5770 | defer p.depths[def_index] -= 1; | ||
| 5771 | return blk_0: { | ||
| 5772 | const pos_0 = p.i; | ||
| 5773 | if (try p.parseskip() and blk_1: { | ||
| 5774 | if (std.mem.startsWith(u8, p.source[p.i..], "callconv")) { | ||
| 5775 | p.i += 8; | ||
| 5776 | break :blk_1 true; | ||
| 5777 | } | ||
| 5778 | break :blk_1 false; | ||
| 5779 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5780 | p.i = pos_0; | ||
| 5781 | break :blk_0 false; | ||
| 5782 | }; | ||
| 5783 | } | ||
| 5784 | pub fn parseKEYWORD_catch(p: *Parser) Error!bool { | ||
| 5785 | const def_index = @intFromEnum(Def.defKEYWORD_catch); | ||
| 5786 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5787 | p.depths[def_index] += 1; | ||
| 5788 | defer p.depths[def_index] -= 1; | ||
| 5789 | return blk_0: { | ||
| 5790 | const pos_0 = p.i; | ||
| 5791 | if (try p.parseskip() and blk_1: { | ||
| 5792 | if (std.mem.startsWith(u8, p.source[p.i..], "catch")) { | ||
| 5793 | p.i += 5; | ||
| 5794 | break :blk_1 true; | ||
| 5795 | } | ||
| 5796 | break :blk_1 false; | ||
| 5797 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5798 | p.i = pos_0; | ||
| 5799 | break :blk_0 false; | ||
| 5800 | }; | ||
| 5801 | } | ||
| 5802 | pub fn parseKEYWORD_comptime(p: *Parser) Error!bool { | ||
| 5803 | const def_index = @intFromEnum(Def.defKEYWORD_comptime); | ||
| 5804 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5805 | p.depths[def_index] += 1; | ||
| 5806 | defer p.depths[def_index] -= 1; | ||
| 5807 | return blk_0: { | ||
| 5808 | const pos_0 = p.i; | ||
| 5809 | if (try p.parseskip() and blk_1: { | ||
| 5810 | if (std.mem.startsWith(u8, p.source[p.i..], "comptime")) { | ||
| 5811 | p.i += 8; | ||
| 5812 | break :blk_1 true; | ||
| 5813 | } | ||
| 5814 | break :blk_1 false; | ||
| 5815 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5816 | p.i = pos_0; | ||
| 5817 | break :blk_0 false; | ||
| 5818 | }; | ||
| 5819 | } | ||
| 5820 | pub fn parseKEYWORD_const(p: *Parser) Error!bool { | ||
| 5821 | const def_index = @intFromEnum(Def.defKEYWORD_const); | ||
| 5822 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5823 | p.depths[def_index] += 1; | ||
| 5824 | defer p.depths[def_index] -= 1; | ||
| 5825 | return blk_0: { | ||
| 5826 | const pos_0 = p.i; | ||
| 5827 | if (try p.parseskip() and blk_1: { | ||
| 5828 | if (std.mem.startsWith(u8, p.source[p.i..], "const")) { | ||
| 5829 | p.i += 5; | ||
| 5830 | break :blk_1 true; | ||
| 5831 | } | ||
| 5832 | break :blk_1 false; | ||
| 5833 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5834 | p.i = pos_0; | ||
| 5835 | break :blk_0 false; | ||
| 5836 | }; | ||
| 5837 | } | ||
| 5838 | pub fn parseKEYWORD_continue(p: *Parser) Error!bool { | ||
| 5839 | const def_index = @intFromEnum(Def.defKEYWORD_continue); | ||
| 5840 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5841 | p.depths[def_index] += 1; | ||
| 5842 | defer p.depths[def_index] -= 1; | ||
| 5843 | return blk_0: { | ||
| 5844 | const pos_0 = p.i; | ||
| 5845 | if (try p.parseskip() and blk_1: { | ||
| 5846 | if (std.mem.startsWith(u8, p.source[p.i..], "continue")) { | ||
| 5847 | p.i += 8; | ||
| 5848 | break :blk_1 true; | ||
| 5849 | } | ||
| 5850 | break :blk_1 false; | ||
| 5851 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5852 | p.i = pos_0; | ||
| 5853 | break :blk_0 false; | ||
| 5854 | }; | ||
| 5855 | } | ||
| 5856 | pub fn parseKEYWORD_defer(p: *Parser) Error!bool { | ||
| 5857 | const def_index = @intFromEnum(Def.defKEYWORD_defer); | ||
| 5858 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5859 | p.depths[def_index] += 1; | ||
| 5860 | defer p.depths[def_index] -= 1; | ||
| 5861 | return blk_0: { | ||
| 5862 | const pos_0 = p.i; | ||
| 5863 | if (try p.parseskip() and blk_1: { | ||
| 5864 | if (std.mem.startsWith(u8, p.source[p.i..], "defer")) { | ||
| 5865 | p.i += 5; | ||
| 5866 | break :blk_1 true; | ||
| 5867 | } | ||
| 5868 | break :blk_1 false; | ||
| 5869 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5870 | p.i = pos_0; | ||
| 5871 | break :blk_0 false; | ||
| 5872 | }; | ||
| 5873 | } | ||
| 5874 | pub fn parseKEYWORD_else(p: *Parser) Error!bool { | ||
| 5875 | const def_index = @intFromEnum(Def.defKEYWORD_else); | ||
| 5876 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5877 | p.depths[def_index] += 1; | ||
| 5878 | defer p.depths[def_index] -= 1; | ||
| 5879 | return blk_0: { | ||
| 5880 | const pos_0 = p.i; | ||
| 5881 | if (try p.parseskip() and blk_1: { | ||
| 5882 | if (std.mem.startsWith(u8, p.source[p.i..], "else")) { | ||
| 5883 | p.i += 4; | ||
| 5884 | break :blk_1 true; | ||
| 5885 | } | ||
| 5886 | break :blk_1 false; | ||
| 5887 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5888 | p.i = pos_0; | ||
| 5889 | break :blk_0 false; | ||
| 5890 | }; | ||
| 5891 | } | ||
| 5892 | pub fn parseKEYWORD_enum(p: *Parser) Error!bool { | ||
| 5893 | const def_index = @intFromEnum(Def.defKEYWORD_enum); | ||
| 5894 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5895 | p.depths[def_index] += 1; | ||
| 5896 | defer p.depths[def_index] -= 1; | ||
| 5897 | return blk_0: { | ||
| 5898 | const pos_0 = p.i; | ||
| 5899 | if (try p.parseskip() and blk_1: { | ||
| 5900 | if (std.mem.startsWith(u8, p.source[p.i..], "enum")) { | ||
| 5901 | p.i += 4; | ||
| 5902 | break :blk_1 true; | ||
| 5903 | } | ||
| 5904 | break :blk_1 false; | ||
| 5905 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5906 | p.i = pos_0; | ||
| 5907 | break :blk_0 false; | ||
| 5908 | }; | ||
| 5909 | } | ||
| 5910 | pub fn parseKEYWORD_errdefer(p: *Parser) Error!bool { | ||
| 5911 | const def_index = @intFromEnum(Def.defKEYWORD_errdefer); | ||
| 5912 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5913 | p.depths[def_index] += 1; | ||
| 5914 | defer p.depths[def_index] -= 1; | ||
| 5915 | return blk_0: { | ||
| 5916 | const pos_0 = p.i; | ||
| 5917 | if (try p.parseskip() and blk_1: { | ||
| 5918 | if (std.mem.startsWith(u8, p.source[p.i..], "errdefer")) { | ||
| 5919 | p.i += 8; | ||
| 5920 | break :blk_1 true; | ||
| 5921 | } | ||
| 5922 | break :blk_1 false; | ||
| 5923 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5924 | p.i = pos_0; | ||
| 5925 | break :blk_0 false; | ||
| 5926 | }; | ||
| 5927 | } | ||
| 5928 | pub fn parseKEYWORD_error(p: *Parser) Error!bool { | ||
| 5929 | const def_index = @intFromEnum(Def.defKEYWORD_error); | ||
| 5930 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5931 | p.depths[def_index] += 1; | ||
| 5932 | defer p.depths[def_index] -= 1; | ||
| 5933 | return blk_0: { | ||
| 5934 | const pos_0 = p.i; | ||
| 5935 | if (try p.parseskip() and blk_1: { | ||
| 5936 | if (std.mem.startsWith(u8, p.source[p.i..], "error")) { | ||
| 5937 | p.i += 5; | ||
| 5938 | break :blk_1 true; | ||
| 5939 | } | ||
| 5940 | break :blk_1 false; | ||
| 5941 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5942 | p.i = pos_0; | ||
| 5943 | break :blk_0 false; | ||
| 5944 | }; | ||
| 5945 | } | ||
| 5946 | pub fn parseKEYWORD_export(p: *Parser) Error!bool { | ||
| 5947 | const def_index = @intFromEnum(Def.defKEYWORD_export); | ||
| 5948 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5949 | p.depths[def_index] += 1; | ||
| 5950 | defer p.depths[def_index] -= 1; | ||
| 5951 | return blk_0: { | ||
| 5952 | const pos_0 = p.i; | ||
| 5953 | if (try p.parseskip() and blk_1: { | ||
| 5954 | if (std.mem.startsWith(u8, p.source[p.i..], "export")) { | ||
| 5955 | p.i += 6; | ||
| 5956 | break :blk_1 true; | ||
| 5957 | } | ||
| 5958 | break :blk_1 false; | ||
| 5959 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5960 | p.i = pos_0; | ||
| 5961 | break :blk_0 false; | ||
| 5962 | }; | ||
| 5963 | } | ||
| 5964 | pub fn parseKEYWORD_extern(p: *Parser) Error!bool { | ||
| 5965 | const def_index = @intFromEnum(Def.defKEYWORD_extern); | ||
| 5966 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5967 | p.depths[def_index] += 1; | ||
| 5968 | defer p.depths[def_index] -= 1; | ||
| 5969 | return blk_0: { | ||
| 5970 | const pos_0 = p.i; | ||
| 5971 | if (try p.parseskip() and blk_1: { | ||
| 5972 | if (std.mem.startsWith(u8, p.source[p.i..], "extern")) { | ||
| 5973 | p.i += 6; | ||
| 5974 | break :blk_1 true; | ||
| 5975 | } | ||
| 5976 | break :blk_1 false; | ||
| 5977 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5978 | p.i = pos_0; | ||
| 5979 | break :blk_0 false; | ||
| 5980 | }; | ||
| 5981 | } | ||
| 5982 | pub fn parseKEYWORD_fn(p: *Parser) Error!bool { | ||
| 5983 | const def_index = @intFromEnum(Def.defKEYWORD_fn); | ||
| 5984 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 5985 | p.depths[def_index] += 1; | ||
| 5986 | defer p.depths[def_index] -= 1; | ||
| 5987 | return blk_0: { | ||
| 5988 | const pos_0 = p.i; | ||
| 5989 | if (try p.parseskip() and blk_1: { | ||
| 5990 | if (std.mem.startsWith(u8, p.source[p.i..], "fn")) { | ||
| 5991 | p.i += 2; | ||
| 5992 | break :blk_1 true; | ||
| 5993 | } | ||
| 5994 | break :blk_1 false; | ||
| 5995 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 5996 | p.i = pos_0; | ||
| 5997 | break :blk_0 false; | ||
| 5998 | }; | ||
| 5999 | } | ||
| 6000 | pub fn parseKEYWORD_for(p: *Parser) Error!bool { | ||
| 6001 | const def_index = @intFromEnum(Def.defKEYWORD_for); | ||
| 6002 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6003 | p.depths[def_index] += 1; | ||
| 6004 | defer p.depths[def_index] -= 1; | ||
| 6005 | return blk_0: { | ||
| 6006 | const pos_0 = p.i; | ||
| 6007 | if (try p.parseskip() and blk_1: { | ||
| 6008 | if (std.mem.startsWith(u8, p.source[p.i..], "for")) { | ||
| 6009 | p.i += 3; | ||
| 6010 | break :blk_1 true; | ||
| 6011 | } | ||
| 6012 | break :blk_1 false; | ||
| 6013 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6014 | p.i = pos_0; | ||
| 6015 | break :blk_0 false; | ||
| 6016 | }; | ||
| 6017 | } | ||
| 6018 | pub fn parseKEYWORD_if(p: *Parser) Error!bool { | ||
| 6019 | const def_index = @intFromEnum(Def.defKEYWORD_if); | ||
| 6020 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6021 | p.depths[def_index] += 1; | ||
| 6022 | defer p.depths[def_index] -= 1; | ||
| 6023 | return blk_0: { | ||
| 6024 | const pos_0 = p.i; | ||
| 6025 | if (try p.parseskip() and blk_1: { | ||
| 6026 | if (std.mem.startsWith(u8, p.source[p.i..], "if")) { | ||
| 6027 | p.i += 2; | ||
| 6028 | break :blk_1 true; | ||
| 6029 | } | ||
| 6030 | break :blk_1 false; | ||
| 6031 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6032 | p.i = pos_0; | ||
| 6033 | break :blk_0 false; | ||
| 6034 | }; | ||
| 6035 | } | ||
| 6036 | pub fn parseKEYWORD_inline(p: *Parser) Error!bool { | ||
| 6037 | const def_index = @intFromEnum(Def.defKEYWORD_inline); | ||
| 6038 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6039 | p.depths[def_index] += 1; | ||
| 6040 | defer p.depths[def_index] -= 1; | ||
| 6041 | return blk_0: { | ||
| 6042 | const pos_0 = p.i; | ||
| 6043 | if (try p.parseskip() and blk_1: { | ||
| 6044 | if (std.mem.startsWith(u8, p.source[p.i..], "inline")) { | ||
| 6045 | p.i += 6; | ||
| 6046 | break :blk_1 true; | ||
| 6047 | } | ||
| 6048 | break :blk_1 false; | ||
| 6049 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6050 | p.i = pos_0; | ||
| 6051 | break :blk_0 false; | ||
| 6052 | }; | ||
| 6053 | } | ||
| 6054 | pub fn parseKEYWORD_noalias(p: *Parser) Error!bool { | ||
| 6055 | const def_index = @intFromEnum(Def.defKEYWORD_noalias); | ||
| 6056 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6057 | p.depths[def_index] += 1; | ||
| 6058 | defer p.depths[def_index] -= 1; | ||
| 6059 | return blk_0: { | ||
| 6060 | const pos_0 = p.i; | ||
| 6061 | if (try p.parseskip() and blk_1: { | ||
| 6062 | if (std.mem.startsWith(u8, p.source[p.i..], "noalias")) { | ||
| 6063 | p.i += 7; | ||
| 6064 | break :blk_1 true; | ||
| 6065 | } | ||
| 6066 | break :blk_1 false; | ||
| 6067 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6068 | p.i = pos_0; | ||
| 6069 | break :blk_0 false; | ||
| 6070 | }; | ||
| 6071 | } | ||
| 6072 | pub fn parseKEYWORD_nosuspend(p: *Parser) Error!bool { | ||
| 6073 | const def_index = @intFromEnum(Def.defKEYWORD_nosuspend); | ||
| 6074 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6075 | p.depths[def_index] += 1; | ||
| 6076 | defer p.depths[def_index] -= 1; | ||
| 6077 | return blk_0: { | ||
| 6078 | const pos_0 = p.i; | ||
| 6079 | if (try p.parseskip() and blk_1: { | ||
| 6080 | if (std.mem.startsWith(u8, p.source[p.i..], "nosuspend")) { | ||
| 6081 | p.i += 9; | ||
| 6082 | break :blk_1 true; | ||
| 6083 | } | ||
| 6084 | break :blk_1 false; | ||
| 6085 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6086 | p.i = pos_0; | ||
| 6087 | break :blk_0 false; | ||
| 6088 | }; | ||
| 6089 | } | ||
| 6090 | pub fn parseKEYWORD_noinline(p: *Parser) Error!bool { | ||
| 6091 | const def_index = @intFromEnum(Def.defKEYWORD_noinline); | ||
| 6092 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6093 | p.depths[def_index] += 1; | ||
| 6094 | defer p.depths[def_index] -= 1; | ||
| 6095 | return blk_0: { | ||
| 6096 | const pos_0 = p.i; | ||
| 6097 | if (try p.parseskip() and blk_1: { | ||
| 6098 | if (std.mem.startsWith(u8, p.source[p.i..], "noinline")) { | ||
| 6099 | p.i += 8; | ||
| 6100 | break :blk_1 true; | ||
| 6101 | } | ||
| 6102 | break :blk_1 false; | ||
| 6103 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6104 | p.i = pos_0; | ||
| 6105 | break :blk_0 false; | ||
| 6106 | }; | ||
| 6107 | } | ||
| 6108 | pub fn parseKEYWORD_opaque(p: *Parser) Error!bool { | ||
| 6109 | const def_index = @intFromEnum(Def.defKEYWORD_opaque); | ||
| 6110 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6111 | p.depths[def_index] += 1; | ||
| 6112 | defer p.depths[def_index] -= 1; | ||
| 6113 | return blk_0: { | ||
| 6114 | const pos_0 = p.i; | ||
| 6115 | if (try p.parseskip() and blk_1: { | ||
| 6116 | if (std.mem.startsWith(u8, p.source[p.i..], "opaque")) { | ||
| 6117 | p.i += 6; | ||
| 6118 | break :blk_1 true; | ||
| 6119 | } | ||
| 6120 | break :blk_1 false; | ||
| 6121 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6122 | p.i = pos_0; | ||
| 6123 | break :blk_0 false; | ||
| 6124 | }; | ||
| 6125 | } | ||
| 6126 | pub fn parseKEYWORD_or(p: *Parser) Error!bool { | ||
| 6127 | const def_index = @intFromEnum(Def.defKEYWORD_or); | ||
| 6128 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6129 | p.depths[def_index] += 1; | ||
| 6130 | defer p.depths[def_index] -= 1; | ||
| 6131 | return blk_0: { | ||
| 6132 | const pos_0 = p.i; | ||
| 6133 | if (try p.parseskip() and blk_1: { | ||
| 6134 | if (std.mem.startsWith(u8, p.source[p.i..], "or")) { | ||
| 6135 | p.i += 2; | ||
| 6136 | break :blk_1 true; | ||
| 6137 | } | ||
| 6138 | break :blk_1 false; | ||
| 6139 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6140 | p.i = pos_0; | ||
| 6141 | break :blk_0 false; | ||
| 6142 | }; | ||
| 6143 | } | ||
| 6144 | pub fn parseKEYWORD_orelse(p: *Parser) Error!bool { | ||
| 6145 | const def_index = @intFromEnum(Def.defKEYWORD_orelse); | ||
| 6146 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6147 | p.depths[def_index] += 1; | ||
| 6148 | defer p.depths[def_index] -= 1; | ||
| 6149 | return blk_0: { | ||
| 6150 | const pos_0 = p.i; | ||
| 6151 | if (try p.parseskip() and blk_1: { | ||
| 6152 | if (std.mem.startsWith(u8, p.source[p.i..], "orelse")) { | ||
| 6153 | p.i += 6; | ||
| 6154 | break :blk_1 true; | ||
| 6155 | } | ||
| 6156 | break :blk_1 false; | ||
| 6157 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6158 | p.i = pos_0; | ||
| 6159 | break :blk_0 false; | ||
| 6160 | }; | ||
| 6161 | } | ||
| 6162 | pub fn parseKEYWORD_packed(p: *Parser) Error!bool { | ||
| 6163 | const def_index = @intFromEnum(Def.defKEYWORD_packed); | ||
| 6164 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6165 | p.depths[def_index] += 1; | ||
| 6166 | defer p.depths[def_index] -= 1; | ||
| 6167 | return blk_0: { | ||
| 6168 | const pos_0 = p.i; | ||
| 6169 | if (try p.parseskip() and blk_1: { | ||
| 6170 | if (std.mem.startsWith(u8, p.source[p.i..], "packed")) { | ||
| 6171 | p.i += 6; | ||
| 6172 | break :blk_1 true; | ||
| 6173 | } | ||
| 6174 | break :blk_1 false; | ||
| 6175 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6176 | p.i = pos_0; | ||
| 6177 | break :blk_0 false; | ||
| 6178 | }; | ||
| 6179 | } | ||
| 6180 | pub fn parseKEYWORD_pub(p: *Parser) Error!bool { | ||
| 6181 | const def_index = @intFromEnum(Def.defKEYWORD_pub); | ||
| 6182 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6183 | p.depths[def_index] += 1; | ||
| 6184 | defer p.depths[def_index] -= 1; | ||
| 6185 | return blk_0: { | ||
| 6186 | const pos_0 = p.i; | ||
| 6187 | if (try p.parseskip() and blk_1: { | ||
| 6188 | if (std.mem.startsWith(u8, p.source[p.i..], "pub")) { | ||
| 6189 | p.i += 3; | ||
| 6190 | break :blk_1 true; | ||
| 6191 | } | ||
| 6192 | break :blk_1 false; | ||
| 6193 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6194 | p.i = pos_0; | ||
| 6195 | break :blk_0 false; | ||
| 6196 | }; | ||
| 6197 | } | ||
| 6198 | pub fn parseKEYWORD_resume(p: *Parser) Error!bool { | ||
| 6199 | const def_index = @intFromEnum(Def.defKEYWORD_resume); | ||
| 6200 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6201 | p.depths[def_index] += 1; | ||
| 6202 | defer p.depths[def_index] -= 1; | ||
| 6203 | return blk_0: { | ||
| 6204 | const pos_0 = p.i; | ||
| 6205 | if (try p.parseskip() and blk_1: { | ||
| 6206 | if (std.mem.startsWith(u8, p.source[p.i..], "resume")) { | ||
| 6207 | p.i += 6; | ||
| 6208 | break :blk_1 true; | ||
| 6209 | } | ||
| 6210 | break :blk_1 false; | ||
| 6211 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6212 | p.i = pos_0; | ||
| 6213 | break :blk_0 false; | ||
| 6214 | }; | ||
| 6215 | } | ||
| 6216 | pub fn parseKEYWORD_return(p: *Parser) Error!bool { | ||
| 6217 | const def_index = @intFromEnum(Def.defKEYWORD_return); | ||
| 6218 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6219 | p.depths[def_index] += 1; | ||
| 6220 | defer p.depths[def_index] -= 1; | ||
| 6221 | return blk_0: { | ||
| 6222 | const pos_0 = p.i; | ||
| 6223 | if (try p.parseskip() and blk_1: { | ||
| 6224 | if (std.mem.startsWith(u8, p.source[p.i..], "return")) { | ||
| 6225 | p.i += 6; | ||
| 6226 | break :blk_1 true; | ||
| 6227 | } | ||
| 6228 | break :blk_1 false; | ||
| 6229 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6230 | p.i = pos_0; | ||
| 6231 | break :blk_0 false; | ||
| 6232 | }; | ||
| 6233 | } | ||
| 6234 | pub fn parseKEYWORD_linksection(p: *Parser) Error!bool { | ||
| 6235 | const def_index = @intFromEnum(Def.defKEYWORD_linksection); | ||
| 6236 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6237 | p.depths[def_index] += 1; | ||
| 6238 | defer p.depths[def_index] -= 1; | ||
| 6239 | return blk_0: { | ||
| 6240 | const pos_0 = p.i; | ||
| 6241 | if (try p.parseskip() and blk_1: { | ||
| 6242 | if (std.mem.startsWith(u8, p.source[p.i..], "linksection")) { | ||
| 6243 | p.i += 11; | ||
| 6244 | break :blk_1 true; | ||
| 6245 | } | ||
| 6246 | break :blk_1 false; | ||
| 6247 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6248 | p.i = pos_0; | ||
| 6249 | break :blk_0 false; | ||
| 6250 | }; | ||
| 6251 | } | ||
| 6252 | pub fn parseKEYWORD_struct(p: *Parser) Error!bool { | ||
| 6253 | const def_index = @intFromEnum(Def.defKEYWORD_struct); | ||
| 6254 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6255 | p.depths[def_index] += 1; | ||
| 6256 | defer p.depths[def_index] -= 1; | ||
| 6257 | return blk_0: { | ||
| 6258 | const pos_0 = p.i; | ||
| 6259 | if (try p.parseskip() and blk_1: { | ||
| 6260 | if (std.mem.startsWith(u8, p.source[p.i..], "struct")) { | ||
| 6261 | p.i += 6; | ||
| 6262 | break :blk_1 true; | ||
| 6263 | } | ||
| 6264 | break :blk_1 false; | ||
| 6265 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6266 | p.i = pos_0; | ||
| 6267 | break :blk_0 false; | ||
| 6268 | }; | ||
| 6269 | } | ||
| 6270 | pub fn parseKEYWORD_suspend(p: *Parser) Error!bool { | ||
| 6271 | const def_index = @intFromEnum(Def.defKEYWORD_suspend); | ||
| 6272 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6273 | p.depths[def_index] += 1; | ||
| 6274 | defer p.depths[def_index] -= 1; | ||
| 6275 | return blk_0: { | ||
| 6276 | const pos_0 = p.i; | ||
| 6277 | if (try p.parseskip() and blk_1: { | ||
| 6278 | if (std.mem.startsWith(u8, p.source[p.i..], "suspend")) { | ||
| 6279 | p.i += 7; | ||
| 6280 | break :blk_1 true; | ||
| 6281 | } | ||
| 6282 | break :blk_1 false; | ||
| 6283 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6284 | p.i = pos_0; | ||
| 6285 | break :blk_0 false; | ||
| 6286 | }; | ||
| 6287 | } | ||
| 6288 | pub fn parseKEYWORD_switch(p: *Parser) Error!bool { | ||
| 6289 | const def_index = @intFromEnum(Def.defKEYWORD_switch); | ||
| 6290 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6291 | p.depths[def_index] += 1; | ||
| 6292 | defer p.depths[def_index] -= 1; | ||
| 6293 | return blk_0: { | ||
| 6294 | const pos_0 = p.i; | ||
| 6295 | if (try p.parseskip() and blk_1: { | ||
| 6296 | if (std.mem.startsWith(u8, p.source[p.i..], "switch")) { | ||
| 6297 | p.i += 6; | ||
| 6298 | break :blk_1 true; | ||
| 6299 | } | ||
| 6300 | break :blk_1 false; | ||
| 6301 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6302 | p.i = pos_0; | ||
| 6303 | break :blk_0 false; | ||
| 6304 | }; | ||
| 6305 | } | ||
| 6306 | pub fn parseKEYWORD_test(p: *Parser) Error!bool { | ||
| 6307 | const def_index = @intFromEnum(Def.defKEYWORD_test); | ||
| 6308 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6309 | p.depths[def_index] += 1; | ||
| 6310 | defer p.depths[def_index] -= 1; | ||
| 6311 | return blk_0: { | ||
| 6312 | const pos_0 = p.i; | ||
| 6313 | if (try p.parseskip() and blk_1: { | ||
| 6314 | if (std.mem.startsWith(u8, p.source[p.i..], "test")) { | ||
| 6315 | p.i += 4; | ||
| 6316 | break :blk_1 true; | ||
| 6317 | } | ||
| 6318 | break :blk_1 false; | ||
| 6319 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6320 | p.i = pos_0; | ||
| 6321 | break :blk_0 false; | ||
| 6322 | }; | ||
| 6323 | } | ||
| 6324 | pub fn parseKEYWORD_threadlocal(p: *Parser) Error!bool { | ||
| 6325 | const def_index = @intFromEnum(Def.defKEYWORD_threadlocal); | ||
| 6326 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6327 | p.depths[def_index] += 1; | ||
| 6328 | defer p.depths[def_index] -= 1; | ||
| 6329 | return blk_0: { | ||
| 6330 | const pos_0 = p.i; | ||
| 6331 | if (try p.parseskip() and blk_1: { | ||
| 6332 | if (std.mem.startsWith(u8, p.source[p.i..], "threadlocal")) { | ||
| 6333 | p.i += 11; | ||
| 6334 | break :blk_1 true; | ||
| 6335 | } | ||
| 6336 | break :blk_1 false; | ||
| 6337 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6338 | p.i = pos_0; | ||
| 6339 | break :blk_0 false; | ||
| 6340 | }; | ||
| 6341 | } | ||
| 6342 | pub fn parseKEYWORD_try(p: *Parser) Error!bool { | ||
| 6343 | const def_index = @intFromEnum(Def.defKEYWORD_try); | ||
| 6344 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6345 | p.depths[def_index] += 1; | ||
| 6346 | defer p.depths[def_index] -= 1; | ||
| 6347 | return blk_0: { | ||
| 6348 | const pos_0 = p.i; | ||
| 6349 | if (try p.parseskip() and blk_1: { | ||
| 6350 | if (std.mem.startsWith(u8, p.source[p.i..], "try")) { | ||
| 6351 | p.i += 3; | ||
| 6352 | break :blk_1 true; | ||
| 6353 | } | ||
| 6354 | break :blk_1 false; | ||
| 6355 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6356 | p.i = pos_0; | ||
| 6357 | break :blk_0 false; | ||
| 6358 | }; | ||
| 6359 | } | ||
| 6360 | pub fn parseKEYWORD_union(p: *Parser) Error!bool { | ||
| 6361 | const def_index = @intFromEnum(Def.defKEYWORD_union); | ||
| 6362 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6363 | p.depths[def_index] += 1; | ||
| 6364 | defer p.depths[def_index] -= 1; | ||
| 6365 | return blk_0: { | ||
| 6366 | const pos_0 = p.i; | ||
| 6367 | if (try p.parseskip() and blk_1: { | ||
| 6368 | if (std.mem.startsWith(u8, p.source[p.i..], "union")) { | ||
| 6369 | p.i += 5; | ||
| 6370 | break :blk_1 true; | ||
| 6371 | } | ||
| 6372 | break :blk_1 false; | ||
| 6373 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6374 | p.i = pos_0; | ||
| 6375 | break :blk_0 false; | ||
| 6376 | }; | ||
| 6377 | } | ||
| 6378 | pub fn parseKEYWORD_unreachable(p: *Parser) Error!bool { | ||
| 6379 | const def_index = @intFromEnum(Def.defKEYWORD_unreachable); | ||
| 6380 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6381 | p.depths[def_index] += 1; | ||
| 6382 | defer p.depths[def_index] -= 1; | ||
| 6383 | return blk_0: { | ||
| 6384 | const pos_0 = p.i; | ||
| 6385 | if (try p.parseskip() and blk_1: { | ||
| 6386 | if (std.mem.startsWith(u8, p.source[p.i..], "unreachable")) { | ||
| 6387 | p.i += 11; | ||
| 6388 | break :blk_1 true; | ||
| 6389 | } | ||
| 6390 | break :blk_1 false; | ||
| 6391 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6392 | p.i = pos_0; | ||
| 6393 | break :blk_0 false; | ||
| 6394 | }; | ||
| 6395 | } | ||
| 6396 | pub fn parseKEYWORD_var(p: *Parser) Error!bool { | ||
| 6397 | const def_index = @intFromEnum(Def.defKEYWORD_var); | ||
| 6398 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6399 | p.depths[def_index] += 1; | ||
| 6400 | defer p.depths[def_index] -= 1; | ||
| 6401 | return blk_0: { | ||
| 6402 | const pos_0 = p.i; | ||
| 6403 | if (try p.parseskip() and blk_1: { | ||
| 6404 | if (std.mem.startsWith(u8, p.source[p.i..], "var")) { | ||
| 6405 | p.i += 3; | ||
| 6406 | break :blk_1 true; | ||
| 6407 | } | ||
| 6408 | break :blk_1 false; | ||
| 6409 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6410 | p.i = pos_0; | ||
| 6411 | break :blk_0 false; | ||
| 6412 | }; | ||
| 6413 | } | ||
| 6414 | pub fn parseKEYWORD_volatile(p: *Parser) Error!bool { | ||
| 6415 | const def_index = @intFromEnum(Def.defKEYWORD_volatile); | ||
| 6416 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6417 | p.depths[def_index] += 1; | ||
| 6418 | defer p.depths[def_index] -= 1; | ||
| 6419 | return blk_0: { | ||
| 6420 | const pos_0 = p.i; | ||
| 6421 | if (try p.parseskip() and blk_1: { | ||
| 6422 | if (std.mem.startsWith(u8, p.source[p.i..], "volatile")) { | ||
| 6423 | p.i += 8; | ||
| 6424 | break :blk_1 true; | ||
| 6425 | } | ||
| 6426 | break :blk_1 false; | ||
| 6427 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6428 | p.i = pos_0; | ||
| 6429 | break :blk_0 false; | ||
| 6430 | }; | ||
| 6431 | } | ||
| 6432 | pub fn parseKEYWORD_while(p: *Parser) Error!bool { | ||
| 6433 | const def_index = @intFromEnum(Def.defKEYWORD_while); | ||
| 6434 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6435 | p.depths[def_index] += 1; | ||
| 6436 | defer p.depths[def_index] -= 1; | ||
| 6437 | return blk_0: { | ||
| 6438 | const pos_0 = p.i; | ||
| 6439 | if (try p.parseskip() and blk_1: { | ||
| 6440 | if (std.mem.startsWith(u8, p.source[p.i..], "while")) { | ||
| 6441 | p.i += 5; | ||
| 6442 | break :blk_1 true; | ||
| 6443 | } | ||
| 6444 | break :blk_1 false; | ||
| 6445 | } and try p.parseend_of_word()) break :blk_0 true; | ||
| 6446 | p.i = pos_0; | ||
| 6447 | break :blk_0 false; | ||
| 6448 | }; | ||
| 6449 | } | ||
| 6450 | pub fn parsekeyword(p: *Parser) Error!bool { | ||
| 6451 | const def_index = @intFromEnum(Def.defkeyword); | ||
| 6452 | if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 6453 | p.depths[def_index] += 1; | ||
| 6454 | defer p.depths[def_index] -= 1; | ||
| 6455 | return blk_0: { | ||
| 6456 | const pos_0 = p.i; | ||
| 6457 | if (try p.parseKEYWORD_addrspace()) break :blk_0 true; | ||
| 6458 | p.i = pos_0; | ||
| 6459 | if (try p.parseKEYWORD_align()) break :blk_0 true; | ||
| 6460 | p.i = pos_0; | ||
| 6461 | if (try p.parseKEYWORD_allowzero()) break :blk_0 true; | ||
| 6462 | p.i = pos_0; | ||
| 6463 | if (try p.parseKEYWORD_and()) break :blk_0 true; | ||
| 6464 | p.i = pos_0; | ||
| 6465 | if (try p.parseKEYWORD_anyframe()) break :blk_0 true; | ||
| 6466 | p.i = pos_0; | ||
| 6467 | if (try p.parseKEYWORD_anytype()) break :blk_0 true; | ||
| 6468 | p.i = pos_0; | ||
| 6469 | if (try p.parseKEYWORD_asm()) break :blk_0 true; | ||
| 6470 | p.i = pos_0; | ||
| 6471 | if (try p.parseKEYWORD_break()) break :blk_0 true; | ||
| 6472 | p.i = pos_0; | ||
| 6473 | if (try p.parseKEYWORD_callconv()) break :blk_0 true; | ||
| 6474 | p.i = pos_0; | ||
| 6475 | if (try p.parseKEYWORD_catch()) break :blk_0 true; | ||
| 6476 | p.i = pos_0; | ||
| 6477 | if (try p.parseKEYWORD_comptime()) break :blk_0 true; | ||
| 6478 | p.i = pos_0; | ||
| 6479 | if (try p.parseKEYWORD_const()) break :blk_0 true; | ||
| 6480 | p.i = pos_0; | ||
| 6481 | if (try p.parseKEYWORD_continue()) break :blk_0 true; | ||
| 6482 | p.i = pos_0; | ||
| 6483 | if (try p.parseKEYWORD_defer()) break :blk_0 true; | ||
| 6484 | p.i = pos_0; | ||
| 6485 | if (try p.parseKEYWORD_else()) break :blk_0 true; | ||
| 6486 | p.i = pos_0; | ||
| 6487 | if (try p.parseKEYWORD_enum()) break :blk_0 true; | ||
| 6488 | p.i = pos_0; | ||
| 6489 | if (try p.parseKEYWORD_errdefer()) break :blk_0 true; | ||
| 6490 | p.i = pos_0; | ||
| 6491 | if (try p.parseKEYWORD_error()) break :blk_0 true; | ||
| 6492 | p.i = pos_0; | ||
| 6493 | if (try p.parseKEYWORD_export()) break :blk_0 true; | ||
| 6494 | p.i = pos_0; | ||
| 6495 | if (try p.parseKEYWORD_extern()) break :blk_0 true; | ||
| 6496 | p.i = pos_0; | ||
| 6497 | if (try p.parseKEYWORD_fn()) break :blk_0 true; | ||
| 6498 | p.i = pos_0; | ||
| 6499 | if (try p.parseKEYWORD_for()) break :blk_0 true; | ||
| 6500 | p.i = pos_0; | ||
| 6501 | if (try p.parseKEYWORD_if()) break :blk_0 true; | ||
| 6502 | p.i = pos_0; | ||
| 6503 | if (try p.parseKEYWORD_inline()) break :blk_0 true; | ||
| 6504 | p.i = pos_0; | ||
| 6505 | if (try p.parseKEYWORD_noalias()) break :blk_0 true; | ||
| 6506 | p.i = pos_0; | ||
| 6507 | if (try p.parseKEYWORD_nosuspend()) break :blk_0 true; | ||
| 6508 | p.i = pos_0; | ||
| 6509 | if (try p.parseKEYWORD_noinline()) break :blk_0 true; | ||
| 6510 | p.i = pos_0; | ||
| 6511 | if (try p.parseKEYWORD_opaque()) break :blk_0 true; | ||
| 6512 | p.i = pos_0; | ||
| 6513 | if (try p.parseKEYWORD_or()) break :blk_0 true; | ||
| 6514 | p.i = pos_0; | ||
| 6515 | if (try p.parseKEYWORD_orelse()) break :blk_0 true; | ||
| 6516 | p.i = pos_0; | ||
| 6517 | if (try p.parseKEYWORD_packed()) break :blk_0 true; | ||
| 6518 | p.i = pos_0; | ||
| 6519 | if (try p.parseKEYWORD_pub()) break :blk_0 true; | ||
| 6520 | p.i = pos_0; | ||
| 6521 | if (try p.parseKEYWORD_resume()) break :blk_0 true; | ||
| 6522 | p.i = pos_0; | ||
| 6523 | if (try p.parseKEYWORD_return()) break :blk_0 true; | ||
| 6524 | p.i = pos_0; | ||
| 6525 | if (try p.parseKEYWORD_linksection()) break :blk_0 true; | ||
| 6526 | p.i = pos_0; | ||
| 6527 | if (try p.parseKEYWORD_struct()) break :blk_0 true; | ||
| 6528 | p.i = pos_0; | ||
| 6529 | if (try p.parseKEYWORD_suspend()) break :blk_0 true; | ||
| 6530 | p.i = pos_0; | ||
| 6531 | if (try p.parseKEYWORD_switch()) break :blk_0 true; | ||
| 6532 | p.i = pos_0; | ||
| 6533 | if (try p.parseKEYWORD_test()) break :blk_0 true; | ||
| 6534 | p.i = pos_0; | ||
| 6535 | if (try p.parseKEYWORD_threadlocal()) break :blk_0 true; | ||
| 6536 | p.i = pos_0; | ||
| 6537 | if (try p.parseKEYWORD_try()) break :blk_0 true; | ||
| 6538 | p.i = pos_0; | ||
| 6539 | if (try p.parseKEYWORD_union()) break :blk_0 true; | ||
| 6540 | p.i = pos_0; | ||
| 6541 | if (try p.parseKEYWORD_unreachable()) break :blk_0 true; | ||
| 6542 | p.i = pos_0; | ||
| 6543 | if (try p.parseKEYWORD_var()) break :blk_0 true; | ||
| 6544 | p.i = pos_0; | ||
| 6545 | if (try p.parseKEYWORD_volatile()) break :blk_0 true; | ||
| 6546 | p.i = pos_0; | ||
| 6547 | if (try p.parseKEYWORD_while()) break :blk_0 true; | ||
| 6548 | p.i = pos_0; | ||
| 6549 | break :blk_0 false; | ||
| 6550 | }; | ||
| 6551 | } | ||
| 6552 | }; | ||
lib/std/zig/parser_test.zig+7-269| ... | @@ -6976,6 +6976,7 @@ test "recovery: missing comma" { | ... | @@ -6976,6 +6976,7 @@ test "recovery: missing comma" { |
| 6976 | , &[_]Error{ | 6976 | , &[_]Error{ |
| 6977 | .expected_comma_after_switch_prong, | 6977 | .expected_comma_after_switch_prong, |
| 6978 | .expected_comma_after_switch_prong, | 6978 | .expected_comma_after_switch_prong, |
| 6979 | .mismatched_binary_op_whitespace, | ||
| 6979 | .expected_expr, | 6980 | .expected_expr, |
| 6980 | }); | 6981 | }); |
| 6981 | } | 6982 | } |
| ... | @@ -6992,10 +6993,10 @@ test "recovery: non-associative operators" { | ... | @@ -6992,10 +6993,10 @@ test "recovery: non-associative operators" { |
| 6992 | 6993 | ||
| 6993 | test "recovery: extra qualifier" { | 6994 | test "recovery: extra qualifier" { |
| 6994 | try testError( | 6995 | try testError( |
| 6995 | \\const a: *const const u8; | 6996 | \\const a: *align(4) align(8) u8; |
| 6996 | \\test "" | 6997 | \\test "" |
| 6997 | , &[_]Error{ | 6998 | , &[_]Error{ |
| 6998 | .extra_const_qualifier, | 6999 | .extra_align_qualifier, |
| 6999 | .expected_block, | 7000 | .expected_block, |
| 7000 | }); | 7001 | }); |
| 7001 | } | 7002 | } |
| ... | @@ -7230,7 +7231,7 @@ test "ampersand" { | ... | @@ -7230,7 +7231,7 @@ test "ampersand" { |
| 7230 | test "Ast: pointer types with subexprs containing qualifiers" { | 7231 | test "Ast: pointer types with subexprs containing qualifiers" { |
| 7231 | var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | 7232 | var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); |
| 7232 | const allocator = fixed_allocator.allocator(); | 7233 | const allocator = fixed_allocator.allocator(); |
| 7233 | var tree = try std.zig.Ast.parse(allocator, "**addrspace(*align(1)T)T", .zon); | 7234 | var tree = try std.zig.Ast.parse(allocator, "**addrspace(*align(1)T)T", .zon, .{}); |
| 7234 | defer tree.deinit(allocator); | 7235 | defer tree.deinit(allocator); |
| 7235 | 7236 | ||
| 7236 | const regular_ptr_node = tree.nodeData(.root).node; | 7237 | const regular_ptr_node = tree.nodeData(.root).node; |
| ... | @@ -7252,7 +7253,7 @@ fn testParse(io: Io, source: [:0]const u8, allocator: Allocator, anything_change | ... | @@ -7252,7 +7253,7 @@ fn testParse(io: Io, source: [:0]const u8, allocator: Allocator, anything_change |
| 7252 | defer io.unlockStderr(); | 7253 | defer io.unlockStderr(); |
| 7253 | const writer = &stderr.file_writer.interface; | 7254 | const writer = &stderr.file_writer.interface; |
| 7254 | 7255 | ||
| 7255 | var tree = try std.zig.Ast.parse(allocator, source, .zig); | 7256 | var tree = try std.zig.Ast.parse(allocator, source, .zig, .{}); |
| 7256 | defer tree.deinit(allocator); | 7257 | defer tree.deinit(allocator); |
| 7257 | 7258 | ||
| 7258 | for (tree.errors) |parse_error| { | 7259 | for (tree.errors) |parse_error| { |
| ... | @@ -7312,7 +7313,7 @@ fn testCanonical(source: [:0]const u8) !void { | ... | @@ -7312,7 +7313,7 @@ fn testCanonical(source: [:0]const u8) !void { |
| 7312 | const Error = std.zig.Ast.Error.Tag; | 7313 | const Error = std.zig.Ast.Error.Tag; |
| 7313 | 7314 | ||
| 7314 | fn testError(source: [:0]const u8, expected_errors: []const Error) !void { | 7315 | fn testError(source: [:0]const u8, expected_errors: []const Error) !void { |
| 7315 | var tree = try std.zig.Ast.parse(std.testing.allocator, source, .zig); | 7316 | var tree = try std.zig.Ast.parse(std.testing.allocator, source, .zig, .{}); |
| 7316 | defer tree.deinit(std.testing.allocator); | 7317 | defer tree.deinit(std.testing.allocator); |
| 7317 | 7318 | ||
| 7318 | std.testing.expectEqual(expected_errors.len, tree.errors.len) catch |err| { | 7319 | std.testing.expectEqual(expected_errors.len, tree.errors.len) catch |err| { |
| ... | @@ -7332,268 +7333,5 @@ fn fuzzTestOneParse(_: void, smith: *std.testing.Smith) !void { | ... | @@ -7332,268 +7333,5 @@ fn fuzzTestOneParse(_: void, smith: *std.testing.Smith) !void { |
| 7332 | const mode = smith.value(std.zig.Ast.Mode); | 7333 | const mode = smith.value(std.zig.Ast.Mode); |
| 7333 | var tokens: std.zig.TokenSmith = .gen(smith); | 7334 | var tokens: std.zig.TokenSmith = .gen(smith); |
| 7334 | var fba: std.heap.FixedBufferAllocator = .init(&fixed_buffer_mem); | 7335 | var fba: std.heap.FixedBufferAllocator = .init(&fixed_buffer_mem); |
| 7335 | _ = std.zig.Ast.parseTokens(fba.allocator(), tokens.source(), tokens.list(), mode) catch return; | 7336 | _ = std.zig.Ast.parseTokens(fba.allocator(), tokens.source(), tokens.list(), mode, .{ .recover = false }) catch return; |
| 7336 | } | ||
| 7337 | |||
| 7338 | test "zig fmt: fuzz" { | ||
| 7339 | try std.testing.fuzz({}, fuzzRender, .{}); | ||
| 7340 | } | ||
| 7341 | |||
| 7342 | fn isRewritable(source: []const u8, tokens: std.zig.Ast.TokenList.Slice) !bool { | ||
| 7343 | @disableInstrumentation(); | ||
| 7344 | |||
| 7345 | // Byte-order marker is stripped | ||
| 7346 | var maybe_rewritable = std.mem.startsWith(u8, source, "\xEF\xBB\xBF"); | ||
| 7347 | // The above variable can not yet be replaced by returns since error.SkipZigTest still needs to | ||
| 7348 | // be checked for. | ||
| 7349 | |||
| 7350 | for (0.., tokens.items(.tag), tokens.items(.start)) |i, tag, start| switch (tag) { | ||
| 7351 | // Extra colons can be removed | ||
| 7352 | .keyword_asm, | ||
| 7353 | // Qualifiers can be reordered | ||
| 7354 | // keyword_const is intentionally excluded since it is used in other contexts and | ||
| 7355 | // having only one qualifier will never lead to reordering. | ||
| 7356 | .keyword_addrspace, | ||
| 7357 | .keyword_align, | ||
| 7358 | .keyword_allowzero, | ||
| 7359 | .keyword_callconv, | ||
| 7360 | .keyword_linksection, | ||
| 7361 | .keyword_volatile, | ||
| 7362 | => maybe_rewritable = true, | ||
| 7363 | .builtin, | ||
| 7364 | // Pointer casts can be reordered | ||
| 7365 | => for ([_][]const u8{ | ||
| 7366 | "ptrCast", | ||
| 7367 | "alignCast", | ||
| 7368 | "addrSpaceCast", | ||
| 7369 | "constCast", | ||
| 7370 | "volatileCast", | ||
| 7371 | }) |id| { | ||
| 7372 | if (std.mem.startsWith(u8, source[start + 1 ..], id)) { | ||
| 7373 | maybe_rewritable = true; | ||
| 7374 | } | ||
| 7375 | }, | ||
| 7376 | // Quoted identifiers can be unquoted | ||
| 7377 | .identifier => if (source[start] == '@') { | ||
| 7378 | maybe_rewritable = true; | ||
| 7379 | }, | ||
| 7380 | else => {}, | ||
| 7381 | // #23754 | ||
| 7382 | .container_doc_comment, | ||
| 7383 | => if (std.mem.endsWith(Token.Tag, tokens.items(.tag)[0..i], &.{.l_brace})) { | ||
| 7384 | return error.SkipZigTest; // Can cause I.B. | ||
| 7385 | }, | ||
| 7386 | // #24507 | ||
| 7387 | .keyword_inline, | ||
| 7388 | .keyword_for, | ||
| 7389 | .keyword_while, | ||
| 7390 | .l_brace, | ||
| 7391 | => if (std.mem.endsWith(Token.Tag, tokens.items(.tag)[0..i], &.{ .identifier, .colon })) { | ||
| 7392 | return error.SkipZigTest; // Can cause I.B. due to double rendering of zig fmt on/off | ||
| 7393 | }, | ||
| 7394 | }; | ||
| 7395 | |||
| 7396 | return maybe_rewritable; | ||
| 7397 | } | ||
| 7398 | |||
| 7399 | /// Checks equivelence of non-whitespace characters. | ||
| 7400 | /// If there are commas in `source`, then it is checked they are also present | ||
| 7401 | /// in `rendered`. Extra commas in `rendered` are ignored. | ||
| 7402 | fn isRewritten(source: [:0]const u8, rendered: [:0]const u8) bool { | ||
| 7403 | @disableInstrumentation(); | ||
| 7404 | var i: usize = 0; | ||
| 7405 | for (source[0 .. source.len + 1]) |c| switch (c) { | ||
| 7406 | ' ', '\r', '\t', '\n' => {}, | ||
| 7407 | else => while (true) { | ||
| 7408 | defer i += 1; | ||
| 7409 | switch (rendered[i]) { | ||
| 7410 | ' ', '\n' => {}, | ||
| 7411 | ',' => if (c == ',') break, | ||
| 7412 | else => |r| if (c != r) return false else break, | ||
| 7413 | } | ||
| 7414 | }, | ||
| 7415 | }; | ||
| 7416 | std.debug.assert(i >= rendered.len); | ||
| 7417 | return false; | ||
| 7418 | } | ||
| 7419 | |||
| 7420 | /// Checks that no line ends in whitespace | ||
| 7421 | fn checkBetweenTokens(src: []const u8, fmt_on: *bool) error{ | ||
| 7422 | TrailingLineWhitespace, | ||
| 7423 | DoubleEmptyLine, | ||
| 7424 | }!void { | ||
| 7425 | @disableInstrumentation(); | ||
| 7426 | var pos: usize = 0; | ||
| 7427 | while (true) { | ||
| 7428 | const nl_pos = std.mem.indexOfScalarPos(u8, src, pos, '\n'); | ||
| 7429 | var check_trailing = fmt_on.*; | ||
| 7430 | |||
| 7431 | const line = src[pos .. nl_pos orelse src.len]; | ||
| 7432 | if (std.mem.indexOfScalar(u8, line, '/')) |comment_start| { | ||
| 7433 | const comment_content = line[comment_start..][2..]; | ||
| 7434 | const trimmed_comment = std.mem.trim(u8, comment_content, &std.ascii.whitespace); | ||
| 7435 | if (std.mem.eql(u8, trimmed_comment, "zig fmt: off")) { | ||
| 7436 | fmt_on.* = false; | ||
| 7437 | } else if (std.mem.eql(u8, trimmed_comment, "zig fmt: on")) { | ||
| 7438 | fmt_on.* = true; | ||
| 7439 | check_trailing = true; | ||
| 7440 | } | ||
| 7441 | } | ||
| 7442 | |||
| 7443 | pos = nl_pos orelse break; | ||
| 7444 | if (check_trailing and pos != 0) switch (src[pos - 1]) { | ||
| 7445 | ' ', '\t', '\r' => return error.TrailingLineWhitespace, | ||
| 7446 | '\n' => if (pos != 1 and src[pos - 2] == '\n') return error.DoubleEmptyLine, | ||
| 7447 | else => {}, | ||
| 7448 | }; | ||
| 7449 | pos += 1; | ||
| 7450 | } | ||
| 7451 | } | ||
| 7452 | |||
| 7453 | /// Ignores extre `.comma` tokens in `rendered` | ||
| 7454 | fn reparseTokens( | ||
| 7455 | fba: Allocator, | ||
| 7456 | rendered: [:0]const u8, | ||
| 7457 | expected_tags: [:.eof]const Token.Tag, | ||
| 7458 | ) error{ | ||
| 7459 | OutOfMemory, | ||
| 7460 | SameLineMultilineStringLiteral, | ||
| 7461 | TrailingLineWhitespace, | ||
| 7462 | DoubleEmptyLine, | ||
| 7463 | }!struct { | ||
| 7464 | toks: std.zig.Ast.TokenList, | ||
| 7465 | rewritten: bool, | ||
| 7466 | } { | ||
| 7467 | @disableInstrumentation(); | ||
| 7468 | var rewritten = false; | ||
| 7469 | var tokens: std.zig.Ast.TokenList = .{}; | ||
| 7470 | var last_token_end: usize = 0; | ||
| 7471 | var fmt_on = true; | ||
| 7472 | |||
| 7473 | try tokens.ensureTotalCapacity(fba, expected_tags.len + 2); // 1 for EOF and 1 for maybe a comma | ||
| 7474 | var tokenizer: std.zig.Tokenizer = .init(rendered); | ||
| 7475 | var i: usize = 0; | ||
| 7476 | while (true) { | ||
| 7477 | const tok = tokenizer.next(); | ||
| 7478 | try tokens.append(fba, .{ | ||
| 7479 | .tag = tok.tag, | ||
| 7480 | .start = @intCast(tok.loc.start), | ||
| 7481 | }); | ||
| 7482 | |||
| 7483 | const between = rendered[last_token_end..tok.loc.start]; | ||
| 7484 | last_token_end = tok.loc.end; | ||
| 7485 | try checkBetweenTokens(between, &fmt_on); | ||
| 7486 | if (tok.tag == .multiline_string_literal_line and fmt_on) blk: { | ||
| 7487 | if (tokens.len == 1) | ||
| 7488 | break :blk; // first token | ||
| 7489 | if (std.mem.indexOfScalar(u8, between, '\n') == null) | ||
| 7490 | return error.SameLineMultilineStringLiteral; | ||
| 7491 | } | ||
| 7492 | if (tok.tag == expected_tags[i]) { | ||
| 7493 | if (tok.tag == .eof) | ||
| 7494 | break; | ||
| 7495 | i += 1; | ||
| 7496 | } else if (tok.tag != .comma or !fmt_on) { | ||
| 7497 | rewritten = true; | ||
| 7498 | } | ||
| 7499 | } | ||
| 7500 | std.debug.assert(i == expected_tags.len); | ||
| 7501 | try checkBetweenTokens(rendered[last_token_end..], &fmt_on); | ||
| 7502 | |||
| 7503 | return .{ .toks = tokens, .rewritten = rewritten }; | ||
| 7504 | } | ||
| 7505 | |||
| 7506 | fn fuzzRender(_: void, smith: *std.testing.Smith) !void { | ||
| 7507 | @disableInstrumentation(); | ||
| 7508 | |||
| 7509 | var ast_smith: std.zig.AstSmith = .init(smith); | ||
| 7510 | try ast_smith.generateSource(); | ||
| 7511 | var fba_ctx = std.heap.FixedBufferAllocator.init(&fixed_buffer_mem); | ||
| 7512 | var opt_rendered: ?[]const u8 = null; | ||
| 7513 | fuzzRenderInner(&ast_smith, fba_ctx.allocator(), &opt_rendered) catch |e| switch (e) { | ||
| 7514 | error.SkipZigTest, error.OutOfMemory, error.WriteFailed => return error.SkipZigTest, | ||
| 7515 | else => |failure| { | ||
| 7516 | ast_smith.logSource(); | ||
| 7517 | if (opt_rendered) |rendered| { | ||
| 7518 | logRenderedSource(rendered); | ||
| 7519 | } | ||
| 7520 | return failure; | ||
| 7521 | }, | ||
| 7522 | }; | ||
| 7523 | } | ||
| 7524 | |||
| 7525 | fn fuzzRenderInner(ast_smith: *std.zig.AstSmith, fba: Allocator, opt_rendered: *?[]const u8) !void { | ||
| 7526 | @disableInstrumentation(); | ||
| 7527 | |||
| 7528 | const source = ast_smith.source(); | ||
| 7529 | const src_rewritable = try isRewritable(source, ast_smith.tokens()); | ||
| 7530 | const src_tree = try std.zig.Ast.parseTokens(fba, source, ast_smith.tokens(), .zig); | ||
| 7531 | std.debug.assert(src_tree.errors.len == 0); | ||
| 7532 | for (src_tree.nodes.items(.tag)) |tag| switch (tag) { | ||
| 7533 | // #24507 (`switch(x) { inline for (a) |a| a => {} }` to | ||
| 7534 | // `switch(x) { { inline for (a) |a| a => {} }` since | ||
| 7535 | // AST determines inline case token as one before the case expression's first) | ||
| 7536 | .switch_case_inline, .switch_case_inline_one => return error.SkipZigTest, | ||
| 7537 | else => {}, | ||
| 7538 | }; | ||
| 7539 | |||
| 7540 | var rendered_w: std.Io.Writer.Allocating = .init(fba); | ||
| 7541 | try rendered_w.ensureUnusedCapacity(source.len + source.len / 2); | ||
| 7542 | try src_tree.render(fba, &rendered_w.writer, .{}); | ||
| 7543 | // `toOwnedSliceSentinel` is not used since it reallocates the entire | ||
| 7544 | // list to save space which is useless for fixed buffer allocators. | ||
| 7545 | try rendered_w.writer.writeByte(0); | ||
| 7546 | const rendered = rendered_w.written()[0 .. rendered_w.written().len - 1 :0]; | ||
| 7547 | opt_rendered.* = rendered; | ||
| 7548 | |||
| 7549 | // First check that the non-whitespace characters match. This ensures that | ||
| 7550 | // identifier names, numbers, comments, et cetera are preserved. | ||
| 7551 | if (!src_rewritable and isRewritten(source, rendered)) | ||
| 7552 | return error.Rewritten; | ||
| 7553 | // Next check that the tokens are the same since whitespace removal can change the tokens | ||
| 7554 | const src_tags = ast_smith.tokens().items(.tag); | ||
| 7555 | const rendered_toks = try reparseTokens(fba, rendered, src_tags[0 .. src_tags.len - 1 :.eof]); | ||
| 7556 | if (!src_rewritable and rendered_toks.rewritten) | ||
| 7557 | return error.Rewritten; | ||
| 7558 | |||
| 7559 | // Rerender the tree to check idempotency and that new commas | ||
| 7560 | // and whitespace changes did not create an AST error. | ||
| 7561 | const rendered_tree = try std.zig.Ast.parseTokens(fba, rendered, rendered_toks.toks.slice(), .zig); | ||
| 7562 | if (rendered_tree.errors.len != 0) | ||
| 7563 | return error.Rewritten; | ||
| 7564 | var rerendered_w: std.Io.Writer.Allocating = .init(fba); | ||
| 7565 | try rerendered_w.ensureUnusedCapacity(source.len); | ||
| 7566 | try rendered_tree.render(fba, &rerendered_w.writer, .{}); | ||
| 7567 | try std.testing.expectEqualStrings(rendered, rerendered_w.written()); | ||
| 7568 | } | ||
| 7569 | |||
| 7570 | fn logRenderedSource(source: []const u8) void { | ||
| 7571 | var buf: [256]u8 = undefined; | ||
| 7572 | const ls = std.debug.lockStderr(&buf); | ||
| 7573 | defer std.debug.unlockStderr(); | ||
| 7574 | logRenderedSourceInner(source, ls.terminal()) catch {}; | ||
| 7575 | } | ||
| 7576 | |||
| 7577 | fn logRenderedSourceInner(source: []const u8, t: std.Io.Terminal) std.Io.Writer.Error!void { | ||
| 7578 | const w = t.writer; | ||
| 7579 | |||
| 7580 | t.setColor(.dim) catch {}; | ||
| 7581 | try w.writeAll("=== Rendered Source ===\n"); | ||
| 7582 | t.setColor(.reset) catch {}; | ||
| 7583 | |||
| 7584 | for (0.., source) |i, c| switch (c) { | ||
| 7585 | ' '...0x7e => try w.writeByte(c), | ||
| 7586 | '\n' => { | ||
| 7587 | if (i != 0 and source[i - 1] == ' ') { | ||
| 7588 | try w.writeAll("⏎"); | ||
| 7589 | } | ||
| 7590 | try w.writeByte('\n'); | ||
| 7591 | }, | ||
| 7592 | else => { | ||
| 7593 | t.setColor(.cyan) catch {}; | ||
| 7594 | try w.print("\\x{x:0>2}", .{c}); | ||
| 7595 | t.setColor(.reset) catch {}; | ||
| 7596 | }, | ||
| 7597 | }; | ||
| 7598 | try w.writeAll("␃\n"); | ||
| 7599 | } | 7337 | } |
lib/std/zig/perf_test.zig+1-1| ... | @@ -32,6 +32,6 @@ pub fn main() !void { | ... | @@ -32,6 +32,6 @@ pub fn main() !void { |
| 32 | fn testOnce() usize { | 32 | fn testOnce() usize { |
| 33 | var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(&fixed_buffer_mem); | 33 | var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(&fixed_buffer_mem); |
| 34 | const allocator = fixed_buf_alloc.allocator(); | 34 | const allocator = fixed_buf_alloc.allocator(); |
| 35 | _ = std.zig.Ast.parse(allocator, source, .zig) catch @panic("parse failure"); | 35 | _ = std.zig.Ast.parse(allocator, source, .zig, .{}) catch @panic("parse failure"); |
| 36 | return fixed_buf_alloc.end_index; | 36 | return fixed_buf_alloc.end_index; |
| 37 | } | 37 | } |
lib/std/zon/parse.zig+3-3| ... | @@ -294,7 +294,7 @@ pub fn fromSliceAlloc( | ... | @@ -294,7 +294,7 @@ pub fn fromSliceAlloc( |
| 294 | ) error{ OutOfMemory, ParseZon }!T { | 294 | ) error{ OutOfMemory, ParseZon }!T { |
| 295 | if (diag) |s| s.assertEmpty(); | 295 | if (diag) |s| s.assertEmpty(); |
| 296 | 296 | ||
| 297 | var ast = try std.zig.Ast.parse(gpa, source, .zon); | 297 | var ast = try std.zig.Ast.parse(gpa, source, .zon, .{}); |
| 298 | defer if (diag == null) ast.deinit(gpa); | 298 | defer if (diag == null) ast.deinit(gpa); |
| 299 | if (diag) |s| s.ast = ast; | 299 | if (diag) |s| s.ast = ast; |
| 300 | 300 | ||
| ... | @@ -2140,7 +2140,7 @@ test "std.zon string literal" { | ... | @@ -2140,7 +2140,7 @@ test "std.zon string literal" { |
| 2140 | // Passing string literal to a array | 2140 | // Passing string literal to a array |
| 2141 | { | 2141 | { |
| 2142 | { | 2142 | { |
| 2143 | var ast = try std.zig.Ast.parse(gpa, "\"abcd\"", .zon); | 2143 | var ast = try std.zig.Ast.parse(gpa, "\"abcd\"", .zon, .{}); |
| 2144 | defer ast.deinit(gpa); | 2144 | defer ast.deinit(gpa); |
| 2145 | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); | 2145 | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); |
| 2146 | defer zoir.deinit(gpa); | 2146 | defer zoir.deinit(gpa); |
| ... | @@ -3534,7 +3534,7 @@ test "std.zon no alloc" { | ... | @@ -3534,7 +3534,7 @@ test "std.zon no alloc" { |
| 3534 | 3534 | ||
| 3535 | const Nested = struct { u8, u8, struct { u8, u8 } }; | 3535 | const Nested = struct { u8, u8, struct { u8, u8 } }; |
| 3536 | 3536 | ||
| 3537 | var ast = try std.zig.Ast.parse(gpa, ".{ 1, 2, .{ 3, 4 } }", .zon); | 3537 | var ast = try std.zig.Ast.parse(gpa, ".{ 1, 2, .{ 3, 4 } }", .zon, .{}); |
| 3538 | defer ast.deinit(gpa); | 3538 | defer ast.deinit(gpa); |
| 3539 | 3539 | ||
| 3540 | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); | 3540 | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); |
src/Builtin.zig+1-1| ... | @@ -296,7 +296,7 @@ pub fn populateFile(opts: @This(), gpa: Allocator, file: *File) Allocator.Error! | ... | @@ -296,7 +296,7 @@ pub fn populateFile(opts: @This(), gpa: Allocator, file: *File) Allocator.Error! |
| 296 | 296 | ||
| 297 | log.debug("parsing and generating 'builtin.zig'", .{}); | 297 | log.debug("parsing and generating 'builtin.zig'", .{}); |
| 298 | 298 | ||
| 299 | file.tree = try std.zig.Ast.parse(gpa, file.source.?, .zig); | 299 | file.tree = try std.zig.Ast.parse(gpa, file.source.?, .zig, .{}); |
| 300 | assert(file.tree.?.errors.len == 0); // builtin.zig must parse | 300 | assert(file.tree.?.errors.len == 0); // builtin.zig must parse |
| 301 | 301 | ||
| 302 | file.zir = try AstGen.generate(gpa, file.tree.?); | 302 | file.zir = try AstGen.generate(gpa, file.tree.?); |
src/Zcu.zig+1-1| ... | @@ -1145,7 +1145,7 @@ pub const File = struct { | ... | @@ -1145,7 +1145,7 @@ pub const File = struct { |
| 1145 | if (file.tree) |*tree| return tree; | 1145 | if (file.tree) |*tree| return tree; |
| 1146 | 1146 | ||
| 1147 | const source = try file.getSource(zcu); | 1147 | const source = try file.getSource(zcu); |
| 1148 | file.tree = try .parse(zcu.gpa, source, file.getMode()); | 1148 | file.tree = try .parse(zcu.gpa, source, file.getMode(), .{}); |
| 1149 | return &file.tree.?; | 1149 | return &file.tree.?; |
| 1150 | } | 1150 | } |
| 1151 | 1151 |
src/Zcu/PerThread.zig+1-1| ... | @@ -642,7 +642,7 @@ pub fn updateFile( | ... | @@ -642,7 +642,7 @@ pub fn updateFile( |
| 642 | 642 | ||
| 643 | var timer = comp.startTimer(); | 643 | var timer = comp.startTimer(); |
| 644 | // Any potential AST errors are converted to ZIR errors when we run AstGen/ZonGen. | 644 | // Any potential AST errors are converted to ZIR errors when we run AstGen/ZonGen. |
| 645 | file.tree = try Ast.parse(gpa, source, file.getMode()); | 645 | file.tree = try Ast.parse(gpa, source, file.getMode(), .{}); |
| 646 | if (timer.finish(io)) |ns_parse| { | 646 | if (timer.finish(io)) |ns_parse| { |
| 647 | comp.mutex.lockUncancelable(io); | 647 | comp.mutex.lockUncancelable(io); |
| 648 | defer comp.mutex.unlock(io); | 648 | defer comp.mutex.unlock(io); |
src/fmt.zig+2-2| ... | @@ -117,7 +117,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! | ... | @@ -117,7 +117,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! |
| 117 | }; | 117 | }; |
| 118 | defer gpa.free(source_code); | 118 | defer gpa.free(source_code); |
| 119 | 119 | ||
| 120 | var tree = std.zig.Ast.parse(gpa, source_code, if (force_zon) .zon else .zig) catch |err| { | 120 | var tree = std.zig.Ast.parse(gpa, source_code, if (force_zon) .zon else .zig, .{}) catch |err| { |
| 121 | fatal("error parsing stdin: {}", .{err}); | 121 | fatal("error parsing stdin: {}", .{err}); |
| 122 | }; | 122 | }; |
| 123 | defer tree.deinit(gpa); | 123 | defer tree.deinit(gpa); |
| ... | @@ -312,7 +312,7 @@ fn fmtPathFile( | ... | @@ -312,7 +312,7 @@ fn fmtPathFile( |
| 312 | break :mode .zig; | 312 | break :mode .zig; |
| 313 | }; | 313 | }; |
| 314 | 314 | ||
| 315 | var tree = try std.zig.Ast.parse(gpa, source_code, mode); | 315 | var tree = try std.zig.Ast.parse(gpa, source_code, mode, .{}); |
| 316 | defer tree.deinit(gpa); | 316 | defer tree.deinit(gpa); |
| 317 | 317 | ||
| 318 | if (tree.errors.len != 0) { | 318 | if (tree.errors.len != 0) { |
src/main.zig+3-3| ... | @@ -5528,7 +5528,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: | ... | @@ -5528,7 +5528,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: |
| 5528 | break :mode .zig; | 5528 | break :mode .zig; |
| 5529 | }; | 5529 | }; |
| 5530 | 5530 | ||
| 5531 | const tree = try Ast.parse(arena, source, mode); | 5531 | const tree = try Ast.parse(arena, source, mode, .{}); |
| 5532 | 5532 | ||
| 5533 | var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); | 5533 | var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); |
| 5534 | const stdout_bw = &stdout_writer.interface; | 5534 | const stdout_bw = &stdout_writer.interface; |
| ... | @@ -5698,7 +5698,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map | ... | @@ -5698,7 +5698,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map |
| 5698 | fatal("unable to read new source file {q}: {t}", .{ new_source_path, err }); | 5698 | fatal("unable to read new source file {q}: {t}", .{ new_source_path, err }); |
| 5699 | }; | 5699 | }; |
| 5700 | 5700 | ||
| 5701 | const old_tree = try Ast.parse(arena, old_source, .zig); | 5701 | const old_tree = try Ast.parse(arena, old_source, .zig, .{}); |
| 5702 | const old_zir = try AstGen.generate(arena, old_tree); | 5702 | const old_zir = try AstGen.generate(arena, old_tree); |
| 5703 | 5703 | ||
| 5704 | if (old_zir.loweringFailed()) { | 5704 | if (old_zir.loweringFailed()) { |
| ... | @@ -5710,7 +5710,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map | ... | @@ -5710,7 +5710,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map |
| 5710 | process.exit(1); | 5710 | process.exit(1); |
| 5711 | } | 5711 | } |
| 5712 | 5712 | ||
| 5713 | const new_tree = try Ast.parse(arena, new_source, .zig); | 5713 | const new_tree = try Ast.parse(arena, new_source, .zig, .{}); |
| 5714 | const new_zir = try AstGen.generate(arena, new_tree); | 5714 | const new_zir = try AstGen.generate(arena, new_tree); |
| 5715 | 5715 | ||
| 5716 | if (new_zir.loweringFailed()) { | 5716 | if (new_zir.loweringFailed()) { |
test/standalone/build.zig+1| ... | @@ -36,6 +36,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -36,6 +36,7 @@ pub fn build(b: *std.Build) void { |
| 36 | "../../tools/fetch_them_macos_headers.zig", | 36 | "../../tools/fetch_them_macos_headers.zig", |
| 37 | "../../tools/gen_macos_headers_c.zig", | 37 | "../../tools/gen_macos_headers_c.zig", |
| 38 | "../../tools/gen_outline_atomics.zig", | 38 | "../../tools/gen_outline_atomics.zig", |
| 39 | "../../tools/gen_parser_oracle.zig", | ||
| 39 | "../../tools/gen_spirv_spec.zig", | 40 | "../../tools/gen_spirv_spec.zig", |
| 40 | "../../tools/gen_stubs.zig", | 41 | "../../tools/gen_stubs.zig", |
| 41 | "../../tools/generate_c_size_and_align_checks.zig", | 42 | "../../tools/generate_c_size_and_align_checks.zig", |
tools/docgen.zig+28-4| ... | @@ -25,6 +25,7 @@ const usage = | ... | @@ -25,6 +25,7 @@ const usage = |
| 25 | \\ | 25 | \\ |
| 26 | \\Options: | 26 | \\Options: |
| 27 | \\ --code-dir dir Path to directory containing code example outputs | 27 | \\ --code-dir dir Path to directory containing code example outputs |
| 28 | \\ --grammar file Path to the PEG grammar definition | ||
| 28 | \\ -h, --help Print this help and exit | 29 | \\ -h, --help Print this help and exit |
| 29 | \\ | 30 | \\ |
| 30 | ; | 31 | ; |
| ... | @@ -37,6 +38,7 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -37,6 +38,7 @@ pub fn main(init: std.process.Init) !void { |
| 37 | if (!args_it.skip()) @panic("expected self arg"); | 38 | if (!args_it.skip()) @panic("expected self arg"); |
| 38 | 39 | ||
| 39 | var opt_code_dir: ?[]const u8 = null; | 40 | var opt_code_dir: ?[]const u8 = null; |
| 41 | var opt_grammar: ?[]const u8 = null; | ||
| 40 | var opt_input: ?[]const u8 = null; | 42 | var opt_input: ?[]const u8 = null; |
| 41 | var opt_output: ?[]const u8 = null; | 43 | var opt_output: ?[]const u8 = null; |
| 42 | 44 | ||
| ... | @@ -51,6 +53,12 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -51,6 +53,12 @@ pub fn main(init: std.process.Init) !void { |
| 51 | } else { | 53 | } else { |
| 52 | fatal("expected parameter after --code-dir", .{}); | 54 | fatal("expected parameter after --code-dir", .{}); |
| 53 | } | 55 | } |
| 56 | } else if (mem.eql(u8, arg, "--grammar")) { | ||
| 57 | if (args_it.next()) |param| { | ||
| 58 | opt_grammar = param; | ||
| 59 | } else { | ||
| 60 | fatal("expected parameter after --grammar", .{}); | ||
| 61 | } | ||
| 54 | } else { | 62 | } else { |
| 55 | fatal("unrecognized option: '{s}'", .{arg}); | 63 | fatal("unrecognized option: '{s}'", .{arg}); |
| 56 | } | 64 | } |
| ... | @@ -65,6 +73,7 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -65,6 +73,7 @@ pub fn main(init: std.process.Init) !void { |
| 65 | const input_path = opt_input orelse fatal("missing input file", .{}); | 73 | const input_path = opt_input orelse fatal("missing input file", .{}); |
| 66 | const output_path = opt_output orelse fatal("missing output file", .{}); | 74 | const output_path = opt_output orelse fatal("missing output file", .{}); |
| 67 | const code_dir_path = opt_code_dir orelse fatal("missing --code-dir argument", .{}); | 75 | const code_dir_path = opt_code_dir orelse fatal("missing --code-dir argument", .{}); |
| 76 | const grammar_path = opt_grammar orelse fatal("missing --grammar argument", .{}); | ||
| 68 | 77 | ||
| 69 | var in_file = try Dir.cwd().openFile(io, input_path, .{}); | 78 | var in_file = try Dir.cwd().openFile(io, input_path, .{}); |
| 70 | defer in_file.close(io); | 79 | defer in_file.close(io); |
| ... | @@ -82,13 +91,16 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -82,13 +91,16 @@ pub fn main(init: std.process.Init) !void { |
| 82 | }; | 91 | }; |
| 83 | defer code_dir.root_dir.handle.close(io); | 92 | defer code_dir.root_dir.handle.close(io); |
| 84 | 93 | ||
| 94 | const grammar = try Dir.cwd().readFileAlloc(io, grammar_path, init.gpa, .limited(max_doc_file_size)); | ||
| 95 | defer init.gpa.free(grammar); | ||
| 96 | |||
| 85 | var in_file_reader = in_file.reader(io, &.{}); | 97 | var in_file_reader = in_file.reader(io, &.{}); |
| 86 | const input_file_bytes = try in_file_reader.interface.allocRemaining(arena, .limited(max_doc_file_size)); | 98 | const input_file_bytes = try in_file_reader.interface.allocRemaining(arena, .limited(max_doc_file_size)); |
| 87 | 99 | ||
| 88 | var tokenizer = Tokenizer.init(input_path, input_file_bytes); | 100 | var tokenizer = Tokenizer.init(input_path, input_file_bytes); |
| 89 | var toc = try genToc(arena, &tokenizer); | 101 | var toc = try genToc(arena, &tokenizer); |
| 90 | 102 | ||
| 91 | try genHtml(arena, io, &tokenizer, &toc, code_dir, &out_file_writer.interface); | 103 | try genHtml(arena, io, &tokenizer, &toc, code_dir, grammar, &out_file_writer.interface); |
| 92 | try out_file_writer.end(); | 104 | try out_file_writer.end(); |
| 93 | } | 105 | } |
| 94 | 106 | ||
| ... | @@ -326,6 +338,7 @@ const Node = union(enum) { | ... | @@ -326,6 +338,7 @@ const Node = union(enum) { |
| 326 | HeaderOpen: HeaderOpen, | 338 | HeaderOpen: HeaderOpen, |
| 327 | SeeAlso: []const SeeAlsoItem, | 339 | SeeAlso: []const SeeAlsoItem, |
| 328 | Code: Code, | 340 | Code: Code, |
| 341 | Grammar, | ||
| 329 | Link: Link, | 342 | Link: Link, |
| 330 | InlineSyntax: Token, | 343 | InlineSyntax: Token, |
| 331 | Shell: Token, | 344 | Shell: Token, |
| ... | @@ -513,6 +526,9 @@ fn genToc(gpa: Allocator, tokenizer: *Tokenizer) !Toc { | ... | @@ -513,6 +526,9 @@ fn genToc(gpa: Allocator, tokenizer: *Tokenizer) !Toc { |
| 513 | .token = name_tok, | 526 | .token = name_tok, |
| 514 | }, | 527 | }, |
| 515 | }); | 528 | }); |
| 529 | } else if (mem.eql(u8, tag_name, "grammar")) { | ||
| 530 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 531 | try nodes.append(.Grammar); | ||
| 516 | } else if (mem.eql(u8, tag_name, "syntax")) { | 532 | } else if (mem.eql(u8, tag_name, "syntax")) { |
| 517 | _ = try eatToken(tokenizer, .bracket_close); | 533 | _ = try eatToken(tokenizer, .bracket_close); |
| 518 | const content_tok = try eatToken(tokenizer, .content); | 534 | const content_tok = try eatToken(tokenizer, .content); |
| ... | @@ -924,14 +940,14 @@ fn tokenizeAndPrint( | ... | @@ -924,14 +940,14 @@ fn tokenizeAndPrint( |
| 924 | return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src); | 940 | return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src); |
| 925 | } | 941 | } |
| 926 | 942 | ||
| 927 | fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: *Writer, syntax_block: SyntaxBlock) !void { | 943 | fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: *Writer, syntax_block: SyntaxBlock, content: ?[]const u8) !void { |
| 928 | const source_type = @tagName(syntax_block.source_type); | 944 | const source_type = @tagName(syntax_block.source_type); |
| 929 | 945 | ||
| 930 | try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name }); | 946 | try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name }); |
| 931 | switch (syntax_block.source_type) { | 947 | switch (syntax_block.source_type) { |
| 932 | .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token), | 948 | .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token), |
| 933 | else => { | 949 | else => { |
| 934 | const raw_source = docgen_tokenizer.buffer[syntax_block.source_token.start..syntax_block.source_token.end]; | 950 | const raw_source = content orelse docgen_tokenizer.buffer[syntax_block.source_token.start..syntax_block.source_token.end]; |
| 935 | const trimmed_raw_source = mem.trim(u8, raw_source, " \r\n"); | 951 | const trimmed_raw_source = mem.trim(u8, raw_source, " \r\n"); |
| 936 | 952 | ||
| 937 | try out.writeAll("<code>"); | 953 | try out.writeAll("<code>"); |
| ... | @@ -995,6 +1011,7 @@ fn genHtml( | ... | @@ -995,6 +1011,7 @@ fn genHtml( |
| 995 | tokenizer: *Tokenizer, | 1011 | tokenizer: *Tokenizer, |
| 996 | toc: *Toc, | 1012 | toc: *Toc, |
| 997 | code_dir: Path, | 1013 | code_dir: Path, |
| 1014 | grammar: []const u8, | ||
| 998 | out: *Writer, | 1015 | out: *Writer, |
| 999 | ) !void { | 1016 | ) !void { |
| 1000 | for (toc.nodes) |node| { | 1017 | for (toc.nodes) |node| { |
| ... | @@ -1042,7 +1059,7 @@ fn genHtml( | ... | @@ -1042,7 +1059,7 @@ fn genHtml( |
| 1042 | try printShell(out, raw_shell_content, true); | 1059 | try printShell(out, raw_shell_content, true); |
| 1043 | }, | 1060 | }, |
| 1044 | .SyntaxBlock => |syntax_block| { | 1061 | .SyntaxBlock => |syntax_block| { |
| 1045 | try printSourceBlock(allocator, tokenizer, out, syntax_block); | 1062 | try printSourceBlock(allocator, tokenizer, out, syntax_block, null); |
| 1046 | }, | 1063 | }, |
| 1047 | .Code => |code| { | 1064 | .Code => |code| { |
| 1048 | const out_basename = try std.fmt.allocPrint(allocator, "{s}.out", .{ | 1065 | const out_basename = try std.fmt.allocPrint(allocator, "{s}.out", .{ |
| ... | @@ -1062,6 +1079,13 @@ fn genHtml( | ... | @@ -1062,6 +1079,13 @@ fn genHtml( |
| 1062 | 1079 | ||
| 1063 | try out.writeAll(contents); | 1080 | try out.writeAll(contents); |
| 1064 | }, | 1081 | }, |
| 1082 | .Grammar => { | ||
| 1083 | try printSourceBlock(allocator, tokenizer, out, .{ | ||
| 1084 | .source_type = .peg, | ||
| 1085 | .name = "grammar.peg", | ||
| 1086 | .source_token = undefined, | ||
| 1087 | }, grammar); | ||
| 1088 | }, | ||
| 1065 | } | 1089 | } |
| 1066 | } | 1090 | } |
| 1067 | } | 1091 | } |
tools/gen_parser_oracle.zig created+789| ... | @@ -0,0 +1,789 @@ | ||
| 1 | //! Example usage: | ||
| 2 | //! zig build gen-parser-oracle | ||
| 3 | //! zig build check-parser-oracle | ||
| 4 | |||
| 5 | // This program implements a subset of the PEG grammar definition | ||
| 6 | // in the peg(1) man page. | ||
| 7 | // | ||
| 8 | // It generates a recursive descent parser that returns true if a given input is | ||
| 9 | // matched by the grammar. This generated parser is used as an oracle for fuzz testing. | ||
| 10 | |||
| 11 | const std = @import("std"); | ||
| 12 | const assert = std.debug.assert; | ||
| 13 | const Io = std.Io; | ||
| 14 | const mem = std.mem; | ||
| 15 | const Allocator = mem.Allocator; | ||
| 16 | const log = std.log; | ||
| 17 | |||
| 18 | pub fn main(init: std.process.Init) !void { | ||
| 19 | const gpa = init.gpa; | ||
| 20 | const arena = init.arena.allocator(); | ||
| 21 | const io = init.io; | ||
| 22 | const args = try init.minimal.args.toSlice(arena); | ||
| 23 | |||
| 24 | const grammar_path = args[1]; | ||
| 25 | const out_path = args[2]; | ||
| 26 | const check = args.len > 3 and mem.eql(u8, args[3], "--check"); | ||
| 27 | |||
| 28 | const grammar = try Io.Dir.cwd().readFileAlloc(io, grammar_path, gpa, .unlimited); | ||
| 29 | defer gpa.free(grammar); | ||
| 30 | |||
| 31 | var parser: Parser = .init(gpa, grammar); | ||
| 32 | defer parser.deinit(); | ||
| 33 | |||
| 34 | const root = try parser.parseGrammar() orelse { | ||
| 35 | log.err("Invalid grammar", .{}); | ||
| 36 | return; | ||
| 37 | }; | ||
| 38 | |||
| 39 | var buffer: Io.Writer.Allocating = .init(gpa); | ||
| 40 | defer buffer.deinit(); | ||
| 41 | |||
| 42 | var g: Generator = .init(&buffer.writer, &parser); | ||
| 43 | try g.genRoot(root); | ||
| 44 | |||
| 45 | const generated = try buffer.toOwnedSliceSentinel(0); | ||
| 46 | defer gpa.free(generated); | ||
| 47 | |||
| 48 | // Parse the generated Zig code and render it in the canonical format | ||
| 49 | var tree = try std.zig.Ast.parse(gpa, generated, .zig, .{}); | ||
| 50 | defer tree.deinit(gpa); | ||
| 51 | |||
| 52 | if (tree.errors.len != 0) { | ||
| 53 | // This should never be reached, but helps a lot when debugging this script. | ||
| 54 | try std.zig.printAstErrorsToStderr(gpa, io, tree, "generated", .auto); | ||
| 55 | return error.ParseError; | ||
| 56 | } | ||
| 57 | |||
| 58 | if (check) { | ||
| 59 | const current = try Io.Dir.cwd().readFileAlloc(io, out_path, gpa, .unlimited); | ||
| 60 | defer gpa.free(current); | ||
| 61 | var aw: Io.Writer.Allocating = .init(gpa); | ||
| 62 | defer aw.deinit(); | ||
| 63 | try tree.render(gpa, &aw.writer, .{}); | ||
| 64 | if (!mem.eql(u8, current, aw.written())) { | ||
| 65 | std.log.err("grammar.peg modified without regenerating oracle", .{}); | ||
| 66 | std.log.info("Run zig build gen-parser-oracle to regenerate", .{}); | ||
| 67 | std.process.exit(1); | ||
| 68 | } | ||
| 69 | } else { | ||
| 70 | var out_file = try Io.Dir.cwd().createFile(io, out_path, .{}); | ||
| 71 | defer out_file.close(io); | ||
| 72 | var out_buffer: [4096]u8 = undefined; | ||
| 73 | var out_writer = out_file.writer(io, &out_buffer); | ||
| 74 | const out = &out_writer.interface; | ||
| 75 | |||
| 76 | try tree.render(gpa, out, .{}); | ||
| 77 | try out.flush(); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | const Generator = struct { | ||
| 82 | w: *Io.Writer, | ||
| 83 | p: *const Parser, | ||
| 84 | /// Suffix for generated identifiers, incremented for each nested scope to avoid shadowing, | ||
| 85 | /// Decremented at end of each generated scope to give smaller git diffs when regenerating | ||
| 86 | /// lib/std/zig/parser_generated_oracle.zig. | ||
| 87 | suffix: usize, | ||
| 88 | |||
| 89 | fn init(w: *Io.Writer, p: *const Parser) Generator { | ||
| 90 | return .{ .w = w, .p = p, .suffix = 0 }; | ||
| 91 | } | ||
| 92 | |||
| 93 | const Error = Io.Writer.Error; | ||
| 94 | const Node = Parser.Node; | ||
| 95 | |||
| 96 | fn genRoot(g: *Generator, node: Node.Index) Error!void { | ||
| 97 | try g.w.writeAll( | ||
| 98 | \\//! This file is generated, do not edit manually! To generate, run: | ||
| 99 | \\//! zig build gen-parser-oracle | ||
| 100 | \\ | ||
| 101 | \\const std = @import("std"); | ||
| 102 | \\ | ||
| 103 | \\const Error = error{MaxDepth}; | ||
| 104 | \\const max_depth = 5; | ||
| 105 | \\ | ||
| 106 | \\/// Returns true if the input source is in the language defined by | ||
| 107 | \\/// the grammar. | ||
| 108 | \\/// Returns error.MaxDepth if more than `max_depth` levels of recursion/iteration are reached. | ||
| 109 | \\pub fn parse(source: []const u8) Error!bool { | ||
| 110 | \\ var p: Parser = .{ .source = source, .i = 0, .depths = @splat(1) }; | ||
| 111 | \\ return p.parseRoot(); | ||
| 112 | \\} | ||
| 113 | ); | ||
| 114 | |||
| 115 | const defs = g.p.getExtra(node.get(g.p).root); | ||
| 116 | |||
| 117 | // This enum exists to minimize git diffs in the generated oracle when | ||
| 118 | // the grammar is modified. It allows mapping from def name (stable) to | ||
| 119 | // def index (unstable). | ||
| 120 | try g.w.writeAll("const Def = enum {"); | ||
| 121 | for (defs) |n| { | ||
| 122 | const def = n.get(g.p).def; | ||
| 123 | const id = def.id.get(g.p).id; | ||
| 124 | try g.w.print("def{s},", .{id}); | ||
| 125 | } | ||
| 126 | try g.w.writeAll("};"); | ||
| 127 | |||
| 128 | try g.w.print( | ||
| 129 | \\const Parser = struct {{ | ||
| 130 | \\ source: []const u8, | ||
| 131 | \\ i: usize, | ||
| 132 | \\ depths: [{d}]u8, | ||
| 133 | , .{defs.len}); | ||
| 134 | for (defs) |def| { | ||
| 135 | try g.genDef(def); | ||
| 136 | } | ||
| 137 | try g.w.writeAll("};"); | ||
| 138 | } | ||
| 139 | |||
| 140 | fn genDef(g: *Generator, node: Node.Index) Error!void { | ||
| 141 | const def = node.get(g.p).def; | ||
| 142 | const id = def.id.get(g.p).id; | ||
| 143 | assert(g.suffix == 0); | ||
| 144 | try g.w.print("pub fn parse{s}(p: *Parser) Error!bool {{", .{id}); | ||
| 145 | try g.w.print( | ||
| 146 | \\const def_index = @intFromEnum(Def.def{s}); | ||
| 147 | \\if (p.depths[def_index] > max_depth) return error.MaxDepth; | ||
| 148 | \\p.depths[def_index] += 1; | ||
| 149 | \\defer p.depths[def_index] -= 1; | ||
| 150 | , .{id}); | ||
| 151 | try g.w.writeAll("return "); | ||
| 152 | try g.genExpr(def.expr); | ||
| 153 | try g.w.writeAll(";}"); | ||
| 154 | } | ||
| 155 | |||
| 156 | fn genExpr(g: *Generator, node: Node.Index) Error!void { | ||
| 157 | const suffix = g.suffix; | ||
| 158 | g.suffix += 1; | ||
| 159 | defer g.suffix -= 1; | ||
| 160 | try g.w.print( | ||
| 161 | \\blk_{d}: {{ | ||
| 162 | \\const pos_{d} = p.i; | ||
| 163 | , .{ suffix, suffix }); | ||
| 164 | for (g.p.getExtra(node.get(g.p).expr)) |seq| { | ||
| 165 | try g.w.writeAll("if ("); | ||
| 166 | try g.genSeq(seq); | ||
| 167 | try g.w.print(") break :blk_{d} true;", .{suffix}); | ||
| 168 | try g.w.print("p.i = pos_{d};", .{suffix}); | ||
| 169 | } | ||
| 170 | try g.w.print("break :blk_{d} false; }}", .{suffix}); | ||
| 171 | } | ||
| 172 | |||
| 173 | fn genSeq(g: *Generator, node: Node.Index) Error!void { | ||
| 174 | const items = g.p.getExtra(node.get(g.p).seq); | ||
| 175 | for (items, 0..) |item, i| { | ||
| 176 | if (i > 0) try g.w.writeAll(" and "); | ||
| 177 | try g.genNode(item); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | fn genNode(g: *Generator, node: Node.Index) Error!void { | ||
| 182 | const suffix = g.suffix; | ||
| 183 | g.suffix += 1; | ||
| 184 | defer g.suffix -= 1; | ||
| 185 | switch (node.get(g.p)) { | ||
| 186 | .id => |id| try g.w.print("try p.parse{s}()", .{id}), | ||
| 187 | .expr => try g.genExpr(node), | ||
| 188 | .@"&" => |child| { | ||
| 189 | // XXX forbid unbounded lookahead | ||
| 190 | try g.w.print( | ||
| 191 | \\blk_{d}: {{ | ||
| 192 | \\const pos_{d} = p.i; | ||
| 193 | \\const match_{d} = | ||
| 194 | , .{ suffix, suffix, suffix }); | ||
| 195 | try g.genNode(child); | ||
| 196 | try g.w.print( | ||
| 197 | \\; | ||
| 198 | \\p.i = pos_{d}; | ||
| 199 | \\ break :blk_{d} match_{d}; | ||
| 200 | \\}} | ||
| 201 | , .{ suffix, suffix, suffix }); | ||
| 202 | }, | ||
| 203 | .@"!" => |child| { | ||
| 204 | // XXX forbid unbounded lookahead | ||
| 205 | try g.w.print( | ||
| 206 | \\blk_{d}: {{ | ||
| 207 | \\const pos_{d} = p.i; | ||
| 208 | \\const match_{d} = | ||
| 209 | , .{ suffix, suffix, suffix }); | ||
| 210 | try g.genNode(child); | ||
| 211 | try g.w.print( | ||
| 212 | \\; | ||
| 213 | \\p.i = pos_{d}; | ||
| 214 | \\ break :blk_{d} !match_{d}; | ||
| 215 | \\}} | ||
| 216 | , .{ suffix, suffix, suffix }); | ||
| 217 | }, | ||
| 218 | .@"?" => |child| { | ||
| 219 | try g.w.writeAll("("); | ||
| 220 | try g.genNode(child); | ||
| 221 | try g.w.writeAll(" or true )"); | ||
| 222 | }, | ||
| 223 | .@"*" => |child| { | ||
| 224 | try g.w.print( | ||
| 225 | \\blk_{d}: {{ | ||
| 226 | \\var i_{d}: usize = 0; | ||
| 227 | \\while ( | ||
| 228 | , .{ suffix, suffix }); | ||
| 229 | try g.genNode(child); | ||
| 230 | try g.w.print( | ||
| 231 | \\) {{ | ||
| 232 | \\ if (i_{d} > max_depth) return error.MaxDepth; | ||
| 233 | \\ i_{d} += 1; | ||
| 234 | \\}} | ||
| 235 | \\break :blk_{d} true; }} | ||
| 236 | , .{ suffix, suffix, suffix }); | ||
| 237 | }, | ||
| 238 | .@"+" => |child| { | ||
| 239 | try g.w.print( | ||
| 240 | \\blk_{d}: {{ | ||
| 241 | \\var match_{d} = false; | ||
| 242 | \\var i_{d}: usize = 0; | ||
| 243 | \\while ( | ||
| 244 | , .{ suffix, suffix, suffix }); | ||
| 245 | try g.genNode(child); | ||
| 246 | try g.w.print( | ||
| 247 | \\) {{ | ||
| 248 | \\ match_{d} = true; | ||
| 249 | \\ if (i_{d} > max_depth) return error.MaxDepth; | ||
| 250 | \\ i_{d} += 1; | ||
| 251 | \\}} | ||
| 252 | \\break :blk_{d} match_{d}; }} | ||
| 253 | , .{ suffix, suffix, suffix, suffix, suffix }); | ||
| 254 | }, | ||
| 255 | .@"." => { | ||
| 256 | try g.w.print( | ||
| 257 | \\blk_{d}: {{ | ||
| 258 | \\ if (p.i < p.source.len) {{ | ||
| 259 | \\ p.i += 1; | ||
| 260 | \\ break :blk_{d} true; | ||
| 261 | \\ }} | ||
| 262 | \\ break :blk_{d} false; | ||
| 263 | \\}} | ||
| 264 | , .{ suffix, suffix, suffix }); | ||
| 265 | }, | ||
| 266 | .literal => |literal| { | ||
| 267 | const bytes = g.p.strings.items[literal.off..][0..literal.len]; | ||
| 268 | try g.w.print( | ||
| 269 | \\blk_{d}: {{ | ||
| 270 | \\if (std.mem.startsWith(u8, p.source[p.i..], " | ||
| 271 | , .{suffix}); | ||
| 272 | try std.zig.stringEscape(bytes, g.w); | ||
| 273 | try g.w.print( | ||
| 274 | \\")) {{ | ||
| 275 | \\p.i += {d}; | ||
| 276 | \\ break :blk_{d} true; | ||
| 277 | \\}} | ||
| 278 | \\break :blk_{d} false; | ||
| 279 | \\}} | ||
| 280 | , .{ bytes.len, suffix, suffix }); | ||
| 281 | }, | ||
| 282 | .class => |ranges| { | ||
| 283 | try g.w.writeAll("(p.i < p.source.len and switch (p.source[p.i]) {"); | ||
| 284 | for (g.p.getExtra(ranges)) |n| { | ||
| 285 | const range = n.get(g.p).range; | ||
| 286 | try g.w.writeAll("'"); | ||
| 287 | try std.zig.charEscape(range.start, g.w); | ||
| 288 | try g.w.writeAll("'...'"); | ||
| 289 | try std.zig.charEscape(range.end, g.w); | ||
| 290 | try g.w.writeAll("',"); | ||
| 291 | } | ||
| 292 | try g.w.print( | ||
| 293 | \\=> blk_{d}: {{ p.i += 1; break :blk_{d} true; }}, | ||
| 294 | \\else => false, | ||
| 295 | \\}}) | ||
| 296 | , .{ suffix, suffix }); | ||
| 297 | }, | ||
| 298 | .sof => try g.w.writeAll("(p.i == 0)"), | ||
| 299 | else => unreachable, | ||
| 300 | } | ||
| 301 | } | ||
| 302 | }; | ||
| 303 | |||
| 304 | /// Parser implements a subset of the PEG grammar definition. | ||
| 305 | /// We don't bother implementing the Action, BEGIN, and END rules | ||
| 306 | /// and also omit unneeded character escape sequences. | ||
| 307 | /// | ||
| 308 | /// The full PEG grammar found in the peg(1) man page: | ||
| 309 | /// | ||
| 310 | /// Grammar <- Spacing Definition+ EndOfFile | ||
| 311 | /// | ||
| 312 | /// Definition <- Identifier LEFTARROW Expression | ||
| 313 | /// Expression <- Sequence ( SLASH Sequence )* | ||
| 314 | /// Sequence <- Prefix* | ||
| 315 | /// Prefix <- AND Action | ||
| 316 | /// / ( AND / NOT )? Suffix | ||
| 317 | /// Suffix <- Primary ( QUERY / STAR / PLUS )? | ||
| 318 | /// Primary <- Identifier !LEFTARROW | ||
| 319 | /// / OPEN Expression CLOSE | ||
| 320 | /// / Literal | ||
| 321 | /// / Class | ||
| 322 | /// / DOT | ||
| 323 | /// / Action | ||
| 324 | /// / BEGIN | ||
| 325 | /// / END | ||
| 326 | /// | ||
| 327 | /// Identifier <- < IdentStart IdentCont* > Spacing | ||
| 328 | /// IdentStart <- [a-zA-Z_] | ||
| 329 | /// IdentCont <- IdentStart / [0-9] | ||
| 330 | /// Literal <- ['] < ( !['] Char )* > ['] Spacing | ||
| 331 | /// / ["] < ( !["] Char )* > ["] Spacing | ||
| 332 | /// Class <- '[' < ( !']' Range )* > ']' Spacing | ||
| 333 | /// Range <- Char '-' Char / Char | ||
| 334 | /// Char <- '\\' [abefnrtv'"\[\]\\] | ||
| 335 | /// / '\\' [0-3][0-7][0-7] | ||
| 336 | /// / '\\' [0-7][0-7]? | ||
| 337 | /// / '\\' '-' | ||
| 338 | /// / !'\\' . | ||
| 339 | /// LEFTARROW <- '<-' Spacing | ||
| 340 | /// SLASH <- '/' Spacing | ||
| 341 | /// AND <- '&' Spacing | ||
| 342 | /// NOT <- '!' Spacing | ||
| 343 | /// QUERY <- '?' Spacing | ||
| 344 | /// STAR <- '*' Spacing | ||
| 345 | /// PLUS <- '+' Spacing | ||
| 346 | /// OPEN <- '(' Spacing | ||
| 347 | /// CLOSE <- ')' Spacing | ||
| 348 | /// DOT <- '.' Spacing | ||
| 349 | /// Spacing <- ( Space / Comment )* | ||
| 350 | /// Comment <- '#' ( !EndOfLine . )* EndOfLine | ||
| 351 | /// Space <- ' ' / '\t' / EndOfLine | ||
| 352 | /// EndOfLine <- '\r\n' / '\n' / '\r' | ||
| 353 | /// EndOfFile <- !. | ||
| 354 | /// Action <- '{' < [^}]* > '}' Spacing | ||
| 355 | /// BEGIN <- '<' Spacing | ||
| 356 | /// END <- '>' Spacing | ||
| 357 | const Parser = struct { | ||
| 358 | gpa: Allocator, | ||
| 359 | /// PEG grammar source | ||
| 360 | source: []const u8, | ||
| 361 | /// Current index into source | ||
| 362 | i: u32, | ||
| 363 | nodes: std.ArrayList(Node), | ||
| 364 | extra: std.ArrayList(Node.Index), | ||
| 365 | strings: std.ArrayList(u8), | ||
| 366 | |||
| 367 | const Node = union(enum) { | ||
| 368 | /// Slice into extra | ||
| 369 | root: Slice, | ||
| 370 | def: struct { | ||
| 371 | id: Index, | ||
| 372 | expr: Index, | ||
| 373 | }, | ||
| 374 | /// Slice into Parser.source | ||
| 375 | id: []const u8, | ||
| 376 | /// Slice into extra | ||
| 377 | expr: Slice, | ||
| 378 | /// Slice into extra | ||
| 379 | seq: Slice, | ||
| 380 | @"&": Index, | ||
| 381 | @"!": Index, | ||
| 382 | @"?": Index, | ||
| 383 | @"*": Index, | ||
| 384 | @"+": Index, | ||
| 385 | @".", | ||
| 386 | /// Slice into strings | ||
| 387 | literal: Slice, | ||
| 388 | /// Slice into extra | ||
| 389 | class: Slice, | ||
| 390 | range: struct { | ||
| 391 | start: u8, | ||
| 392 | end: u8, | ||
| 393 | }, | ||
| 394 | /// Start of file | ||
| 395 | sof, | ||
| 396 | |||
| 397 | const Index = enum(u32) { | ||
| 398 | _, | ||
| 399 | |||
| 400 | fn get(index: Index, p: *const Parser) Node { | ||
| 401 | return p.nodes.items[@intFromEnum(index)]; | ||
| 402 | } | ||
| 403 | }; | ||
| 404 | |||
| 405 | const Slice = struct { | ||
| 406 | off: u32, | ||
| 407 | len: u32, | ||
| 408 | }; | ||
| 409 | }; | ||
| 410 | |||
| 411 | fn init(gpa: Allocator, source: []const u8) Parser { | ||
| 412 | return .{ | ||
| 413 | .gpa = gpa, | ||
| 414 | .source = source, | ||
| 415 | .i = 0, | ||
| 416 | .nodes = .empty, | ||
| 417 | .extra = .empty, | ||
| 418 | .strings = .empty, | ||
| 419 | }; | ||
| 420 | } | ||
| 421 | |||
| 422 | fn deinit(p: *Parser) void { | ||
| 423 | p.nodes.deinit(p.gpa); | ||
| 424 | p.extra.deinit(p.gpa); | ||
| 425 | p.strings.deinit(p.gpa); | ||
| 426 | } | ||
| 427 | |||
| 428 | // Grammar <- Spacing Definition+ EndOfFile | ||
| 429 | // EndOfFile <- !. | ||
| 430 | fn parseGrammar(p: *Parser) !?Node.Index { | ||
| 431 | var scratch: std.ArrayList(Node.Index) = .empty; | ||
| 432 | defer scratch.deinit(p.gpa); | ||
| 433 | _ = p.eatSpacing(); | ||
| 434 | while (try p.parseDefinition()) |def| { | ||
| 435 | try scratch.append(p.gpa, def); | ||
| 436 | } | ||
| 437 | if (scratch.items.len == 0) return null; | ||
| 438 | if (p.peek() != null) return null; | ||
| 439 | const defs = try p.addExtra(scratch.items); | ||
| 440 | return try p.addNode(.{ .root = defs }); | ||
| 441 | } | ||
| 442 | |||
| 443 | // Definition <- Identifier LEFTARROW Expression | ||
| 444 | fn parseDefinition(p: *Parser) !?Node.Index { | ||
| 445 | const id = try p.parseIdentifier() orelse return null; | ||
| 446 | if (!p.eatLeftArrow()) return null; | ||
| 447 | const expr = try p.parseExpression() orelse return null; | ||
| 448 | return try p.addNode(.{ .def = .{ | ||
| 449 | .id = id, | ||
| 450 | .expr = expr, | ||
| 451 | } }); | ||
| 452 | } | ||
| 453 | |||
| 454 | // Expression <- Sequence ( SLASH Sequence )* | ||
| 455 | fn parseExpression(p: *Parser) error{OutOfMemory}!?Node.Index { | ||
| 456 | var scratch: std.ArrayList(Node.Index) = .empty; | ||
| 457 | defer scratch.deinit(p.gpa); | ||
| 458 | while (try p.parseSequence()) |seq| { | ||
| 459 | try scratch.append(p.gpa, seq); | ||
| 460 | if (!p.eatSlash()) break; | ||
| 461 | } | ||
| 462 | if (scratch.items.len == 0) return null; | ||
| 463 | const seqs = try p.addExtra(scratch.items); | ||
| 464 | return try p.addNode(.{ .expr = seqs }); | ||
| 465 | } | ||
| 466 | |||
| 467 | // Sequence <- Prefix* | ||
| 468 | fn parseSequence(p: *Parser) !?Node.Index { | ||
| 469 | var scratch: std.ArrayList(Node.Index) = .empty; | ||
| 470 | defer scratch.deinit(p.gpa); | ||
| 471 | while (try p.parsePrefix()) |primary| { | ||
| 472 | try scratch.append(p.gpa, primary); | ||
| 473 | } | ||
| 474 | const primaries = try p.addExtra(scratch.items); | ||
| 475 | return try p.addNode(.{ .seq = primaries }); | ||
| 476 | } | ||
| 477 | |||
| 478 | // Prefix <- AND Action | ||
| 479 | // / ( AND / NOT )? Suffix | ||
| 480 | fn parsePrefix(p: *Parser) !?Node.Index { | ||
| 481 | if (p.eatAnd()) { | ||
| 482 | // We only support a single hardcoded "start of file" Action | ||
| 483 | if (p.eat('{')) { | ||
| 484 | // Action <- '{' < [^}]* > '}' Spacing | ||
| 485 | if (std.mem.startsWith(u8, p.source[p.i..], " (yy->__pos == 0) }")) { | ||
| 486 | while (!p.eat('}')) p.i += 1; | ||
| 487 | _ = p.eatSpacing(); | ||
| 488 | return try p.addNode(.sof); | ||
| 489 | } | ||
| 490 | return null; | ||
| 491 | } | ||
| 492 | const suffix = try p.parseSuffix() orelse return null; | ||
| 493 | return try p.addNode(.{ .@"&" = suffix }); | ||
| 494 | } | ||
| 495 | if (p.eatNot()) { | ||
| 496 | const suffix = try p.parseSuffix() orelse return null; | ||
| 497 | return try p.addNode(.{ .@"!" = suffix }); | ||
| 498 | } | ||
| 499 | return try p.parseSuffix(); | ||
| 500 | } | ||
| 501 | |||
| 502 | // Suffix <- Primary ( QUERY / STAR / PLUS )? | ||
| 503 | fn parseSuffix(p: *Parser) !?Node.Index { | ||
| 504 | const primary = try p.parsePrimary() orelse return null; | ||
| 505 | if (p.eatQuery()) { | ||
| 506 | return try p.addNode(.{ .@"?" = primary }); | ||
| 507 | } | ||
| 508 | if (p.eatStar()) { | ||
| 509 | return try p.addNode(.{ .@"*" = primary }); | ||
| 510 | } | ||
| 511 | if (p.eatPlus()) { | ||
| 512 | return try p.addNode(.{ .@"+" = primary }); | ||
| 513 | } | ||
| 514 | return primary; | ||
| 515 | } | ||
| 516 | |||
| 517 | // Primary <- Identifier !LEFTARROW | ||
| 518 | // / OPEN Expression CLOSE | ||
| 519 | // / Literal | ||
| 520 | // / Class | ||
| 521 | // / DOT | ||
| 522 | // / Action | ||
| 523 | // / BEGIN | ||
| 524 | // / END | ||
| 525 | fn parsePrimary(p: *Parser) !?Node.Index { | ||
| 526 | const init_pos = p.savePos(); | ||
| 527 | if (try p.parseIdentifier()) |id| { | ||
| 528 | const pos = p.savePos(); | ||
| 529 | if (!p.eatLeftArrow()) { | ||
| 530 | p.restorePos(pos); | ||
| 531 | return id; | ||
| 532 | } | ||
| 533 | } | ||
| 534 | p.restorePos(init_pos); | ||
| 535 | if (p.eatOpen()) if (try p.parseExpression()) |expr| if (p.eatClose()) return expr; | ||
| 536 | p.restorePos(init_pos); | ||
| 537 | if (try p.parseLiteral()) |literal| return literal; | ||
| 538 | p.restorePos(init_pos); | ||
| 539 | if (try p.parseClass()) |class| return class; | ||
| 540 | p.restorePos(init_pos); | ||
| 541 | if (p.eatDot()) return try p.addNode(.@"."); | ||
| 542 | // We don't implement Action, BEGIN, and END. | ||
| 543 | return null; | ||
| 544 | } | ||
| 545 | |||
| 546 | // Identifier <- < IdentStart IdentCont* > Spacing | ||
| 547 | // IdentStart <- [a-zA-Z_] | ||
| 548 | // IdentCont <- IdentStart / [0-9] | ||
| 549 | fn parseIdentifier(p: *Parser) !?Node.Index { | ||
| 550 | const start = p.i; | ||
| 551 | switch (p.next() orelse return null) { | ||
| 552 | 'a'...'z', 'A'...'Z', '_' => {}, | ||
| 553 | else => return null, | ||
| 554 | } | ||
| 555 | while (p.peek()) |cont| { | ||
| 556 | switch (cont) { | ||
| 557 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => p.i += 1, | ||
| 558 | else => break, | ||
| 559 | } | ||
| 560 | } | ||
| 561 | const id = p.source[start..p.i]; | ||
| 562 | _ = p.eatSpacing(); | ||
| 563 | return try p.addNode(.{ .id = id }); | ||
| 564 | } | ||
| 565 | |||
| 566 | // Literal <- ['] < ( !['] Char )* > ['] Spacing | ||
| 567 | // / ["] < ( !["] Char )* > ["] Spacing | ||
| 568 | fn parseLiteral(p: *Parser) !?Node.Index { | ||
| 569 | const quote: u8 = if (p.eat('\'')) '\'' else if (p.eat('"')) '"' else return null; | ||
| 570 | const off = p.strings.items.len; | ||
| 571 | while (!p.eat(quote)) { | ||
| 572 | const byte = p.parseChar() orelse return null; | ||
| 573 | try p.strings.append(p.gpa, byte); | ||
| 574 | } | ||
| 575 | _ = p.eatSpacing(); | ||
| 576 | return try p.addNode(.{ .literal = .{ | ||
| 577 | .off = @intCast(off), | ||
| 578 | .len = @intCast(p.strings.items.len - off), | ||
| 579 | } }); | ||
| 580 | } | ||
| 581 | |||
| 582 | // Class <- '[' < ( !']' Range )* > ']' Spacing | ||
| 583 | fn parseClass(p: *Parser) !?Node.Index { | ||
| 584 | var scratch: std.ArrayList(Node.Index) = .empty; | ||
| 585 | defer scratch.deinit(p.gpa); | ||
| 586 | if (!p.eat('[')) return null; | ||
| 587 | while (!p.eat(']')) { | ||
| 588 | const range = try p.parseRange() orelse return null; | ||
| 589 | try scratch.append(p.gpa, range); | ||
| 590 | } | ||
| 591 | _ = p.eatSpacing(); | ||
| 592 | const ranges = try p.addExtra(scratch.items); | ||
| 593 | return try p.addNode(.{ .class = ranges }); | ||
| 594 | } | ||
| 595 | |||
| 596 | // Range <- Char '-' Char / Char | ||
| 597 | fn parseRange(p: *Parser) !?Node.Index { | ||
| 598 | const start = p.parseChar() orelse return null; | ||
| 599 | const end = blk: { | ||
| 600 | if (p.eat('-')) { | ||
| 601 | break :blk p.parseChar() orelse return null; | ||
| 602 | } | ||
| 603 | break :blk start; | ||
| 604 | }; | ||
| 605 | return try p.addNode(.{ .range = .{ | ||
| 606 | .start = start, | ||
| 607 | .end = end, | ||
| 608 | } }); | ||
| 609 | } | ||
| 610 | |||
| 611 | // Char <- '\\' [abefnrtv'"\[\]\\] | ||
| 612 | // / '\\' [0-3][0-7][0-7] | ||
| 613 | // / '\\' [0-7][0-7]? | ||
| 614 | // / '\\' '-' | ||
| 615 | // / !'\\' . | ||
| 616 | fn parseChar(p: *Parser) ?u8 { | ||
| 617 | if (p.eat('\\')) { | ||
| 618 | const c = p.next() orelse return null; | ||
| 619 | return switch (c) { | ||
| 620 | // Only the escape sequences actually used in the Zig grammar are implemented | ||
| 621 | 'n' => '\n', | ||
| 622 | 'r' => '\r', | ||
| 623 | 't' => '\t', | ||
| 624 | '\'' => '\'', | ||
| 625 | '"' => '"', | ||
| 626 | '[' => '[', | ||
| 627 | ']' => ']', | ||
| 628 | '\\' => '\\', | ||
| 629 | '-' => '-', | ||
| 630 | '0'...'7' => { | ||
| 631 | // octal | ||
| 632 | if (c <= '3') { | ||
| 633 | const c2 = p.next() orelse return null; | ||
| 634 | if (c2 < '0' or c2 > '7') return null; | ||
| 635 | const c3 = p.next() orelse return null; | ||
| 636 | if (c3 < '0' or c3 > '7') return null; | ||
| 637 | return (c - '0') * 8 * 8 + (c2 - '0') * 8 + (c3 - '0'); | ||
| 638 | } else { | ||
| 639 | if (p.peek()) |c2| { | ||
| 640 | if (c2 >= '0' and c2 <= '7') { | ||
| 641 | p.i += 1; | ||
| 642 | return (c - '0') * 8 + (c2 - '0'); | ||
| 643 | } | ||
| 644 | } | ||
| 645 | return (c - '0'); | ||
| 646 | } | ||
| 647 | }, | ||
| 648 | else => null, | ||
| 649 | }; | ||
| 650 | } else { | ||
| 651 | return p.next(); | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | // LEFTARROW <- '<-' Spacing | ||
| 656 | fn eatLeftArrow(p: *Parser) bool { | ||
| 657 | return p.eat('<') and p.eat('-') and p.eatSpacing(); | ||
| 658 | } | ||
| 659 | |||
| 660 | // SLASH <- '/' Spacing | ||
| 661 | fn eatSlash(p: *Parser) bool { | ||
| 662 | return p.eat('/') and p.eatSpacing(); | ||
| 663 | } | ||
| 664 | |||
| 665 | // AND <- '&' Spacing | ||
| 666 | fn eatAnd(p: *Parser) bool { | ||
| 667 | return p.eat('&') and p.eatSpacing(); | ||
| 668 | } | ||
| 669 | |||
| 670 | // NOT <- '!' Spacing | ||
| 671 | fn eatNot(p: *Parser) bool { | ||
| 672 | return p.eat('!') and p.eatSpacing(); | ||
| 673 | } | ||
| 674 | |||
| 675 | // QUERY <- '?' Spacing | ||
| 676 | fn eatQuery(p: *Parser) bool { | ||
| 677 | return p.eat('?') and p.eatSpacing(); | ||
| 678 | } | ||
| 679 | |||
| 680 | // STAR <- '*' Spacing | ||
| 681 | fn eatStar(p: *Parser) bool { | ||
| 682 | return p.eat('*') and p.eatSpacing(); | ||
| 683 | } | ||
| 684 | |||
| 685 | // PLUS <- '+' Spacing | ||
| 686 | fn eatPlus(p: *Parser) bool { | ||
| 687 | return p.eat('+') and p.eatSpacing(); | ||
| 688 | } | ||
| 689 | |||
| 690 | // OPEN <- '(' Spacing | ||
| 691 | fn eatOpen(p: *Parser) bool { | ||
| 692 | return p.eat('(') and p.eatSpacing(); | ||
| 693 | } | ||
| 694 | |||
| 695 | // CLOSE <- ')' Spacing | ||
| 696 | fn eatClose(p: *Parser) bool { | ||
| 697 | return p.eat(')') and p.eatSpacing(); | ||
| 698 | } | ||
| 699 | |||
| 700 | // DOT <- '.' Spacing | ||
| 701 | fn eatDot(p: *Parser) bool { | ||
| 702 | return p.eat('.') and p.eatSpacing(); | ||
| 703 | } | ||
| 704 | |||
| 705 | // Spacing <- ( Space / Comment )* | ||
| 706 | fn eatSpacing(p: *Parser) bool { | ||
| 707 | while (p.eatSpace() or p.eatComment()) {} | ||
| 708 | return true; | ||
| 709 | } | ||
| 710 | |||
| 711 | // Comment <- '#' ( !EndOfLine . )* EndOfLine | ||
| 712 | fn eatComment(p: *Parser) bool { | ||
| 713 | if (!p.eat('#')) return false; | ||
| 714 | while (!p.eatEndOfLine()) p.i += 1; | ||
| 715 | return true; | ||
| 716 | } | ||
| 717 | |||
| 718 | // Space <- ' ' / '\t' / EndOfLine | ||
| 719 | fn eatSpace(p: *Parser) bool { | ||
| 720 | return p.eat(' ') or p.eat('\t') or p.eatEndOfLine(); | ||
| 721 | } | ||
| 722 | |||
| 723 | // EndOfLine <- '\r\n' / '\n' / '\r' | ||
| 724 | fn eatEndOfLine(p: *Parser) bool { | ||
| 725 | return p.eat('\n'); | ||
| 726 | } | ||
| 727 | |||
| 728 | fn peek(p: *Parser) ?u8 { | ||
| 729 | if (p.i < p.source.len) { | ||
| 730 | return p.source[p.i]; | ||
| 731 | } | ||
| 732 | return null; | ||
| 733 | } | ||
| 734 | |||
| 735 | fn next(p: *Parser) ?u8 { | ||
| 736 | if (p.i < p.source.len) { | ||
| 737 | defer p.i += 1; | ||
| 738 | return p.source[p.i]; | ||
| 739 | } | ||
| 740 | return null; | ||
| 741 | } | ||
| 742 | |||
| 743 | fn eat(p: *Parser, byte: u8) bool { | ||
| 744 | if (p.i < p.source.len and p.source[p.i] == byte) { | ||
| 745 | p.i += 1; | ||
| 746 | return true; | ||
| 747 | } | ||
| 748 | return false; | ||
| 749 | } | ||
| 750 | |||
| 751 | fn addNode(p: *Parser, node: Node) !Node.Index { | ||
| 752 | try p.nodes.append(p.gpa, node); | ||
| 753 | return @enumFromInt(p.nodes.items.len - 1); | ||
| 754 | } | ||
| 755 | |||
| 756 | fn addExtra(p: *Parser, nodes: []const Node.Index) !Node.Slice { | ||
| 757 | const off = p.extra.items.len; | ||
| 758 | try p.extra.appendSlice(p.gpa, nodes); | ||
| 759 | return .{ .off = @intCast(off), .len = @intCast(p.extra.items.len - off) }; | ||
| 760 | } | ||
| 761 | |||
| 762 | const Pos = struct { | ||
| 763 | i: u32, | ||
| 764 | nodes_len: u32, | ||
| 765 | extra_len: u32, | ||
| 766 | strings_len: u32, | ||
| 767 | }; | ||
| 768 | |||
| 769 | fn savePos(p: *const Parser) Pos { | ||
| 770 | return .{ | ||
| 771 | .i = p.i, | ||
| 772 | .nodes_len = @intCast(p.nodes.items.len), | ||
| 773 | .extra_len = @intCast(p.extra.items.len), | ||
| 774 | .strings_len = @intCast(p.strings.items.len), | ||
| 775 | }; | ||
| 776 | } | ||
| 777 | |||
| 778 | fn restorePos(p: *Parser, pos: Pos) void { | ||
| 779 | assert(p.i >= pos.i); | ||
| 780 | p.i = pos.i; | ||
| 781 | p.nodes.shrinkRetainingCapacity(pos.nodes_len); | ||
| 782 | p.extra.shrinkRetainingCapacity(pos.extra_len); | ||
| 783 | p.strings.shrinkRetainingCapacity(pos.strings_len); | ||
| 784 | } | ||
| 785 | |||
| 786 | fn getExtra(p: *const Parser, s: Node.Slice) []const Node.Index { | ||
| 787 | return p.extra.items[s.off..][0..s.len]; | ||
| 788 | } | ||
| 789 | }; | ||
tools/gen_spirv_spec.zig+1-1| ... | @@ -116,7 +116,7 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -116,7 +116,7 @@ pub fn main(init: std.process.Init) !void { |
| 116 | try allocating.writer.writeByte(0); | 116 | try allocating.writer.writeByte(0); |
| 117 | const output = allocating.written()[0 .. allocating.written().len - 1 :0]; | 117 | const output = allocating.written()[0 .. allocating.written().len - 1 :0]; |
| 118 | 118 | ||
| 119 | var tree = try std.zig.Ast.parse(arena, output, .zig); | 119 | var tree = try std.zig.Ast.parse(arena, output, .zig, .{}); |
| 120 | 120 | ||
| 121 | if (tree.errors.len != 0) { | 121 | if (tree.errors.len != 0) { |
| 122 | try std.zig.printAstErrorsToStderr(arena, io, tree, "", .auto); | 122 | try std.zig.printAstErrorsToStderr(arena, io, tree, "", .auto); |