authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-08 21:46:59+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-08 21:46:59+02:00
logcf8120f58f0db251cf5b144ec644d0da465aec45
tree7379e64047704b32a614511ffb1d0ac7e253a6a5
parentde7fdfecd81e74c115395256179c64cb480cb860
parentb2c3c33eef468634a2fc47b19bfb2e6f51a1a9b4

Merge pull request 'Make std.zig.Ast.parse() and grammar.peg finally agree' (#36094) from ifreund/zig:parser-oracle into master

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 {
719719 check_mingw_run.addDirectoryArg(b.path("lib/libc/mingw"));
720720 check_mingw_step.dependOn(&check_mingw_run.step);
721721
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
722746 const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases");
723747 try tests.addIncrementalTests(b, test_incremental_step, test_filters);
724748 if (!skip_test_incremental) test_step.dependOn(test_incremental_step);
......@@ -1569,8 +1593,9 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath {
15691593
15701594 var it = dir.iterateAssumeFirstIteration();
15711595 while (it.next(io) catch @panic("failed to read dir")) |entry| {
1572 if (std.mem.startsWith(u8, entry.name, ".") or entry.kind != .file)
1573 continue;
1596 if (entry.kind != .file) continue;
1597 if (std.mem.startsWith(u8, entry.name, ".")) continue;
1598 if (!std.mem.endsWith(u8, entry.name, ".zig")) continue;
15741599
15751600 const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)});
15761601 const cmd = b.addRunArtifact(doctest_exe);
......@@ -1603,6 +1628,8 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath {
16031628 const docgen_cmd = b.addRunArtifact(docgen_exe);
16041629 docgen_cmd.addArgs(&.{"--code-dir"});
16051630 docgen_cmd.addDirectoryArg(wf.getDirectory());
1631 docgen_cmd.addArgs(&.{"--grammar"});
1632 docgen_cmd.addFileArg(b.path("doc/langref/grammar.peg"));
16061633
16071634 docgen_cmd.addFileArg(b.path("doc/langref.html.in"));
16081635 return docgen_cmd.addOutputFileArg("langref.html");
doc/langref.html.in+1-591
......@@ -7798,597 +7798,7 @@ fn readU32Be() u32 {}
77987798
77997799 {#header_open|Appendix#}
78007800 {#header_open|Grammar#}
7801 {#syntax_block|peg|grammar.peg#}
7802Root <- skip ContainerMembers eof
7803
7804# *** Top level ***
7805ContainerMembers <- container_doc_comment? ContainerDeclaration* (ContainerField COMMA)* (ContainerField / ContainerDeclaration*)
7806
7807ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl
7808
7809TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block
7810
7811ComptimeDecl <- KEYWORD_comptime Block
7812
7813Decl
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
7818FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix
7819
7820VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection?
7821
7822GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON
7823
7824ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)?
7825
7826# *** Block Level ***
7827BlockStatement
7828 <- Statement
7829 / KEYWORD_defer BlockExprStatement
7830 / KEYWORD_errdefer BlockExprStatement
7831 / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
7832
7833Statement
7834 <- ExprStatement
7835 / KEYWORD_suspend BlockExprStatement
7836 / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON
7837
7838ExprStatement
7839 <- IfStatement
7840 / LabeledStatement
7841 / KEYWORD_nosuspend BlockExprStatement
7842 / KEYWORD_comptime BlockExpr
7843
7844IfStatement
7845 <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
7846 / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
7847
7848LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)
7849
7850LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
7851
7852ForStatement
7853 <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )
7854 / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement )
7855
7856WhileStatement
7857 <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
7858 / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
7859
7860BlockExprStatement
7861 <- BlockExpr
7862 / !BlockExpr AssignExpr SEMICOLON
7863
7864BlockExpr <- BlockLabel? Block
7865
7866# An assignment or a destructure whose LHS are all lvalue expressions or variable declarations.
7867VarAssignStatement <- (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.
7872AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)?
7873
7874SingleAssignExpr <- Expr (AssignOp Expr)?
7875
7876Expr <- BoolOrExpr
7877
7878BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
7879
7880BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
7881
7882CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
7883
7884BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
7885
7886BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
7887
7888AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
7889
7890MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
7891
7892PrefixExpr <- PrefixOp* PrimaryExpr
7893
7894PrimaryExpr
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
7907IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
7908
7909Block <- LBRACE BlockStatement* RBRACE
7910
7911LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
7912
7913ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix
7914
7915WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
7916
7917CurlySuffixExpr <- TypeExpr InitList?
7918
7919InitList
7920 <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
7921 / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
7922 / LBRACE RBRACE
7923
7924TypeExpr <- PrefixTypeOp* ErrorUnionExpr
7925
7926ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
7927
7928SuffixExpr
7929 <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
7930
7931PrimaryTypeExpr
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
7951ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
7952
7953ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
7954
7955GroupedExpr <- LPAREN Expr RPAREN
7956
7957IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
7958
7959LabeledTypeExpr
7960 <- BlockLabel Block
7961 / BlockLabel? LoopTypeExpr
7962 / BlockLabel? SwitchExpr
7963
7964LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
7965
7966ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix
7967
7968WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
7969
7970SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
7971
7972# *** Assembly ***
7973AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
7974
7975AsmOutput <- COLON AsmOutputList AsmInput?
7976
7977AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
7978
7979AsmInput <- COLON AsmInputList AsmClobbers?
7980
7981AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN
7982
7983AsmClobbers <- COLON Expr
7984
7985# *** Helper grammar ***
7986BreakLabel <- COLON IDENTIFIER
7987
7988BlockLabel <- IDENTIFIER COLON
7989
7990FieldInit <- DOT IDENTIFIER EQUAL Expr
7991
7992WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
7993
7994LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
7995
7996AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
7997
7998# Fn specific
7999CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
8000
8001ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime / !KEYWORD_comptime) (IDENTIFIER COLON / !(IDENTIFIER COLON)) ParamType
8002
8003ParamType
8004 <- KEYWORD_anytype
8005 / TypeExpr
8006
8007# Control flow prefixes
8008IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
8009
8010WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
8011
8012ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload
8013
8014# Payloads
8015Payload <- PIPE IDENTIFIER PIPE
8016
8017PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
8018
8019PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
8020
8021PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE
8022
8023# Switch specific
8024SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr
8025
8026SwitchCase
8027 <- SwitchItem (COMMA SwitchItem)* COMMA?
8028 / KEYWORD_else
8029
8030SwitchItem <- Expr (DOT3 Expr)?
8031
8032# For specific
8033ForArgumentsList <- ForItem (COMMA ForItem)* COMMA?
8034
8035ForItem <- Expr (DOT2 Expr?)?
8036
8037# Operators
8038AssignOp
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
8058CompareOp
8059 <- EQUALEQUAL
8060 / EXCLAMATIONMARKEQUAL
8061 / LARROW
8062 / RARROW
8063 / LARROWEQUAL
8064 / RARROWEQUAL
8065
8066BitwiseOp
8067 <- AMPERSAND
8068 / CARET
8069 / PIPE
8070 / KEYWORD_orelse
8071 / KEYWORD_catch Payload?
8072
8073BitShiftOp
8074 <- LARROW2
8075 / RARROW2
8076 / LARROW2PIPE
8077
8078AdditionOp
8079 <- PLUS
8080 / MINUS
8081 / PLUS2
8082 / PLUSPERCENT
8083 / MINUSPERCENT
8084 / PLUSPIPE
8085 / MINUSPIPE
8086
8087MultiplyOp
8088 <- PIPE2
8089 / ASTERISK
8090 / SLASH
8091 / PERCENT
8092 / ASTERISKPERCENT
8093 / ASTERISKPIPE
8094
8095PrefixOp
8096 <- EXCLAMATIONMARK
8097 / MINUS
8098 / TILDE
8099 / MINUSPERCENT
8100 / AMPERSAND
8101 / KEYWORD_try
8102
8103PrefixTypeOp
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
8110SuffixOp
8111 <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET
8112 / DOT IDENTIFIER
8113 / DOTASTERISK
8114 / DOTQUESTIONMARK
8115
8116FnCallArguments <- LPAREN ExprList RPAREN
8117
8118ExprSuffix
8119 <- KEYWORD_or
8120 / KEYWORD_and
8121 / CompareOp
8122 / BitwiseOp
8123 / BitShiftOp
8124 / AdditionOp
8125 / MultiplyOp
8126 / EXCLAMATIONMARK
8127 / SuffixOp
8128 / FnCallArguments
8129
8130LabelableExpr
8131 <- Block
8132 / SwitchExpr
8133 / LoopExpr
8134
8135# Ptr specific
8136SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
8137
8138SinglePtrTypeStart <- ASTERISK
8139
8140ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
8141
8142ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET
8143
8144# ContainerDecl specific
8145ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
8146
8147ContainerDeclType
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
8154ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
8155
8156BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
8157
8158# Lists
8159IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?
8160
8161SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
8162
8163AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
8164
8165AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
8166
8167ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)?
8168
8169ExprList <- (Expr COMMA)* Expr?
8170
8171# *** Tokens ***
8172eof <- !.
8173bin <- [01]
8174bin_ <- '_'? bin
8175oct <- [0-7]
8176oct_ <- '_'? oct
8177hex <- [0-9a-fA-F]
8178hex_ <- '_'? hex
8179dec <- [0-9]
8180dec_ <- '_'? dec
8181
8182bin_int <- bin bin_*
8183oct_int <- oct oct_*
8184dec_int <- dec dec_*
8185hex_int <- hex hex_*
8186
8187ox80_oxBF <- [\200-\277]
8188oxF4 <- '\364'
8189ox80_ox8F <- [\200-\217]
8190oxF1_oxF3 <- [\361-\363]
8191oxF0 <- '\360'
8192ox90_0xBF <- [\220-\277]
8193oxEE_oxEF <- [\356-\357]
8194oxED <- '\355'
8195ox80_ox9F <- [\200-\237]
8196oxE1_oxEC <- [\341-\354]
8197oxE0 <- '\340'
8198oxA0_oxBF <- [\240-\277]
8199oxC2_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
8213multibyte_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
8223non_control_ascii <- [\040-\176]
8224non_control_utf8 <- [\040-\377]
8225
8226char_escape
8227 <- "\\x" hex hex
8228 / "\\u{" hex+ "}"
8229 / "\\" [nr\\t'"]
8230char_char
8231 <- multibyte_utf8
8232 / char_escape
8233 / ![\\'\n] non_control_ascii
8234
8235string_char
8236 <- multibyte_utf8
8237 / char_escape
8238 / ![\\"\n] non_control_ascii
8239
8240container_doc_comment <- ('//!' non_control_utf8* [ \n]* skip)+
8241doc_comment <- ('///' non_control_utf8* [ \n]* skip)+
8242line_comment <- '//' ![!/] non_control_utf8* / '////' non_control_utf8*
8243line_string <- '\\\\' non_control_utf8* [ \n]*
8244skip <- ([ \n] / line_comment)*
8245
8246CHAR_LITERAL <- ['] char_char ['] skip
8247FLOAT
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
8252INTEGER
8253 <- '0b' bin_int skip
8254 / '0o' oct_int skip
8255 / '0x' hex_int skip
8256 / dec_int skip
8257STRINGLITERALSINGLE <- ["] string_char* ["] skip
8258STRINGLITERAL
8259 <- STRINGLITERALSINGLE
8260 / (line_string skip)+
8261IDENTIFIER
8262 <- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
8263 / '@' STRINGLITERALSINGLE
8264BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip
8265
8266
8267AMPERSAND <- '&' ![=] skip
8268AMPERSANDEQUAL <- '&=' skip
8269ASTERISK <- '*' ![%=|] skip
8270ASTERISKEQUAL <- '*=' skip
8271ASTERISKPERCENT <- '*%' ![=] skip
8272ASTERISKPERCENTEQUAL <- '*%=' skip
8273ASTERISKPIPE <- '*|' ![=] skip
8274ASTERISKPIPEEQUAL <- '*|=' skip
8275CARET <- '^' ![=] skip
8276CARETEQUAL <- '^=' skip
8277COLON <- ':' skip
8278COMMA <- ',' skip
8279DOT <- '.' ![*.?] skip
8280DOT2 <- '..' ![.] skip
8281DOT3 <- '...' skip
8282DOTASTERISK <- '.*' skip
8283DOTQUESTIONMARK <- '.?' skip
8284EQUAL <- '=' ![>=] skip
8285EQUALEQUAL <- '==' skip
8286EQUALRARROW <- '=>' skip
8287EXCLAMATIONMARK <- '!' ![=] skip
8288EXCLAMATIONMARKEQUAL <- '!=' skip
8289LARROW <- '<' ![<=] skip
8290LARROW2 <- '<<' ![=|] skip
8291LARROW2EQUAL <- '<<=' skip
8292LARROW2PIPE <- '<<|' ![=] skip
8293LARROW2PIPEEQUAL <- '<<|=' skip
8294LARROWEQUAL <- '<=' skip
8295LBRACE <- '{' skip
8296LBRACKET <- '[' skip
8297LPAREN <- '(' skip
8298MINUS <- '-' ![%=>|] skip
8299MINUSEQUAL <- '-=' skip
8300MINUSPERCENT <- '-%' ![=] skip
8301MINUSPERCENTEQUAL <- '-%=' skip
8302MINUSPIPE <- '-|' ![=] skip
8303MINUSPIPEEQUAL <- '-|=' skip
8304MINUSRARROW <- '->' skip
8305PERCENT <- '%' ![=] skip
8306PERCENTEQUAL <- '%=' skip
8307PIPE <- '|' ![|=] skip
8308PIPE2 <- '||' skip
8309PIPEEQUAL <- '|=' skip
8310PLUS <- '+' ![%+=|] skip
8311PLUS2 <- '++' skip
8312PLUSEQUAL <- '+=' skip
8313PLUSPERCENT <- '+%' ![=] skip
8314PLUSPERCENTEQUAL <- '+%=' skip
8315PLUSPIPE <- '+|' ![=] skip
8316PLUSPIPEEQUAL <- '+|=' skip
8317LETTERC <- 'c' skip
8318QUESTIONMARK <- '?' skip
8319RARROW <- '>' ![>=] skip
8320RARROW2 <- '>>' ![=] skip
8321RARROW2EQUAL <- '>>=' skip
8322RARROWEQUAL <- '>=' skip
8323RBRACE <- '}' skip
8324RBRACKET <- ']' skip
8325RPAREN <- ')' skip
8326SEMICOLON <- ';' skip
8327SLASH <- '/' ![=] skip
8328SLASHEQUAL <- '/=' skip
8329TILDE <- '~' skip
8330
8331end_of_word <- ![a-zA-Z0-9_] skip
8332KEYWORD_addrspace <- 'addrspace' end_of_word
8333KEYWORD_align <- 'align' end_of_word
8334KEYWORD_allowzero <- 'allowzero' end_of_word
8335KEYWORD_and <- 'and' end_of_word
8336KEYWORD_anyframe <- 'anyframe' end_of_word
8337KEYWORD_anytype <- 'anytype' end_of_word
8338KEYWORD_asm <- 'asm' end_of_word
8339KEYWORD_break <- 'break' end_of_word
8340KEYWORD_callconv <- 'callconv' end_of_word
8341KEYWORD_catch <- 'catch' end_of_word
8342KEYWORD_comptime <- 'comptime' end_of_word
8343KEYWORD_const <- 'const' end_of_word
8344KEYWORD_continue <- 'continue' end_of_word
8345KEYWORD_defer <- 'defer' end_of_word
8346KEYWORD_else <- 'else' end_of_word
8347KEYWORD_enum <- 'enum' end_of_word
8348KEYWORD_errdefer <- 'errdefer' end_of_word
8349KEYWORD_error <- 'error' end_of_word
8350KEYWORD_export <- 'export' end_of_word
8351KEYWORD_extern <- 'extern' end_of_word
8352KEYWORD_fn <- 'fn' end_of_word
8353KEYWORD_for <- 'for' end_of_word
8354KEYWORD_if <- 'if' end_of_word
8355KEYWORD_inline <- 'inline' end_of_word
8356KEYWORD_noalias <- 'noalias' end_of_word
8357KEYWORD_nosuspend <- 'nosuspend' end_of_word
8358KEYWORD_noinline <- 'noinline' end_of_word
8359KEYWORD_opaque <- 'opaque' end_of_word
8360KEYWORD_or <- 'or' end_of_word
8361KEYWORD_orelse <- 'orelse' end_of_word
8362KEYWORD_packed <- 'packed' end_of_word
8363KEYWORD_pub <- 'pub' end_of_word
8364KEYWORD_resume <- 'resume' end_of_word
8365KEYWORD_return <- 'return' end_of_word
8366KEYWORD_linksection <- 'linksection' end_of_word
8367KEYWORD_struct <- 'struct' end_of_word
8368KEYWORD_suspend <- 'suspend' end_of_word
8369KEYWORD_switch <- 'switch' end_of_word
8370KEYWORD_test <- 'test' end_of_word
8371KEYWORD_threadlocal <- 'threadlocal' end_of_word
8372KEYWORD_try <- 'try' end_of_word
8373KEYWORD_union <- 'union' end_of_word
8374KEYWORD_unreachable <- 'unreachable' end_of_word
8375KEYWORD_var <- 'var' end_of_word
8376KEYWORD_volatile <- 'volatile' end_of_word
8377KEYWORD_while <- 'while' end_of_word
8378
8379keyword <- 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#}
7801 {#grammar#}
83927802 {#header_close#}
83937803 {#header_open|Zen#}
83947804 <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
39Root <- ContainerMembers skip eof
40
41# *** Top level ***
42ContainerMembers <- container_doc_comment? ContainerDecl* ContainerMembersRest
43ContainerMembersRest
44 <- !ContainerDeclPrefix ContainerField (COMMA ContainerMembersRest)?
45 / ContainerDecl*
46
47ContainerDecl <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl
48
49ContainerDeclPrefix
50 <- KEYWORD_test
51 / KEYWORD_comptime LBRACE
52 / doc_comment? KEYWORD_pub? DeclPrefix
53
54TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block
55
56ComptimeDecl <- KEYWORD_comptime Block
57
58Decl
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
63DeclPrefix
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
68FnProto <- KEYWORD_fn IDENTIFIER? ParamDeclList ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
69
70VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection?
71
72GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON
73
74ContainerField <- doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)?
75
76# *** Block Level ***
77BlockStatement
78 <- Statement
79 / KEYWORD_defer BlockExprStatement
80 / KEYWORD_errdefer BlockExprStatement
81 / !StatementPrefix KEYWORD_comptime? VarAssignStatement
82
83Statement
84 <- IfStatement
85 / LabeledStatement
86 / KEYWORD_nosuspend BlockExprStatement
87 / KEYWORD_comptime BlockExpr
88 / KEYWORD_suspend BlockExprStatement
89 / !StatementPrefix KEYWORD_comptime? AssignExpr SEMICOLON
90
91StatementPrefix
92 <- KEYWORD_if
93 / BlockLabel? (LBRACE / KEYWORD_inline? (KEYWORD_for / KEYWORD_while) / KEYWORD_switch)
94 / KEYWORD_nosuspend
95 / KEYWORD_comptime BlockExprPrefix
96
97IfStatement
98 <- IfPrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else)
99 / IfPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement)
100
101LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)
102
103LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
104
105ForStatement
106 <- ForPrefix BlockExpr (KEYWORD_else Statement / !KEYWORD_else)
107 / ForPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Statement)
108
109WhileStatement
110 <- WhilePrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else)
111 / WhilePrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement)
112
113BlockExprStatement
114 <- BlockExpr
115 / !BlockExprPrefix AssignExpr SEMICOLON
116
117BlockExprPrefix <- BlockLabel? LBRACE
118BlockExpr <- BlockLabel? Block
119
120# An assignment or a destructure whose LHS are all lvalue expressions or variable declarations.
121VarAssignStatement <- (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.
126AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA)
127
128SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp)
129
130Expr <- BoolOrExpr
131
132BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp
133
134BoolAndExpr <- CompareExpr (AndOp CompareExpr)* !AndOp
135
136CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? !CompareOp
137
138BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* !BitwiseOp
139
140BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* !BitShiftOp
141
142AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* !AdditionOp
143
144MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* !MultiplyOp
145
146PrefixExpr <- PrefixOp* !PrefixOp PrimaryExpr
147
148PrimaryExpr
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
161IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else)
162
163Block <- LBRACE BlockStatement* RBRACE
164
165LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
166
167ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else)
168
169WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
170
171CurlySuffixExpr <- TypeExpr (InitList / !LBRACE)
172
173InitList
174 <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
175 / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
176 / LBRACE RBRACE
177
178TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr
179
180ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK)
181
182SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix
183
184PrimaryTypeExpr
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
203ContainerType <- (KEYWORD_extern / KEYWORD_packed)? ContainerTypeAuto
204
205ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
206
207GroupedExpr <- LPAREN Expr RPAREN
208
209IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
210
211LabeledTypeExpr
212 <- BlockLabel Block
213 / BlockLabel? LoopTypeExpr
214 / BlockLabel? SwitchExpr
215
216LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
217
218ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else)
219
220WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
221
222SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
223
224# *** Assembly ***
225AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
226
227AsmOutput <- COLON AsmOutputList AsmInput?
228
229AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
230
231AsmInput <- COLON AsmInputList AsmClobbers?
232
233AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN
234
235AsmClobbers <- COLON Expr
236
237# *** Helper grammar ***
238BreakLabel <- COLON IDENTIFIER
239
240BlockLabel <- IDENTIFIER COLON
241
242FieldInit <- DOT IDENTIFIER EQUAL Expr
243
244WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
245
246LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
247
248AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
249
250# Fn specific
251CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
252
253ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime?) (IDENTIFIER COLON)? ParamType
254
255ParamType
256 <- KEYWORD_anytype
257 / TypeExpr
258
259# Control flow prefixes
260IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
261
262WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
263
264ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload
265
266# Payloads
267Payload <- PIPE IDENTIFIER PIPE
268
269PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
270
271PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
272
273PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE
274
275# Switch specific
276SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr
277
278SwitchCase
279 <- SwitchItem (COMMA SwitchItem)* COMMA?
280 / KEYWORD_else
281
282SwitchItem <- Expr (DOT3 Expr)?
283
284# For specific
285ForArgumentsList <- ForItem (COMMA ForItem)* COMMA?
286
287ForItem <- Expr (DOT2 (Expr / !ExprPrefix) / !DOT2)
288
289# Operators
290AssignOp
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
310OrOp <- pre_op_white KEYWORD_or post_op_white
311 / !pre_op_white KEYWORD_or !post_op_white
312
313AndOp <- pre_op_white KEYWORD_and post_op_white
314 / !pre_op_white KEYWORD_and !post_op_white
315
316CompareOp <- pre_op_white CompareOpTok post_op_white
317 / !pre_op_white CompareOpTok !post_op_white
318CompareOpTok
319 <- EQUALEQUAL
320 / EXCLAMATIONMARKEQUAL
321 / LARROW
322 / RARROW
323 / LARROWEQUAL
324 / RARROWEQUAL
325
326BitwiseOp <- 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?
330BitwiseOpTok
331 <- AMPERSAND ![&]
332 / CARET
333 / PIPE
334 / KEYWORD_orelse
335
336BitShiftOp <- pre_op_white BitShiftOpTok post_op_white
337 / !pre_op_white BitShiftOpTok !post_op_white
338BitShiftOpTok
339 <- LARROW2
340 / RARROW2
341 / LARROW2PIPE
342
343AdditionOp <- pre_op_white AdditionOpTok post_op_white
344 / !pre_op_white AdditionOpTok !post_op_white
345AdditionOpTok
346 <- PLUS
347 / MINUS
348 / PLUS2
349 / PLUSPERCENT
350 / MINUSPERCENT
351 / PLUSPIPE
352 / MINUSPIPE
353
354MultiplyOp <- pre_op_white MultiplyOpTok post_op_white
355 / !pre_op_white MultiplyOpTok !post_op_white
356MultiplyOpTok
357 <- PIPE2
358 / ASTERISK
359 / SLASH
360 / PERCENT
361 / ASTERISKPERCENT
362 / ASTERISKPIPE
363
364PrefixOp
365 <- EXCLAMATIONMARK
366 / MINUS
367 / TILDE
368 / MINUSPERCENT
369 / AMPERSAND
370 / KEYWORD_try
371
372PrefixTypeOp
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.
385PtrMods
386 <- PtrMod* !KEYWORD_addrspace ByteAlign? PtrMod* AddrSpace? PtrMod*
387 / PtrMod* !KEYWORD_align AddrSpace? PtrMod* ByteAlign? PtrMod*
388
389SinglePtrMods
390 <- PtrMod* !KEYWORD_addrspace BitAlign? PtrMod* AddrSpace? PtrMod*
391 / PtrMod* !KEYWORD_align AddrSpace? PtrMod* BitAlign? PtrMod*
392
393PtrMod
394 <- KEYWORD_allowzero
395 / KEYWORD_const
396 / KEYWORD_volatile
397
398PrefixTypeOpPrefix
399 <- QUESTIONMARK
400 / KEYWORD_anyframe MINUSRARROW
401 / LBRACKET
402 / ASTERISK
403
404SuffixOp
405 <- LBRACKET Expr (DOT2 (Expr / !ExprPrefix) (COLON Expr)?)? RBRACKET
406 / DOT IDENTIFIER
407 / DOTASTERISK
408 / DOT QUESTIONMARK
409 / FnCallArguments
410
411SuffixOpPrefix
412 <- LBRACKET
413 / DOT IDENTIFIER
414 / DOTASTERISK
415 / DOT QUESTIONMARK
416 / LPAREN
417
418FnCallArguments <- LPAREN ExprList RPAREN
419
420# Ptr specific
421SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
422
423SinglePtrTypeStart <- ASTERISK
424
425ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
426
427ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET
428
429# ContainerType specific
430ContainerTypeAuto <- ContainerTypeKind LBRACE ContainerMembers RBRACE
431
432ContainerTypeKind
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
439ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
440
441BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
442
443# Lists
444IdentifierList <- (doc_comment? IDENTIFIER (COMMA IdentifierList)?)?
445
446SwitchProngList <- (SwitchProng (COMMA SwitchProngList)?)?
447
448AsmOutputList <- (AsmOutputItem (COMMA AsmOutputList)?)?
449
450AsmInputList <- (AsmInputItem (COMMA AsmInputList)?)?
451
452ParamDeclList <- LPAREN ParamDeclListRest
453ParamDeclListRest
454 <- RPAREN
455 / DOT3 COMMA? RPAREN
456 / ParamDecl (COMMA ParamDeclListRest / RPAREN)
457
458ExprList <- Expr (COMMA ExprList)? / !ExprPrefix
459
460ExprPrefix <- ASTERISK
461
462# *** Tokens ***
463
464# https://en.wikipedia.org/wiki/Byte_order_mark
465byte_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.
471sof <- &{ (yy->__pos == 0) } byte_order_mark?
472eof <- !.
473
474ox80_oxBF <- [\200-\277]
475oxF4 <- '\364'
476ox80_ox8F <- [\200-\217]
477oxF1_oxF3 <- [\361-\363]
478oxF0 <- '\360'
479ox90_0xBF <- [\220-\277]
480oxEE_oxEF <- [\356-\357]
481oxED <- '\355'
482ox80_ox9F <- [\200-\237]
483oxE1_oxEC <- [\341-\354]
484oxE0 <- '\340'
485oxA0_oxBF <- [\240-\277]
486oxC2_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
500multibyte_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
511non_control_ascii <- [\040-\176]
512non_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
529char_char
530 <- "\\\\"
531 / "\\'"
532 / !['] non_control_utf8
533
534string_char
535 <- '\\\\'
536 / '\\"'
537 / !["] non_control_utf8
538
539
540container_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.
543doc_comment <- (sof / skip_require_newline) (skip '///' non_control_utf8* newline)+
544line_comment
545 <- '//' ![!/] non_control_utf8* newline
546 / '////' non_control_utf8* newline
547line_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.
552newline <- &("\n" / "\r\n" / eof)
553skip <- sof? ([ \n\t\r] / line_comment)*
554skip_require_newline <- [ \t\r]* ([\n] / line_comment) skip
555pre_op_white <- ([ \n\t\r] / line_comment)+
556post_op_white <- [ \n\t\r] skip
557
558CHAR_LITERAL <- skip ['] char_char* [']
559
560digit <- [_0-9A-DF-OQ-Za-df-oq-z]
561digit_int <- digit / [eEpP]
562digit_float <- digit / [eEpP] [-+]?
563NUMBERLITERAL
564 <- skip [0-9] digit_int* '.' digit_float+
565 / skip [0-9] digit_float*
566
567
568string <- ["] string_char* ["]
569STRINGLITERALSINGLE <- skip string
570STRINGLITERAL
571 <- skip string
572 / (skip line_string)+
573IDENTIFIER
574 <- skip !keyword [A-Za-z_] [A-Za-z0-9_]*
575 / skip '@' string
576BUILTINIDENTIFIER <- skip '@'[A-Za-z_][A-Za-z0-9_]*
577
578
579AMPERSAND <- skip '&' ![=]
580AMPERSANDEQUAL <- skip '&='
581ASTERISK <- skip '*' ![%=|]
582ASTERISKEQUAL <- skip '*='
583ASTERISKPERCENT <- skip '*%' ![=]
584ASTERISKPERCENTEQUAL <- skip '*%='
585ASTERISKPIPE <- skip '*|' ![=]
586ASTERISKPIPEEQUAL <- skip '*|='
587CARET <- skip '^' ![=]
588CARETEQUAL <- skip '^='
589COLON <- skip ':'
590COMMA <- skip ','
591DOT <- skip '.' ![*.]
592DOT2 <- skip '..' ![.]
593DOT3 <- skip '...'
594DOTASTERISK <- skip '.*'
595EQUAL <- skip '=' ![>=]
596EQUALEQUAL <- skip '=='
597EQUALRARROW <- skip '=>'
598EXCLAMATIONMARK <- skip '!' ![=]
599EXCLAMATIONMARKEQUAL <- skip '!='
600LARROW <- skip '<' ![<=]
601LARROW2 <- skip '<<' ![=|]
602LARROW2EQUAL <- skip '<<='
603LARROW2PIPE <- skip '<<|' ![=]
604LARROW2PIPEEQUAL <- skip '<<|='
605LARROWEQUAL <- skip '<='
606LBRACE <- skip '{'
607LBRACKET <- skip '['
608LPAREN <- skip '('
609MINUS <- skip '-' ![%=>|]
610MINUSEQUAL <- skip '-='
611MINUSPERCENT <- skip '-%' ![=]
612MINUSPERCENTEQUAL <- skip '-%='
613MINUSPIPE <- skip '-|' ![=]
614MINUSPIPEEQUAL <- skip '-|='
615MINUSRARROW <- skip '->'
616PERCENT <- skip '%' ![=]
617PERCENTEQUAL <- skip '%='
618PIPE <- skip '|' ![|=]
619PIPE2 <- skip '||'
620PIPEEQUAL <- skip '|='
621PLUS <- skip '+' ![%+=|]
622PLUS2 <- skip '++'
623PLUSEQUAL <- skip '+='
624PLUSPERCENT <- skip '+%' ![=]
625PLUSPERCENTEQUAL <- skip '+%='
626PLUSPIPE <- skip '+|' ![=]
627PLUSPIPEEQUAL <- skip '+|='
628LETTERC <- skip 'c'
629QUESTIONMARK <- skip '?'
630RARROW <- skip '>' ![>=]
631RARROW2 <- skip '>>' ![=]
632RARROW2EQUAL <- skip '>>='
633RARROWEQUAL <- skip '>='
634RBRACE <- skip '}'
635RBRACKET <- skip ']'
636RPAREN <- skip ')'
637SEMICOLON <- skip ';'
638SLASH <- skip '/' ![=/]
639SLASHEQUAL <- skip '/='
640TILDE <- skip '~'
641
642end_of_word <- ![a-zA-Z0-9_]
643KEYWORD_addrspace <- skip 'addrspace' end_of_word
644KEYWORD_align <- skip 'align' end_of_word
645KEYWORD_allowzero <- skip 'allowzero' end_of_word
646KEYWORD_and <- skip 'and' end_of_word
647KEYWORD_anyframe <- skip 'anyframe' end_of_word
648KEYWORD_anytype <- skip 'anytype' end_of_word
649KEYWORD_asm <- skip 'asm' end_of_word
650KEYWORD_break <- skip 'break' end_of_word
651KEYWORD_callconv <- skip 'callconv' end_of_word
652KEYWORD_catch <- skip 'catch' end_of_word
653KEYWORD_comptime <- skip 'comptime' end_of_word
654KEYWORD_const <- skip 'const' end_of_word
655KEYWORD_continue <- skip 'continue' end_of_word
656KEYWORD_defer <- skip 'defer' end_of_word
657KEYWORD_else <- skip 'else' end_of_word
658KEYWORD_enum <- skip 'enum' end_of_word
659KEYWORD_errdefer <- skip 'errdefer' end_of_word
660KEYWORD_error <- skip 'error' end_of_word
661KEYWORD_export <- skip 'export' end_of_word
662KEYWORD_extern <- skip 'extern' end_of_word
663KEYWORD_fn <- skip 'fn' end_of_word
664KEYWORD_for <- skip 'for' end_of_word
665KEYWORD_if <- skip 'if' end_of_word
666KEYWORD_inline <- skip 'inline' end_of_word
667KEYWORD_noalias <- skip 'noalias' end_of_word
668KEYWORD_nosuspend <- skip 'nosuspend' end_of_word
669KEYWORD_noinline <- skip 'noinline' end_of_word
670KEYWORD_opaque <- skip 'opaque' end_of_word
671KEYWORD_or <- skip 'or' end_of_word
672KEYWORD_orelse <- skip 'orelse' end_of_word
673KEYWORD_packed <- skip 'packed' end_of_word
674KEYWORD_pub <- skip 'pub' end_of_word
675KEYWORD_resume <- skip 'resume' end_of_word
676KEYWORD_return <- skip 'return' end_of_word
677KEYWORD_linksection <- skip 'linksection' end_of_word
678KEYWORD_struct <- skip 'struct' end_of_word
679KEYWORD_suspend <- skip 'suspend' end_of_word
680KEYWORD_switch <- skip 'switch' end_of_word
681KEYWORD_test <- skip 'test' end_of_word
682KEYWORD_threadlocal <- skip 'threadlocal' end_of_word
683KEYWORD_try <- skip 'try' end_of_word
684KEYWORD_union <- skip 'union' end_of_word
685KEYWORD_unreachable <- skip 'unreachable' end_of_word
686KEYWORD_var <- skip 'var' end_of_word
687KEYWORD_volatile <- skip 'volatile' end_of_word
688KEYWORD_while <- skip 'while' end_of_word
689
690keyword <- 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(
35363536 else => |e| fatal("unable to load {s}: {t}", .{ Package.Manifest.basename, e }),
35373537 };
35383538 };
3539 var ast = try std.zig.Ast.parse(gpa, manifest_bytes, .zon);
3539 var ast = try std.zig.Ast.parse(gpa, manifest_bytes, .zon, .{});
35403540 errdefer ast.deinit(gpa);
35413541
35423542 if (ast.errors.len > 0) {
lib/compiler/Maker/Package/Manifest.zig+4-4
......@@ -597,7 +597,7 @@ pub fn load(
597597 0,
598598 );
599599
600 ast.* = try std.zig.Ast.parse(arena, manifest_bytes, .zon);
600 ast.* = try std.zig.Ast.parse(arena, manifest_bytes, .zon, .{});
601601
602602 if (ast.errors.len > 0) {
603603 const file_path = try manifest_path.joinString(arena, "");
......@@ -636,7 +636,7 @@ test "basic" {
636636 \\}
637637 ;
638638
639 var ast = try Ast.parse(gpa, example, .zon);
639 var ast = try Ast.parse(gpa, example, .zon, .{});
640640 defer ast.deinit(gpa);
641641
642642 try testing.expect(ast.errors.len == 0);
......@@ -682,7 +682,7 @@ test "minimum_zig_version" {
682682 \\}
683683 ;
684684
685 var ast = try Ast.parse(gpa, example, .zon);
685 var ast = try Ast.parse(gpa, example, .zon, .{});
686686 defer ast.deinit(gpa);
687687
688688 try testing.expect(ast.errors.len == 0);
......@@ -717,7 +717,7 @@ test "minimum_zig_version - invalid version" {
717717 \\}
718718 ;
719719
720 var ast = try Ast.parse(gpa, example, .zon);
720 var ast = try Ast.parse(gpa, example, .zon, .{});
721721 defer ast.deinit(gpa);
722722
723723 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 {
188188 try astgen_input.writer.writeAll(rendered.written());
189189 try astgen_input.writer.writeByte(0);
190190 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, .{});
192192 defer astgen_tree.deinit(gpa);
193193 if (astgen_tree.errors.len != 0) {
194194 @panic("syntax errors occurred");
......@@ -407,7 +407,7 @@ fn parse(gpa: Allocator, io: Io, file_path: []const u8) !Ast {
407407 };
408408 errdefer gpa.free(source_code);
409409
410 var tree = try Ast.parse(gpa, source_code, .zig);
410 var tree = try Ast.parse(gpa, source_code, .zig, .{});
411411 errdefer tree.deinit(gpa);
412412
413413 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 {
428428 break :s source[0 .. source.len - 1 :0];
429429 };
430430
431 var ast = try Ast.parse(gpa, adjusted_source, .zig);
431 var ast = try Ast.parse(gpa, adjusted_source, .zig, .{});
432432 if (ast.errors.len > 0) {
433433 defer ast.deinit(gpa);
434434
......@@ -446,7 +446,7 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast {
446446 file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.written(),
447447 });
448448 }
449 return Ast.parse(gpa, "", .zig);
449 return Ast.parse(gpa, "", .zig, .{});
450450 }
451451 return ast;
452452}
......@@ -1085,7 +1085,7 @@ pub fn isPrimitiveNonType(name: []const u8) bool {
10851085//
10861086// // example test command:
10871087// // 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, .{});
10891089// defer ast.deinit(gpa);
10901090//
10911091// var w: Walk = .{
lib/std/zig.zig+3-2
......@@ -29,7 +29,6 @@ pub const primitives = @import("zig/primitives.zig");
2929pub const isPrimitive = primitives.isPrimitive;
3030pub const Ast = @import("zig/Ast.zig");
3131pub const AstGen = @import("zig/AstGen.zig");
32pub const AstSmith = @import("zig/AstSmith.zig");
3332pub const Zir = @import("zig/Zir.zig");
3433pub const Zoir = @import("zig/Zoir.zig");
3534pub const ZonGen = @import("zig/ZonGen.zig");
......@@ -43,6 +42,8 @@ pub const PkgConfig = @import("zig/PkgConfig.zig");
4342pub const target = @import("zig/target.zig");
4443pub const llvm = @import("zig/llvm.zig");
4544
45pub const parser_generated_oracle = @import("zig/parser_generated_oracle.zig");
46
4647// Character literal parsing
4748pub const ParsedCharLiteral = string_literal.ParsedCharLiteral;
4849pub const parseCharLiteral = string_literal.parseCharLiteral;
......@@ -1863,7 +1864,6 @@ fn readStreamAlloc(gpa: Allocator, io: Io, file: Io.File, limit: Io.Limit) ![]u8
18631864test {
18641865 _ = Ast;
18651866 _ = AstRlAnnotate;
1866 _ = AstSmith;
18671867 _ = BuiltinFn;
18681868 _ = Client;
18691869 _ = ErrorBundle;
......@@ -1879,4 +1879,5 @@ test {
18791879 _ = target;
18801880 _ = c_translation;
18811881 _ = llvm;
1882 _ = @import("zig/parser_fuzz.zig");
18821883}
lib/std/zig/Ast.zig+27-25
......@@ -139,10 +139,13 @@ pub fn deinit(tree: *Ast, gpa: Allocator) void {
139139}
140140
141141pub const Mode = enum { zig, zon };
142pub const ParseOptions = struct {
143 recover: bool = true,
144};
142145
143146/// Result should be freed with tree.deinit() when there are
144147/// no more references to any of the tokens or nodes.
145pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!Ast {
148pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode, options: ParseOptions) Allocator.Error!Ast {
146149 var tokens = Ast.TokenList{};
147150 defer tokens.deinit(gpa);
148151
......@@ -162,7 +165,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A
162165
163166 var tokens_slice = tokens.toOwnedSlice();
164167 errdefer tokens_slice.deinit(gpa);
165 return parseTokens(gpa, source, tokens_slice, mode);
168 return parseTokens(gpa, source, tokens_slice, mode, options);
166169}
167170
168171pub fn parseTokens(
......@@ -170,6 +173,7 @@ pub fn parseTokens(
170173 source: [:0]const u8,
171174 tokens: Ast.TokenList.Slice,
172175 mode: Mode,
176 options: ParseOptions,
173177) Allocator.Error!Ast {
174178 var parser: Parse = .{
175179 .source = source,
......@@ -180,6 +184,7 @@ pub fn parseTokens(
180184 .extra_data = .empty,
181185 .scratch = .empty,
182186 .tok_i = 0,
187 .recover = options.recover,
183188 };
184189 defer parser.errors.deinit(gpa);
185190 defer parser.nodes.deinit(gpa);
......@@ -465,15 +470,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void
465470 .extra_align_qualifier => {
466471 return w.writeAll("extra align qualifier");
467472 },
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 },
477473 .ptr_mod_on_array_child_type => {
478474 return w.print("pointer modifier '{s}' not allowed on array child type", .{
479475 tree.tokenTag(parse_error.token).symbol(),
......@@ -559,12 +555,6 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void
559555 .var_const_decl => {
560556 return w.writeAll("use 'var' or 'const' to declare variable");
561557 },
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 },
568558
569559 .invalid_byte => {
570560 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
21162106 .allowzero_token = null,
21172107 .const_token = null,
21182108 .volatile_token = null,
2109 .duplicate_token = null,
21192110 .ast = info,
21202111 };
21212112 // 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
21312122 const end = tree.firstToken(info.child_type);
21322123 while (i < end) : (i += 1) {
21332124 switch (tree.tokenTag(i)) {
2134 .keyword_allowzero => result.allowzero_token = i,
2135 .keyword_const => result.const_token = i,
2136 .keyword_volatile => result.volatile_token = i,
2125 .keyword_allowzero => {
2126 if (result.allowzero_token != null) {
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 },
21372143 .keyword_align => {
21382144 if (info.bit_range_end.unwrap()) |bit_range_end| {
21392145 assert(info.bit_range_start != .none);
......@@ -2730,6 +2736,7 @@ pub const full = struct {
27302736 allowzero_token: ?TokenIndex,
27312737 const_token: ?TokenIndex,
27322738 volatile_token: ?TokenIndex,
2739 duplicate_token: ?TokenIndex,
27332740 ast: Components,
27342741
27352742 pub const Components = struct {
......@@ -2863,9 +2870,6 @@ pub const Error = struct {
28632870 extern_fn_body,
28642871 extra_addrspace_qualifier,
28652872 extra_align_qualifier,
2866 extra_allowzero_qualifier,
2867 extra_const_qualifier,
2868 extra_volatile_qualifier,
28692873 ptr_mod_on_array_child_type,
28702874 invalid_bit_range,
28712875 same_line_doc_comment,
......@@ -2889,8 +2893,6 @@ pub const Error = struct {
28892893 expected_var_const,
28902894 wrong_equal_var_decl,
28912895 var_const_decl,
2892 extra_for_capture,
2893 for_input_not_captured,
28942896
28952897 zig_style_container,
28962898 previous_field,
lib/std/zig/AstGen.zig+10
......@@ -3746,6 +3746,9 @@ fn ptrType(
37463746 if (ptr_info.size == .c and ptr_info.allowzero_token != null) {
37473747 return gz.astgen.failTok(ptr_info.allowzero_token.?, "C pointers always allow address zero", .{});
37483748 }
3749 if (ptr_info.duplicate_token) |duplicate| {
3750 return gz.astgen.failTok(duplicate, "Extra pointer qualifier", .{});
3751 }
37493752
37503753 const source_offset = gz.astgen.source_offset;
37513754 const source_line = gz.astgen.source_line;
......@@ -6709,6 +6712,9 @@ fn forExpr(
67096712 for (for_full.ast.inputs, indexables, lens) |input, *indexable_ref, *len_refs| {
67106713 const capture_is_ref = tree.tokenTag(capture_token) == .asterisk;
67116714 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 }
67126718 const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_");
67136719
67146720 if (is_discard and capture_is_ref) {
......@@ -6751,6 +6757,10 @@ fn forExpr(
67516757 len_refs.* = .{ indexable, .none };
67526758 }
67536759 }
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 }
67546764 }
67556765
67566766 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
5const std = @import("../std.zig");
6const assert = std.debug.assert;
7const Token = std.zig.Token;
8const Smith = std.testing.Smith;
9const Weight = Smith.Weight;
10const AstSmith = @This();
11
12smith: *Smith,
13
14source_buf: [16384]u8,
15source_len: usize,
16
17token_tag_buf: [2048]Token.Tag,
18token_start_buf: [2048]std.zig.Ast.ByteOffset,
19tokens_len: usize,
20
21not_token: ?Token.Tag,
22not_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
34not_expr_suffix: bool,
35/// LabelableExpr
36/// <- Block
37/// / SwitchExpr
38/// / LoopExpr
39not_labelable_expr: ?enum { colon, expr },
40not_label: bool,
41not_break_label: bool,
42not_block_expr: bool,
43not_expr_statement: bool,
44
45prev_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
49prev_ids_len: usize,
50
51/// `generate` must be called on the returned value before any other methods
52pub 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
77pub 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.
82pub 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
94pub const Error = error{ OutOfMemory, SkipZigTest };
95const SourceError = error{SkipZigTest};
96
97pub 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
104pub 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
115inline 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
123inline fn smithListItemEos(a: *AstSmith) bool {
124 return a.smith.eosWeightedSimple(1, 63);
125}
126
127fn sourceCapacity(a: *AstSmith) []u8 {
128 return a.source_buf[a.source_len..];
129}
130
131fn sourceCapacityLen(a: *AstSmith) usize {
132 return a.source_buf.len - a.source_len;
133}
134
135fn ensureSourceCapacity(a: *AstSmith, n: usize) SourceError!void {
136 if (a.sourceCapacityLen() < n) return error.SkipZigTest;
137}
138
139fn addSourceByte(a: *AstSmith, byte: u8) SourceError!void {
140 try a.ensureSourceCapacity(1);
141 a.addSourceByteAssumeCapacity(byte);
142}
143
144fn addSourceByteAssumeCapacity(a: *AstSmith, byte: u8) void {
145 a.sourceCapacity()[0] = byte;
146 a.source_len += 1;
147}
148
149fn addSource(a: *AstSmith, bytes: []const u8) SourceError!void {
150 try a.ensureSourceCapacity(bytes.len);
151 a.addSourceAssumeCapacity(bytes);
152}
153
154fn addSourceAssumeCapacity(a: *AstSmith, bytes: []const u8) void {
155 @memcpy(a.sourceCapacity()[0..bytes.len], bytes);
156 a.source_len += bytes.len;
157}
158
159fn addSourceAsSlice(a: *AstSmith, len: usize) SourceError![]u8 {
160 try a.ensureSourceCapacity(len);
161 return a.addSourceAsSliceAssumeCapacity(len);
162}
163
164fn addSourceAsSliceAssumeCapacity(a: *AstSmith, len: usize) []u8 {
165 const slice = a.sourceCapacity()[0..len];
166 a.source_len += len;
167 return slice;
168}
169
170fn tokenCapacityLen(a: *AstSmith) usize {
171 return a.token_tag_buf.len - a.tokens_len;
172}
173
174fn ensureTokenCapacity(a: *AstSmith, n: usize) SourceError!void {
175 if (a.tokenCapacityLen() < n) return error.SkipZigTest;
176}
177
178fn 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
189fn 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
196fn 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)
236fn 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`
270fn 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
287fn 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*)
294fn 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
316fn 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
331fn 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
342fn 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
352fn 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
393fn 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?
422fn 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
445fn 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)?
456fn 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
484fn 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
524fn 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 )
567fn 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)
590fn 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)
602fn 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 )
616fn 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 )
638fn 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
663fn 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
674fn 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
682fn 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)?
703fn 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)?
721fn 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
730const pegExpr = pegBoolOrExpr;
731
732/// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
733fn 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)*
742fn 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)?
751fn 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)*
760fn 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)*
769fn 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)*
778fn 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)*
787fn 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
796fn 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
815fn 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
903fn 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
923fn 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)
932fn 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
945fn 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
958fn 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?
978fn 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
989fn 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
1013fn 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)?
1021fn 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)*
1031fn 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
1061fn 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
1160fn 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
1170fn 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
1178fn 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
1185fn 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
1208fn 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)
1239fn 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
1252fn 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
1265fn 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
1285fn 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
1297fn 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?
1311fn 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
1320fn 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?
1336fn 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
1345fn 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
1356fn pegAsmClobbers(a: *AstSmith) SourceError!void {
1357 try a.pegToken(.colon);
1358 try a.pegExpr();
1359}
1360
1361/// BreakLabel <- COLON IDENTIFIER
1362fn pegBreakLabel(a: *AstSmith) SourceError!void {
1363 try a.pegToken(.colon);
1364 try a.pegIdentifier();
1365}
1366
1367/// BlockLabel <- IDENTIFIER COLON
1368fn pegBlockLabel(a: *AstSmith) SourceError!void {
1369 try a.pegIdentifier();
1370 try a.pegToken(.colon);
1371}
1372
1373/// FieldInit <- DOT IDENTIFIER EQUAL Expr
1374fn 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
1382fn 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
1390fn 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
1398fn 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
1406fn 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
1416fn 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
1436fn 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?
1445fn 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?
1454fn 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.
1473fn 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
1482fn 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
1489fn 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
1499fn 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
1513fn 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
1535fn 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
1550fn 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)?
1566fn 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?
1575fn 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?)?
1590fn 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
1616fn 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
1647fn 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?
1665fn 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
1684fn 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
1701fn 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
1721fn 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
1741fn 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
1761fn 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
1814fn 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
1845fn 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
1852fn 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
1862fn pegSinglePtrTypeStart(a: *AstSmith) SourceError!void {
1863 try a.pegToken(.asterisk);
1864}
1865
1866/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
1867fn 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
1886fn 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
1898fn 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)?
1910fn 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
1951fn 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
1959fn 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)?
1973fn 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?
1986fn 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?
1997fn 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?
2008fn 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?)?
2019fn 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?
2040fn 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)+
2051fn 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?
2061fn 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)+
2070fn 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*
2083fn pegLineComment(a: *AstSmith) SourceError!void {
2084 return a.pegGenericLine("//", .line_comment);
2085}
2086
2087/// line_string <- '\\\\' non_control_utf8* [ \n]*
2088fn 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.
2097fn 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)*
2137fn 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
2165const bin_weights: []const Weight = &.{.rangeAtMost(u8, '0', '1', 1)};
2166const oct_weights: []const Weight = &.{.rangeAtMost(u8, '0', '7', 1)};
2167const dec_weights: []const Weight = &.{.rangeAtMost(u8, '0', '9', 1)};
2168const 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`
2175fn 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
2212fn 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
2268fn 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
2281fn 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
2337fn 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.
2355fn 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
2364fn 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)+
2373fn 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
2385const 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
2395fn 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
2451fn 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
2477test AstSmith {
2478 try std.testing.fuzz({}, checkGenerated, .{});
2479}
2480
2481fn 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
2510fn 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
2517fn 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
2556pub 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
2563fn 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 @@
11//! Represents in-progress parsing, will be converted to an Ast after completion.
22
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
316pub const Error = error{ParseError} || Allocator.Error;
417
518gpa: Allocator,
......@@ -10,6 +23,7 @@ errors: std.ArrayList(AstError),
1023nodes: Ast.NodeList,
1124extra_data: std.ArrayList(u32),
1225scratch: std.ArrayList(Node.Index),
26recover: bool,
1327
1428fn tokenTag(p: *const Parse, token_index: TokenIndex) Token.Tag {
1529 return p.tokens.items(.tag)[token_index];
......@@ -108,7 +122,7 @@ fn addExtra(p: *Parse, extra: anytype) Allocator.Error!ExtraIndex {
108122 return result;
109123}
110124
111fn warnExpected(p: *Parse, expected_token: Token.Tag) error{OutOfMemory}!void {
125fn warnExpected(p: *Parse, expected_token: Token.Tag) Error!void {
112126 @branchHint(.cold);
113127 try p.warnMsg(.{
114128 .tag = .expected_token,
......@@ -117,12 +131,12 @@ fn warnExpected(p: *Parse, expected_token: Token.Tag) error{OutOfMemory}!void {
117131 });
118132}
119133
120fn warn(p: *Parse, error_tag: AstError.Tag) error{OutOfMemory}!void {
134fn warn(p: *Parse, error_tag: AstError.Tag) Error!void {
121135 @branchHint(.cold);
122136 try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i });
123137}
124138
125fn warnMsg(p: *Parse, msg: Ast.Error) error{OutOfMemory}!void {
139fn warnMsg(p: *Parse, msg: Ast.Error) Error!void {
126140 @branchHint(.cold);
127141 switch (msg.tag) {
128142 .expected_semi_after_decl,
......@@ -161,11 +175,13 @@ fn warnMsg(p: *Parse, msg: Ast.Error) error{OutOfMemory}!void {
161175 var copy = msg;
162176 copy.token_is_prev = true;
163177 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);
165181 },
166 else => {},
182 else => try p.errors.append(p.gpa, msg),
167183 }
168 try p.errors.append(p.gpa, msg);
184 if (!p.recover) return error.ParseError;
169185}
170186
171187fn fail(p: *Parse, tag: Ast.Error.Tag) error{ ParseError, OutOfMemory } {
......@@ -189,17 +205,29 @@ fn failMsg(p: *Parse, msg: Ast.Error) error{ ParseError, OutOfMemory } {
189205}
190206
191207/// Root <- skip ContainerMembers eof
192pub fn parseRoot(p: *Parse) !void {
208pub fn parseRoot(p: *Parse) Allocator.Error!void {
193209 // Root node must be index 0.
194210 p.nodes.appendAssumeCapacity(.{
195211 .tag = .root,
196212 .main_token = 0,
197213 .data = undefined,
198214 });
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 };
200222 const root_decls = try root_members.toSpan(p);
201223 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 };
203231 }
204232 p.nodes.items(.data)[0] = .{ .extra_range = root_decls };
205233}
......@@ -207,7 +235,7 @@ pub fn parseRoot(p: *Parse) !void {
207235/// Parse in ZON mode. Subset of the language.
208236/// TODO: set a flag in Parse struct, and honor that flag
209237/// by emitting compilation errors when non-zon nodes are encountered.
210pub fn parseZon(p: *Parse) !void {
238pub fn parseZon(p: *Parse) Allocator.Error!void {
211239 // We must use index 0 so that 0 can be used as null elsewhere.
212240 p.nodes.appendAssumeCapacity(.{
213241 .tag = .root,
......@@ -222,7 +250,13 @@ pub fn parseZon(p: *Parse) !void {
222250 else => |e| return e,
223251 };
224252 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 };
226260 }
227261 p.nodes.items(.data)[0] = .{ .node = node_index };
228262}
......@@ -232,7 +266,7 @@ pub fn parseZon(p: *Parse) !void {
232266/// ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl
233267///
234268/// ComptimeDecl <- KEYWORD_comptime Block
235fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
269fn parseContainerMembers(p: *Parse) Error!Members {
236270 const scratch_top = p.scratch.items.len;
237271 defer p.scratch.shrinkRetainingCapacity(scratch_top);
238272
......@@ -300,13 +334,6 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
300334 else => {
301335 const identifier = p.tok_i;
302336 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 };
310337 switch (field_state) {
311338 .none => field_state = .seen,
312339 .err, .seen => {},
......@@ -329,6 +356,13 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
329356 field_state = .err;
330357 },
331358 }
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 };
332366 try p.scratch.append(p.gpa, container_field);
333367 switch (p.tokenTag(p.tok_i)) {
334368 .comma => {
......@@ -405,13 +439,6 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
405439
406440 const identifier = p.tok_i;
407441 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 };
415442 switch (field_state) {
416443 .none => field_state = .seen,
417444 .err, .seen => {},
......@@ -434,6 +461,13 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
434461 field_state = .err;
435462 },
436463 }
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 };
437471 try p.scratch.append(p.gpa, container_field);
438472 switch (p.tokenTag(p.tok_i)) {
439473 .comma => {
......@@ -484,6 +518,12 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
484518
485519/// Attempts to find next container member by searching for certain tokens
486520fn 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 }
487527 var level: u32 = 0;
488528 while (true) {
489529 const tok = p.nextToken();
......@@ -541,6 +581,12 @@ fn findNextContainerMember(p: *Parse) void {
541581
542582/// Attempts to find the next statement by searching for a semicolon
543583fn 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 }
544590 var level: u32 = 0;
545591 while (true) {
546592 const tok = p.nextToken();
......@@ -864,7 +910,7 @@ fn parseGlobalVarDecl(p: *Parse) !?Node.Index {
864910 return var_decl;
865911}
866912
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)?
868914fn expectContainerField(p: *Parse) !Node.Index {
869915 _ = p.eatToken(.keyword_comptime);
870916 const main_token = p.tok_i;
......@@ -910,18 +956,21 @@ fn expectContainerField(p: *Parse) !Node.Index {
910956/// <- Statement
911957/// / KEYWORD_defer BlockExprStatement
912958/// / KEYWORD_errdefer BlockExprStatement
913/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
959/// / !StatementPrefix KEYWORD_comptime? VarAssignStatement
914960///
915961/// Statement
916/// <- ExprStatement
917/// / KEYWORD_suspend BlockExprStatement
918/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON
919///
920/// ExprStatement
921962/// <- IfStatement
922963/// / LabeledStatement
923964/// / KEYWORD_nosuspend BlockExprStatement
924965/// / 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
925974fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
926975 if (p.eatToken(.keyword_comptime)) |comptime_token| {
927976 const opt_block_expr = try p.parseBlockExpr();
......@@ -934,7 +983,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
934983 }
935984
936985 if (is_block_level) {
937 return p.expectVarDeclExprStatement(comptime_token);
986 return p.expectVarAssignStatement(comptime_token);
938987 } else {
939988 const assign = try p.expectAssignExpr();
940989 try p.expectSemicolon(.expected_semi_after_stmt, true);
......@@ -995,7 +1044,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
9951044 if (try p.parseLabeledStatement()) |labeled_statement| return labeled_statement;
9961045
9971046 if (is_block_level) {
998 return p.expectVarDeclExprStatement(null);
1047 return p.expectVarAssignStatement(null);
9991048 } else {
10001049 const assign = try p.expectAssignExpr();
10011050 try p.expectSemicolon(.expected_semi_after_stmt, true);
......@@ -1003,30 +1052,8 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
10031052 }
10041053}
10051054
1006/// ComptimeStatement
1007/// <- BlockExpr
1008/// / VarDeclExprStatement
1009fn 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///
10281055/// VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON
1029fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index {
1056fn expectVarAssignStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Index {
10301057 const scratch_top = p.scratch.items.len;
10311058 defer p.scratch.shrinkRetainingCapacity(scratch_top);
10321059
......@@ -1138,7 +1165,7 @@ fn expectVarDeclExprStatement(p: *Parse, comptime_token: ?TokenIndex) !Node.Inde
11381165
11391166/// If a parse error occurs, reports an error, but then finds the next statement
11401167/// and returns that one instead. If a parse error occurs but there is no following
1141/// statement, returns 0.
1168/// statement, returns null.
11421169fn expectStatementRecoverable(p: *Parse) Error!?Node.Index {
11431170 while (true) {
11441171 return p.expectStatement(true) catch |err| switch (err) {
......@@ -1156,8 +1183,10 @@ fn expectStatementRecoverable(p: *Parse) Error!?Node.Index {
11561183}
11571184
11581185/// IfStatement
1159/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
1160/// / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
1186/// <- IfPrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else)
1187/// / IfPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement)
1188///
1189/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
11611190fn expectIfStatement(p: *Parse) !Node.Index {
11621191 const if_token = p.assertToken(.keyword_if);
11631192 _ = try p.expectToken(.l_paren);
......@@ -1226,13 +1255,17 @@ fn parseLabeledStatement(p: *Parse) !?Node.Index {
12261255 const label_token = opt_label_token orelse return null;
12271256
12281257 const after_colon = p.tok_i;
1229 if (try p.parseTypeExpr()) |_| {
1230 const a = try p.parseByteAlign();
1231 const b = try p.parseAddrSpace();
1232 const c = try p.parseLinkSection();
1233 const d = if (p.eatToken(.equal) == null) null else try p.expectExpr();
1234 if (a != null or b != null or c != null or d != null) {
1235 return p.failMsg(.{ .tag = .expected_var_const, .token = label_token });
1258 // Don't bother trying to give a better error message if recovery is disabled.
1259 // This avoids a possible stack overflow in e.g. parseTypeExpr() when fuzzing.
1260 if (p.recover) {
1261 if (try p.parseTypeExpr()) |_| {
1262 const a = try p.parseByteAlign();
1263 const b = try p.parseAddrSpace();
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 }
12361269 }
12371270 }
12381271 return p.failMsg(.{ .tag = .expected_labelable, .token = after_colon });
......@@ -1252,8 +1285,8 @@ fn parseLoopStatement(p: *Parse) !?Node.Index {
12521285}
12531286
12541287/// ForStatement
1255/// <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )
1256/// / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement )
1288/// <- ForPrefix BlockExpr (KEYWORD_else Statement / !KEYWORD_else)
1289/// / ForPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Statement)
12571290fn parseForStatement(p: *Parse) !?Node.Index {
12581291 const for_token = p.eatToken(.keyword_for) orelse return null;
12591292
......@@ -1309,8 +1342,8 @@ fn parseForStatement(p: *Parse) !?Node.Index {
13091342/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
13101343///
13111344/// WhileStatement
1312/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
1313/// / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
1345/// <- WhilePrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else)
1346/// / WhilePrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement)
13141347fn parseWhileStatement(p: *Parse) !?Node.Index {
13151348 const while_token = p.eatToken(.keyword_while) orelse return null;
13161349 _ = try p.expectToken(.l_paren);
......@@ -1400,7 +1433,7 @@ fn parseWhileStatement(p: *Parse) !?Node.Index {
14001433
14011434/// BlockExprStatement
14021435/// <- BlockExpr
1403/// / !BlockExpr AssignExpr SEMICOLON
1436/// / !BlockExprPrefix AssignExpr SEMICOLON
14041437fn parseBlockExprStatement(p: *Parse) !?Node.Index {
14051438 const block_expr = try p.parseBlockExpr();
14061439 if (block_expr) |expr| return expr;
......@@ -1434,7 +1467,7 @@ fn parseBlockExpr(p: *Parse) Error!?Node.Index {
14341467 }
14351468}
14361469
1437/// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)?
1470/// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA)
14381471///
14391472/// AssignOp
14401473/// <- ASTERISKEQUAL
......@@ -1460,7 +1493,7 @@ fn parseAssignExpr(p: *Parse) !?Node.Index {
14601493 return try p.finishAssignExpr(expr);
14611494}
14621495
1463/// SingleAssignExpr <- Expr (AssignOp Expr)?
1496/// SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp)
14641497fn parseSingleAssignExpr(p: *Parse) !?Node.Index {
14651498 const lhs = try p.parseExpr() orelse return null;
14661499 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 {
16341667 if (tok_tag == .keyword_catch) {
16351668 _ = try p.parsePayload();
16361669 }
1637 const rhs = try p.parseExprPrecedence(info.prec + 1) orelse {
1638 try p.warn(.expected_expr);
1639 return node;
1640 };
16411670
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.
16421675 {
16431676 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 }
16441681 const char_before = p.source[p.tokenStart(oper_token) - 1];
16451682 const char_after = p.source[p.tokenStart(oper_token) + tok_len];
16461683 if (tok_tag == .ampersand and char_after == '&') {
......@@ -1652,6 +1689,11 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index {
16521689 }
16531690 }
16541691
1692 const rhs = try p.parseExprPrecedence(info.prec + 1) orelse {
1693 try p.warn(.expected_expr);
1694 return node;
1695 };
1696
16551697 node = try p.addNode(.{
16561698 .tag = info.tag,
16571699 .main_token = oper_token,
......@@ -1666,7 +1708,7 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index {
16661708 return node;
16671709}
16681710
1669/// PrefixExpr <- PrefixOp* PrimaryExpr
1711/// PrefixExpr <- PrefixOp* PrimaryExpr / !PrefixOp
16701712///
16711713/// PrefixOp
16721714/// <- EXCLAMATIONMARK
......@@ -1696,25 +1738,28 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index {
16961738 return try p.parsePrefixExpr() orelse return p.fail(.expected_prefix_expr);
16971739}
16981740
1699/// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
1741/// TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr
17001742///
17011743/// PrefixTypeOp
17021744/// <- QUESTIONMARK
17031745/// / KEYWORD_anyframe MINUSRARROW
1704/// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
1705/// / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
1706/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
1746/// / (ManyPtrTypeStart / SliceTypeStart) PtrMods
1747/// / SinglePtrTypeStart SinglePtrMods
17071748/// / ArrayTypeStart
17081749///
1750/// PrefixTypeOpPrefix
1751/// <- QUESTIONMARK
1752/// / KEYWORD_anyframe MINUSRARROW
1753/// / LBRACKET
1754/// / ASTERISK
1755///
17091756/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
17101757///
17111758/// SinglePtrTypeStart <- ASTERISK
17121759///
17131760/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
17141761///
1715/// ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET
1716///
1717/// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
1762/// ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET
17181763fn parseTypeExpr(p: *Parse) Error!?Node.Index {
17191764 switch (p.tokenTag(p.tok_i)) {
17201765 .question_mark => return try p.addNode(.{
......@@ -1735,7 +1780,7 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index {
17351780 },
17361781 .asterisk => {
17371782 const asterisk = p.nextToken();
1738 const mods = try p.parsePtrModifiers();
1783 const mods = try p.parsePtrModifiers(.bit_align);
17391784 const elem_type = try p.expectTypeExpr();
17401785 if (mods.bit_range_start != .none) {
17411786 return try p.addNode(.{
......@@ -1790,14 +1835,8 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index {
17901835 sentinel = try p.expectExpr();
17911836 }
17921837 _ = try p.expectToken(.r_bracket);
1793 const mods = try p.parsePtrModifiers();
1838 const mods = try p.parsePtrModifiers(.byte_align);
17941839 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 }
18011840 if (sentinel == null and mods.addrspace_node == .none) {
18021841 return try p.addNode(.{
18031842 .tag = .ptr_type_aligned,
......@@ -1840,14 +1879,8 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index {
18401879 null;
18411880 _ = try p.expectToken(.r_bracket);
18421881 if (len_expr == null) {
1843 const mods = try p.parsePtrModifiers();
1882 const mods = try p.parsePtrModifiers(.byte_align);
18441883 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 }
18511884 if (sentinel == null and mods.addrspace_node == .none) {
18521885 return try p.addNode(.{
18531886 .tag = .ptr_type_aligned,
......@@ -1927,19 +1960,19 @@ fn expectTypeExpr(p: *Parse) Error!Node.Index {
19271960/// PrimaryExpr
19281961/// <- AsmExpr
19291962/// / IfExpr
1930/// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
1931/// / KEYWORD_comptime Expr !ExprSuffix
1932/// / KEYWORD_nosuspend Expr !ExprSuffix
1933/// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
1934/// / KEYWORD_resume Expr !ExprSuffix
1935/// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart)
1963/// / KEYWORD_break BreakLabel? Expr?
1964/// / KEYWORD_comptime Expr
1965/// / KEYWORD_nosuspend Expr
1966/// / KEYWORD_continue BreakLabel? Expr?
1967/// / KEYWORD_resume Expr
1968/// / KEYWORD_return Expr?
19361969/// / BlockLabel? LoopExpr
19371970/// / Block
19381971/// / CurlySuffixExpr
19391972fn parsePrimaryExpr(p: *Parse) !?Node.Index {
19401973 switch (p.tokenTag(p.tok_i)) {
19411974 .keyword_asm => return try p.expectAsmExpr(),
1942 .keyword_if => return try p.parseIfExpr(),
1975 .keyword_if => return try p.expectIf(expectExpr),
19431976 .keyword_break => {
19441977 return try p.addNode(.{
19451978 .tag = .@"break",
......@@ -1994,18 +2027,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {
19942027 .keyword_inline => {
19952028 p.tok_i += 3;
19962029 switch (p.tokenTag(p.tok_i)) {
1997 .keyword_for => return try p.parseFor(expectExpr),
1998 .keyword_while => return try p.parseWhileExpr(),
2030 .keyword_for => return try p.expectFor(expectExpr),
2031 .keyword_while => return try p.expectWhileExpr(),
19992032 else => return p.fail(.expected_inlinable),
20002033 }
20012034 },
20022035 .keyword_for => {
20032036 p.tok_i += 2;
2004 return try p.parseFor(expectExpr);
2037 return try p.expectFor(expectExpr);
20052038 },
20062039 .keyword_while => {
20072040 p.tok_i += 2;
2008 return try p.parseWhileExpr();
2041 return try p.expectWhileExpr();
20092042 },
20102043 else => return try p.parseCurlySuffixExpr(),
20112044 }
......@@ -2016,23 +2049,18 @@ fn parsePrimaryExpr(p: *Parse) !?Node.Index {
20162049 .keyword_inline => {
20172050 p.tok_i += 1;
20182051 switch (p.tokenTag(p.tok_i)) {
2019 .keyword_for => return try p.parseFor(expectExpr),
2020 .keyword_while => return try p.parseWhileExpr(),
2052 .keyword_for => return try p.expectFor(expectExpr),
2053 .keyword_while => return try p.expectWhileExpr(),
20212054 else => return p.fail(.expected_inlinable),
20222055 }
20232056 },
2024 .keyword_for => return try p.parseFor(expectExpr),
2025 .keyword_while => return try p.parseWhileExpr(),
2057 .keyword_for => return try p.expectFor(expectExpr),
2058 .keyword_while => return try p.expectWhileExpr(),
20262059 .l_brace => return try p.parseBlock(),
20272060 else => return try p.parseCurlySuffixExpr(),
20282061 }
20292062}
20302063
2031/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
2032fn parseIfExpr(p: *Parse) !?Node.Index {
2033 return try p.parseIf(expectExpr);
2034}
2035
20362064/// Block <- LBRACE BlockStatement* RBRACE
20372065fn parseBlock(p: *Parse) !?Node.Index {
20382066 const lbrace = p.eatToken(.l_brace) orelse return null;
......@@ -2106,16 +2134,9 @@ fn forPrefix(p: *Parse) Error!usize {
21062134 return inputs;
21072135 };
21082136
2109 var warned_excess = false;
2110 var captures: u32 = 0;
21112137 while (true) {
21122138 _ = p.eatToken(.asterisk);
2113 const identifier = 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 }
2139 _ = try p.expectToken(.identifier);
21192140 switch (p.tokenTag(p.tok_i)) {
21202141 .comma => p.tok_i += 1,
21212142 .pipe => {
......@@ -2128,19 +2149,14 @@ fn forPrefix(p: *Parse) Error!usize {
21282149 if (p.eatToken(.pipe)) |_| break;
21292150 }
21302151
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 }
21362152 return inputs;
21372153}
21382154
21392155/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
21402156///
21412157/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffi
2142fn parseWhileExpr(p: *Parse) !?Node.Index {
2143 const while_token = p.eatToken(.keyword_while) orelse return null;
2158fn expectWhileExpr(p: *Parse) !Node.Index {
2159 const while_token = p.assertToken(.keyword_while);
21442160 _ = try p.expectToken(.l_paren);
21452161 const condition = try p.expectExpr();
21462162 _ = try p.expectToken(.r_paren);
......@@ -2188,7 +2204,7 @@ fn parseWhileExpr(p: *Parse) !?Node.Index {
21882204 });
21892205}
21902206
2191/// CurlySuffixExpr <- TypeExpr InitList?
2207/// CurlySuffixExpr <- TypeExpr (InitList / !LBRACE)
21922208///
21932209/// InitList
21942210/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
......@@ -2290,7 +2306,7 @@ fn parseCurlySuffixExpr(p: *Parse) !?Node.Index {
22902306 }
22912307}
22922308
2293/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
2309/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK)
22942310fn parseErrorUnionExpr(p: *Parse) !?Node.Index {
22952311 const suffix_expr = try p.parseSuffixExpr() orelse return null;
22962312 const bang = p.eatToken(.bang) orelse return suffix_expr;
......@@ -2304,59 +2320,13 @@ fn parseErrorUnionExpr(p: *Parse) !?Node.Index {
23042320 });
23052321}
23062322
2307/// SuffixExpr
2308/// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
2309///
2310/// FnCallArguments <- LPAREN ExprList RPAREN
2311///
2312/// ExprList <- (Expr COMMA)* Expr?
2323/// SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix
23132324fn parseSuffixExpr(p: *Parse) !?Node.Index {
23142325 var res = try p.parsePrimaryTypeExpr() orelse return null;
2315 while (true) {
2316 const opt_suffix_op = try p.parseSuffixOp(res);
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 };
2326 while (try p.parseSuffixOp(res)) |suffix_op| {
2327 res = suffix_op;
23592328 }
2329 return res;
23602330}
23612331
23622332/// PrimaryTypeExpr
......@@ -2366,17 +2336,16 @@ fn parseSuffixExpr(p: *Parse) !?Node.Index {
23662336/// / DOT IDENTIFIER
23672337/// / DOT InitList
23682338/// / ErrorSetDecl
2369/// / FLOAT
23702339/// / FnProto
23712340/// / GroupedExpr
23722341/// / LabeledTypeExpr
2373/// / IDENTIFIER !(COLON LabelableExpr)
2342/// / IDENTIFIER
23742343/// / IfTypeExpr
2375/// / INTEGER
2376/// / KEYWORD_comptime TypeExpr !ExprSuffix
2344/// / KEYWORD_comptime TypeExpr
23772345/// / KEYWORD_error DOT IDENTIFIER
23782346/// / KEYWORD_anyframe
23792347/// / KEYWORD_unreachable
2348/// / NUMBERLITERAL
23802349/// / STRINGLITERAL
23812350///
23822351/// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
......@@ -2431,23 +2400,23 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
24312400 });
24322401 },
24332402
2434 .builtin => return try p.parseBuiltinCall(),
2435 .keyword_fn => return try p.parseFnProto(),
2436 .keyword_if => return try p.parseIf(expectTypeExpr),
2403 .builtin => return try p.expectBuiltinCall(),
2404 .keyword_fn => return (try p.parseFnProto()).?,
2405 .keyword_if => return try p.expectIf(expectTypeExpr),
24372406 .keyword_switch => return try p.expectSwitchExpr(false),
24382407
24392408 .keyword_extern,
24402409 .keyword_packed,
24412410 => {
24422411 p.tok_i += 1;
2443 return try p.parseContainerDeclAuto();
2412 return try p.expectContainerDeclAuto();
24442413 },
24452414
24462415 .keyword_struct,
24472416 .keyword_opaque,
24482417 .keyword_enum,
24492418 .keyword_union,
2450 => return try p.parseContainerDeclAuto(),
2419 => return try p.expectContainerDeclAuto(),
24512420
24522421 .keyword_comptime => return try p.addNode(.{
24532422 .tag = .@"comptime",
......@@ -2473,18 +2442,18 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
24732442 .keyword_inline => {
24742443 p.tok_i += 3;
24752444 switch (p.tokenTag(p.tok_i)) {
2476 .keyword_for => return try p.parseFor(expectTypeExpr),
2477 .keyword_while => return try p.parseWhileTypeExpr(),
2445 .keyword_for => return try p.expectFor(expectTypeExpr),
2446 .keyword_while => return try p.expectWhileTypeExpr(),
24782447 else => return p.fail(.expected_inlinable),
24792448 }
24802449 },
24812450 .keyword_for => {
24822451 p.tok_i += 2;
2483 return try p.parseFor(expectTypeExpr);
2452 return try p.expectFor(expectTypeExpr);
24842453 },
24852454 .keyword_while => {
24862455 p.tok_i += 2;
2487 return try p.parseWhileTypeExpr();
2456 return try p.expectWhileTypeExpr();
24882457 },
24892458 .keyword_switch => {
24902459 p.tok_i += 2;
......@@ -2492,7 +2461,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
24922461 },
24932462 .l_brace => {
24942463 p.tok_i += 2;
2495 return try p.parseBlock();
2464 return (try p.parseBlock()).?;
24962465 },
24972466 else => return try p.addNode(.{
24982467 .tag = .identifier,
......@@ -2509,13 +2478,13 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
25092478 .keyword_inline => {
25102479 p.tok_i += 1;
25112480 switch (p.tokenTag(p.tok_i)) {
2512 .keyword_for => return try p.parseFor(expectTypeExpr),
2513 .keyword_while => return try p.parseWhileTypeExpr(),
2481 .keyword_for => return try p.expectFor(expectTypeExpr),
2482 .keyword_while => return try p.expectWhileTypeExpr(),
25142483 else => return p.fail(.expected_inlinable),
25152484 }
25162485 },
2517 .keyword_for => return try p.parseFor(expectTypeExpr),
2518 .keyword_while => return try p.parseWhileTypeExpr(),
2486 .keyword_for => return try p.expectFor(expectTypeExpr),
2487 .keyword_while => return try p.expectWhileTypeExpr(),
25192488 .period => switch (p.tokenTag(p.tok_i + 1)) {
25202489 .identifier => {
25212490 p.tok_i += 1;
......@@ -2643,10 +2612,8 @@ fn parsePrimaryTypeExpr(p: *Parse) !?Node.Index {
26432612 },
26442613 else => {
26452614 const main_token = p.nextToken();
2646 const period = p.eatToken(.period);
2647 if (period == null) return p.failExpected(.period);
2648 const identifier = p.eatToken(.identifier);
2649 if (identifier == null) return p.failExpected(.identifier);
2615 _ = try p.expectToken(.period);
2616 _ = try p.expectToken(.identifier);
26502617 return try p.addNode(.{
26512618 .tag = .error_value,
26522619 .main_token = main_token,
......@@ -2672,9 +2639,9 @@ fn expectPrimaryTypeExpr(p: *Parse) !Node.Index {
26722639
26732640/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
26742641///
2675/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
2676fn parseWhileTypeExpr(p: *Parse) !?Node.Index {
2677 const while_token = p.eatToken(.keyword_while) orelse return null;
2642/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
2643fn expectWhileTypeExpr(p: *Parse) !Node.Index {
2644 const while_token = p.assertToken(.keyword_while);
26782645 _ = try p.expectToken(.l_paren);
26792646 const condition = try p.expectExpr();
26802647 _ = try p.expectToken(.r_paren);
......@@ -3076,16 +3043,29 @@ const PtrModifiers = struct {
30763043 bit_range_end: Node.OptionalIndex,
30773044};
30783045
3079fn 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
3062fn parsePtrModifiers(p: *Parse, align_type: enum { bit_align, byte_align }) !PtrModifiers {
30803063 var result: PtrModifiers = .{
30813064 .align_node = .none,
30823065 .addrspace_node = .none,
30833066 .bit_range_start = .none,
30843067 .bit_range_end = .none,
30853068 };
3086 var saw_const = false;
3087 var saw_volatile = false;
3088 var saw_allowzero = false;
30893069 while (true) {
30903070 switch (p.tokenTag(p.tok_i)) {
30913071 .keyword_align => {
......@@ -3096,7 +3076,10 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers {
30963076 _ = try p.expectToken(.l_paren);
30973077 result.align_node = (try p.expectExpr()).toOptional();
30983078
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 }
31003083 result.bit_range_start = (try p.expectExpr()).toOptional();
31013084 _ = try p.expectToken(.colon);
31023085 result.bit_range_end = (try p.expectExpr()).toOptional();
......@@ -3104,33 +3087,16 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers {
31043087
31053088 _ = try p.expectToken(.r_paren);
31063089 },
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 },
31283090 .keyword_addrspace => {
31293091 if (result.addrspace_node != .none) {
31303092 try p.warn(.extra_addrspace_qualifier);
31313093 }
31323094 result.addrspace_node = .fromOptional(try p.parseAddrSpace());
31333095 },
3096 .keyword_allowzero,
3097 .keyword_const,
3098 .keyword_volatile,
3099 => p.tok_i += 1,
31343100 else => return result,
31353101 }
31363102 }
......@@ -3140,7 +3106,12 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers {
31403106/// <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET
31413107/// / DOT IDENTIFIER
31423108/// / DOTASTERISK
3143/// / DOTQUESTIONMARK
3109/// / DOT QUESTIONMARK
3110/// / FnCallArguments
3111///
3112/// FnCallArguments <- LPAREN ExprList RPAREN
3113///
3114/// ExprList <- (Expr COMMA)* Expr?
31443115fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
31453116 switch (p.tokenTag(p.tok_i)) {
31463117 .l_bracket => {
......@@ -3230,6 +3201,46 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
32303201 return null;
32313202 },
32323203 },
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 },
32333244 else => return null,
32343245 }
32353246}
......@@ -3243,7 +3254,7 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
32433254/// / KEYWORD_opaque
32443255/// / KEYWORD_enum (LPAREN Expr RPAREN)?
32453256/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
3246fn parseContainerDeclAuto(p: *Parse) !?Node.Index {
3257fn expectContainerDeclAuto(p: *Parse) !Node.Index {
32473258 const main_token = p.nextToken();
32483259 const arg_expr = switch (p.tokenTag(main_token)) {
32493260 .keyword_opaque => null,
......@@ -3366,6 +3377,7 @@ fn parseContainerDeclAuto(p: *Parse) !?Node.Index {
33663377/// Give a helpful error message for those transitioning from
33673378/// C's 'struct Foo {};' to Zig's 'const Foo = struct {};'.
33683379fn parseCStyleContainer(p: *Parse) Error!bool {
3380 if (!p.recover) return false;
33693381 const main_token = p.tok_i;
33703382 switch (p.tokenTag(p.tok_i)) {
33713383 .keyword_enum, .keyword_union, .keyword_struct => {},
......@@ -3431,10 +3443,13 @@ fn parseParamDeclList(p: *Parse) !SmallSpan {
34313443 _ = try p.expectToken(.l_paren);
34323444 const scratch_top = p.scratch.items.len;
34333445 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3434 var varargs: union(enum) { none, seen, nonfinal: TokenIndex } = .none;
3446 var varargs: enum { none, seen, err } = .none;
34353447 while (true) {
34363448 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 }
34383453 const opt_param = try p.expectParamDecl();
34393454 if (opt_param) |param| {
34403455 try p.scratch.append(p.gpa, param);
......@@ -3452,9 +3467,6 @@ fn parseParamDeclList(p: *Parse) !SmallSpan {
34523467 else => try p.warn(.expected_comma_after_param),
34533468 }
34543469 }
3455 if (varargs == .nonfinal) {
3456 try p.warnMsg(.{ .tag = .varargs_nonfinal, .token = varargs.nonfinal });
3457 }
34583470 const params = p.scratch.items[scratch_top..];
34593471 return switch (params.len) {
34603472 0 => .{ .zero_or_one = .none },
......@@ -3466,7 +3478,7 @@ fn parseParamDeclList(p: *Parse) !SmallSpan {
34663478/// FnCallArguments <- LPAREN ExprList RPAREN
34673479///
34683480/// ExprList <- (Expr COMMA)* Expr?
3469fn parseBuiltinCall(p: *Parse) !Node.Index {
3481fn expectBuiltinCall(p: *Parse) !Node.Index {
34703482 const builtin_token = p.assertToken(.builtin);
34713483 _ = p.eatToken(.l_paren) orelse {
34723484 try p.warn(.expected_param_list);
......@@ -3514,9 +3526,13 @@ fn parseBuiltinCall(p: *Parse) !Node.Index {
35143526 }
35153527}
35163528
3529/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else)
3530///
3531/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else)
3532///
35173533/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
3518fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index {
3519 const if_token = p.eatToken(.keyword_if) orelse return null;
3534fn expectIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index {
3535 const if_token = p.assertToken(.keyword_if);
35203536 _ = try p.expectToken(.l_paren);
35213537 const condition = try p.expectExpr();
35223538 _ = try p.expectToken(.r_paren);
......@@ -3548,11 +3564,11 @@ fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?N
35483564 });
35493565}
35503566
3551/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix
3567/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else)
35523568///
3553/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix
3554fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?Node.Index {
3555 const for_token = p.eatToken(.keyword_for) orelse return null;
3569/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else)
3570fn expectFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index {
3571 const for_token = p.assertToken(.keyword_for);
35563572
35573573 const scratch_top = p.scratch.items.len;
35583574 defer p.scratch.shrinkRetainingCapacity(scratch_top);
......@@ -3588,7 +3604,7 @@ fn parseFor(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !?
35883604}
35893605
35903606/// Skips over doc comment tokens. Returns the first one, if any.
3591fn eatDocComments(p: *Parse) Allocator.Error!?TokenIndex {
3607fn eatDocComments(p: *Parse) Error!?TokenIndex {
35923608 if (p.eatToken(.doc_comment)) |tok| {
35933609 var first_line = tok;
35943610 if (tok > 0 and tokensOnSameLine(p, tok - 1, tok)) {
......@@ -3643,7 +3659,7 @@ fn expectSemicolon(p: *Parse, error_tag: AstError.Tag, recoverable: bool) Error!
36433659 return;
36443660 }
36453661 try p.warn(error_tag);
3646 if (!recoverable) return error.ParseError;
3662 if (!recoverable or !p.recover) return error.ParseError;
36473663}
36483664
36493665fn nextToken(p: *Parse) TokenIndex {
lib/std/zig/parser_fuzz.zig created+243
......@@ -0,0 +1,243 @@
1const std = @import("../std.zig");
2const Allocator = std.mem.Allocator;
3const Smith = std.testing.Smith;
4
5const oracle = @import("parser_generated_oracle.zig");
6
7test "fuzz std.zig.Ast.parse() against generated oracle" {
8 try std.testing.fuzz({}, fuzzAgainstOracle, .{});
9}
10
11fn 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
23test "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++
32test "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++
45test "doc comment or division operator" {
46 try checkAgainstOracle("0=0///\n0");
47}
48
49// Found using AFL++
50test "double ampersand" {
51 try checkAgainstOracle("0=0&&0"); // error
52 try checkAgainstOracle("test{&&0;}"); // ok
53}
54
55// Found using AFL++
56test "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++
68test "extra capture in for loop" {
69 try checkAgainstOracle("for(0)|t,r|0");
70}
71
72// Found using AFL++
73test "expression nesting" {
74 try checkAgainstOracle("test{*comptime 0 == 0;}");
75}
76
77// Found using AFL++
78test "comptime fn" {
79 try checkAgainstOracle("comptime fn()0");
80}
81
82// Found using AFL++
83test "return asterisk" {
84 try checkAgainstOracle("test{return*!0;}");
85}
86
87// Found using AFL++
88test "fn container field" {
89 try checkAgainstOracle("fn()0");
90}
91
92// Found using AFL++
93test "at newline string" {
94 try checkAgainstOracle(
95 \\@
96 \\""
97 );
98}
99
100// Found using AFL++
101test "string lit" {
102 try checkAgainstOracle(
103 \\"\\"
104 );
105}
106
107// Found using AFL++
108test "dot question" {
109 try checkAgainstOracle("0. ?");
110}
111
112// Found using AFL++
113test "volatile const" {
114 try checkAgainstOracle("*volatile\nconst\n0");
115}
116
117// Found using AFL++
118test "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++
126test "catch capture whitespace" {
127 try checkAgainstOracle("test{0 catch |h|0;}");
128}
129
130// Found using AFL++
131test "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++
138test "nosuspend multi assign" {
139 try checkAgainstOracle("test{nosuspend*0,var _=0;}");
140}
141
142// Found using AFL++
143test "bin op at end of file" {
144 try checkAgainstOracle(
145 \\test {
146 \\ _ = 00
147 \\|
148 );
149}
150
151// Found using AFL++
152test "resume block chained compare ops" {
153 try checkAgainstOracle("test{resume{0 > 0;} > 0 > 0;}");
154}
155
156// Found using AFL++
157test "for multiassign" {
158 try checkAgainstOracle("test{for(0)|t|0,const w=0;}");
159}
160
161fn 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
180fn 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
188fn 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
202pub 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
210fn 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
4const std = @import("std");
5
6const Error = error{MaxDepth};
7const 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.
12pub fn parse(source: []const u8) Error!bool {
13 var p: Parser = .{ .source = source, .i = 0, .depths = @splat(1) };
14 return p.parseRoot();
15}
16const 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};
290const 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" {
69766976 , &[_]Error{
69776977 .expected_comma_after_switch_prong,
69786978 .expected_comma_after_switch_prong,
6979 .mismatched_binary_op_whitespace,
69796980 .expected_expr,
69806981 });
69816982}
......@@ -6992,10 +6993,10 @@ test "recovery: non-associative operators" {
69926993
69936994test "recovery: extra qualifier" {
69946995 try testError(
6995 \\const a: *const const u8;
6996 \\const a: *align(4) align(8) u8;
69966997 \\test ""
69976998 , &[_]Error{
6998 .extra_const_qualifier,
6999 .extra_align_qualifier,
69997000 .expected_block,
70007001 });
70017002}
......@@ -7230,7 +7231,7 @@ test "ampersand" {
72307231test "Ast: pointer types with subexprs containing qualifiers" {
72317232 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
72327233 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, .{});
72347235 defer tree.deinit(allocator);
72357236
72367237 const regular_ptr_node = tree.nodeData(.root).node;
......@@ -7252,7 +7253,7 @@ fn testParse(io: Io, source: [:0]const u8, allocator: Allocator, anything_change
72527253 defer io.unlockStderr();
72537254 const writer = &stderr.file_writer.interface;
72547255
7255 var tree = try std.zig.Ast.parse(allocator, source, .zig);
7256 var tree = try std.zig.Ast.parse(allocator, source, .zig, .{});
72567257 defer tree.deinit(allocator);
72577258
72587259 for (tree.errors) |parse_error| {
......@@ -7312,7 +7313,7 @@ fn testCanonical(source: [:0]const u8) !void {
73127313const Error = std.zig.Ast.Error.Tag;
73137314
73147315fn 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, .{});
73167317 defer tree.deinit(std.testing.allocator);
73177318
73187319 std.testing.expectEqual(expected_errors.len, tree.errors.len) catch |err| {
......@@ -7332,268 +7333,5 @@ fn fuzzTestOneParse(_: void, smith: *std.testing.Smith) !void {
73327333 const mode = smith.value(std.zig.Ast.Mode);
73337334 var tokens: std.zig.TokenSmith = .gen(smith);
73347335 var fba: std.heap.FixedBufferAllocator = .init(&fixed_buffer_mem);
7335 _ = std.zig.Ast.parseTokens(fba.allocator(), tokens.source(), tokens.list(), mode) catch return;
7336}
7337
7338test "zig fmt: fuzz" {
7339 try std.testing.fuzz({}, fuzzRender, .{});
7340}
7341
7342fn 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.
7402fn 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
7421fn 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`
7454fn 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
7506fn 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
7525fn 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
7570fn 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
7577fn 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");
7336 _ = std.zig.Ast.parseTokens(fba.allocator(), tokens.source(), tokens.list(), mode, .{ .recover = false }) catch return;
75997337}
lib/std/zig/perf_test.zig+1-1
......@@ -32,6 +32,6 @@ pub fn main() !void {
3232fn testOnce() usize {
3333 var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(&fixed_buffer_mem);
3434 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");
3636 return fixed_buf_alloc.end_index;
3737}
lib/std/zon/parse.zig+3-3
......@@ -294,7 +294,7 @@ pub fn fromSliceAlloc(
294294) error{ OutOfMemory, ParseZon }!T {
295295 if (diag) |s| s.assertEmpty();
296296
297 var ast = try std.zig.Ast.parse(gpa, source, .zon);
297 var ast = try std.zig.Ast.parse(gpa, source, .zon, .{});
298298 defer if (diag == null) ast.deinit(gpa);
299299 if (diag) |s| s.ast = ast;
300300
......@@ -2140,7 +2140,7 @@ test "std.zon string literal" {
21402140 // Passing string literal to a array
21412141 {
21422142 {
2143 var ast = try std.zig.Ast.parse(gpa, "\"abcd\"", .zon);
2143 var ast = try std.zig.Ast.parse(gpa, "\"abcd\"", .zon, .{});
21442144 defer ast.deinit(gpa);
21452145 var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
21462146 defer zoir.deinit(gpa);
......@@ -3534,7 +3534,7 @@ test "std.zon no alloc" {
35343534
35353535 const Nested = struct { u8, u8, struct { u8, u8 } };
35363536
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, .{});
35383538 defer ast.deinit(gpa);
35393539
35403540 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!
296296
297297 log.debug("parsing and generating 'builtin.zig'", .{});
298298
299 file.tree = try std.zig.Ast.parse(gpa, file.source.?, .zig);
299 file.tree = try std.zig.Ast.parse(gpa, file.source.?, .zig, .{});
300300 assert(file.tree.?.errors.len == 0); // builtin.zig must parse
301301
302302 file.zir = try AstGen.generate(gpa, file.tree.?);
src/Zcu.zig+1-1
......@@ -1145,7 +1145,7 @@ pub const File = struct {
11451145 if (file.tree) |*tree| return tree;
11461146
11471147 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(), .{});
11491149 return &file.tree.?;
11501150 }
11511151
src/Zcu/PerThread.zig+1-1
......@@ -642,7 +642,7 @@ pub fn updateFile(
642642
643643 var timer = comp.startTimer();
644644 // 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(), .{});
646646 if (timer.finish(io)) |ns_parse| {
647647 comp.mutex.lockUncancelable(io);
648648 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) !
117117 };
118118 defer gpa.free(source_code);
119119
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| {
121121 fatal("error parsing stdin: {}", .{err});
122122 };
123123 defer tree.deinit(gpa);
......@@ -312,7 +312,7 @@ fn fmtPathFile(
312312 break :mode .zig;
313313 };
314314
315 var tree = try std.zig.Ast.parse(gpa, source_code, mode);
315 var tree = try std.zig.Ast.parse(gpa, source_code, mode, .{});
316316 defer tree.deinit(gpa);
317317
318318 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:
55285528 break :mode .zig;
55295529 };
55305530
5531 const tree = try Ast.parse(arena, source, mode);
5531 const tree = try Ast.parse(arena, source, mode, .{});
55325532
55335533 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
55345534 const stdout_bw = &stdout_writer.interface;
......@@ -5698,7 +5698,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map
56985698 fatal("unable to read new source file {q}: {t}", .{ new_source_path, err });
56995699 };
57005700
5701 const old_tree = try Ast.parse(arena, old_source, .zig);
5701 const old_tree = try Ast.parse(arena, old_source, .zig, .{});
57025702 const old_zir = try AstGen.generate(arena, old_tree);
57035703
57045704 if (old_zir.loweringFailed()) {
......@@ -5710,7 +5710,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map
57105710 process.exit(1);
57115711 }
57125712
5713 const new_tree = try Ast.parse(arena, new_source, .zig);
5713 const new_tree = try Ast.parse(arena, new_source, .zig, .{});
57145714 const new_zir = try AstGen.generate(arena, new_tree);
57155715
57165716 if (new_zir.loweringFailed()) {
test/standalone/build.zig+1
......@@ -36,6 +36,7 @@ pub fn build(b: *std.Build) void {
3636 "../../tools/fetch_them_macos_headers.zig",
3737 "../../tools/gen_macos_headers_c.zig",
3838 "../../tools/gen_outline_atomics.zig",
39 "../../tools/gen_parser_oracle.zig",
3940 "../../tools/gen_spirv_spec.zig",
4041 "../../tools/gen_stubs.zig",
4142 "../../tools/generate_c_size_and_align_checks.zig",
tools/docgen.zig+28-4
......@@ -25,6 +25,7 @@ const usage =
2525 \\
2626 \\Options:
2727 \\ --code-dir dir Path to directory containing code example outputs
28 \\ --grammar file Path to the PEG grammar definition
2829 \\ -h, --help Print this help and exit
2930 \\
3031;
......@@ -37,6 +38,7 @@ pub fn main(init: std.process.Init) !void {
3738 if (!args_it.skip()) @panic("expected self arg");
3839
3940 var opt_code_dir: ?[]const u8 = null;
41 var opt_grammar: ?[]const u8 = null;
4042 var opt_input: ?[]const u8 = null;
4143 var opt_output: ?[]const u8 = null;
4244
......@@ -51,6 +53,12 @@ pub fn main(init: std.process.Init) !void {
5153 } else {
5254 fatal("expected parameter after --code-dir", .{});
5355 }
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 }
5462 } else {
5563 fatal("unrecognized option: '{s}'", .{arg});
5664 }
......@@ -65,6 +73,7 @@ pub fn main(init: std.process.Init) !void {
6573 const input_path = opt_input orelse fatal("missing input file", .{});
6674 const output_path = opt_output orelse fatal("missing output file", .{});
6775 const code_dir_path = opt_code_dir orelse fatal("missing --code-dir argument", .{});
76 const grammar_path = opt_grammar orelse fatal("missing --grammar argument", .{});
6877
6978 var in_file = try Dir.cwd().openFile(io, input_path, .{});
7079 defer in_file.close(io);
......@@ -82,13 +91,16 @@ pub fn main(init: std.process.Init) !void {
8291 };
8392 defer code_dir.root_dir.handle.close(io);
8493
94 const grammar = try Dir.cwd().readFileAlloc(io, grammar_path, init.gpa, .limited(max_doc_file_size));
95 defer init.gpa.free(grammar);
96
8597 var in_file_reader = in_file.reader(io, &.{});
8698 const input_file_bytes = try in_file_reader.interface.allocRemaining(arena, .limited(max_doc_file_size));
8799
88100 var tokenizer = Tokenizer.init(input_path, input_file_bytes);
89101 var toc = try genToc(arena, &tokenizer);
90102
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);
92104 try out_file_writer.end();
93105}
94106
......@@ -326,6 +338,7 @@ const Node = union(enum) {
326338 HeaderOpen: HeaderOpen,
327339 SeeAlso: []const SeeAlsoItem,
328340 Code: Code,
341 Grammar,
329342 Link: Link,
330343 InlineSyntax: Token,
331344 Shell: Token,
......@@ -513,6 +526,9 @@ fn genToc(gpa: Allocator, tokenizer: *Tokenizer) !Toc {
513526 .token = name_tok,
514527 },
515528 });
529 } else if (mem.eql(u8, tag_name, "grammar")) {
530 _ = try eatToken(tokenizer, .bracket_close);
531 try nodes.append(.Grammar);
516532 } else if (mem.eql(u8, tag_name, "syntax")) {
517533 _ = try eatToken(tokenizer, .bracket_close);
518534 const content_tok = try eatToken(tokenizer, .content);
......@@ -924,14 +940,14 @@ fn tokenizeAndPrint(
924940 return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src);
925941}
926942
927fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: *Writer, syntax_block: SyntaxBlock) !void {
943fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: *Writer, syntax_block: SyntaxBlock, content: ?[]const u8) !void {
928944 const source_type = @tagName(syntax_block.source_type);
929945
930946 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name });
931947 switch (syntax_block.source_type) {
932948 .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token),
933949 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];
935951 const trimmed_raw_source = mem.trim(u8, raw_source, " \r\n");
936952
937953 try out.writeAll("<code>");
......@@ -995,6 +1011,7 @@ fn genHtml(
9951011 tokenizer: *Tokenizer,
9961012 toc: *Toc,
9971013 code_dir: Path,
1014 grammar: []const u8,
9981015 out: *Writer,
9991016) !void {
10001017 for (toc.nodes) |node| {
......@@ -1042,7 +1059,7 @@ fn genHtml(
10421059 try printShell(out, raw_shell_content, true);
10431060 },
10441061 .SyntaxBlock => |syntax_block| {
1045 try printSourceBlock(allocator, tokenizer, out, syntax_block);
1062 try printSourceBlock(allocator, tokenizer, out, syntax_block, null);
10461063 },
10471064 .Code => |code| {
10481065 const out_basename = try std.fmt.allocPrint(allocator, "{s}.out", .{
......@@ -1062,6 +1079,13 @@ fn genHtml(
10621079
10631080 try out.writeAll(contents);
10641081 },
1082 .Grammar => {
1083 try printSourceBlock(allocator, tokenizer, out, .{
1084 .source_type = .peg,
1085 .name = "grammar.peg",
1086 .source_token = undefined,
1087 }, grammar);
1088 },
10651089 }
10661090 }
10671091}
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
11const std = @import("std");
12const assert = std.debug.assert;
13const Io = std.Io;
14const mem = std.mem;
15const Allocator = mem.Allocator;
16const log = std.log;
17
18pub 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
81const 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
357const 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 {
116116 try allocating.writer.writeByte(0);
117117 const output = allocating.written()[0 .. allocating.written().len - 1 :0];
118118
119 var tree = try std.zig.Ast.parse(arena, output, .zig);
119 var tree = try std.zig.Ast.parse(arena, output, .zig, .{});
120120
121121 if (tree.errors.len != 0) {
122122 try std.zig.printAstErrorsToStderr(arena, io, tree, "", .auto);