authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-06-11 09:43:16+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 11:48:57+02:00
log82297207263575358702e84788731e2b2c4d8871
treef07d78253475fbc52df9974f3a4d0cd0ebafe5c9
parentf2c9e7a5c9d6fb171ec78e094e5c41df6b9cdfe5
signaturelock-open Commit is signed but in an unrecognized format.

langref: move grammar.peg to separate file

This improves the developer experience, especially with the new gen_parser_oracle tool. My intent is for doc/langref/grammar.peg to be the single source of truth, at least until we have an actual language spec. The separate copy in the separate zig-spec repo should not be considered canonical as it is not tested against by CI.

4 files changed, 623 insertions(+), 597 deletions(-)

build.zig+5-2
...@@ -1569,8 +1569,9 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath {...@@ -1569,8 +1569,9 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath {
15691569
1570 var it = dir.iterateAssumeFirstIteration();1570 var it = dir.iterateAssumeFirstIteration();
1571 while (it.next(io) catch @panic("failed to read dir")) |entry| {1571 while (it.next(io) catch @panic("failed to read dir")) |entry| {
1572 if (std.mem.startsWith(u8, entry.name, ".") or entry.kind != .file)1572 if (entry.kind != .file) continue;
1573 continue;1573 if (std.mem.startsWith(u8, entry.name, ".")) continue;
1574 if (!std.mem.endsWith(u8, entry.name, ".zig")) continue;
15741575
1575 const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)});1576 const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)});
1576 const cmd = b.addRunArtifact(doctest_exe);1577 const cmd = b.addRunArtifact(doctest_exe);
...@@ -1603,6 +1604,8 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath {...@@ -1603,6 +1604,8 @@ fn generateLangRef(b: *std.Build) !std.Build.LazyPath {
1603 const docgen_cmd = b.addRunArtifact(docgen_exe);1604 const docgen_cmd = b.addRunArtifact(docgen_exe);
1604 docgen_cmd.addArgs(&.{"--code-dir"});1605 docgen_cmd.addArgs(&.{"--code-dir"});
1605 docgen_cmd.addDirectoryArg(wf.getDirectory());1606 docgen_cmd.addDirectoryArg(wf.getDirectory());
1607 docgen_cmd.addArgs(&.{"--grammar"});
1608 docgen_cmd.addFileArg(b.path("doc/langref/grammar.peg"));
16061609
1607 docgen_cmd.addFileArg(b.path("doc/langref.html.in"));1610 docgen_cmd.addFileArg(b.path("doc/langref.html.in"));
1608 return docgen_cmd.addOutputFileArg("langref.html");1611 return docgen_cmd.addOutputFileArg("langref.html");
doc/langref.html.in+1-591
...@@ -7782,597 +7782,7 @@ fn readU32Be() u32 {}...@@ -7782,597 +7782,7 @@ fn readU32Be() u32 {}
77827782
7783 {#header_open|Appendix#}7783 {#header_open|Appendix#}
7784 {#header_open|Grammar#}7784 {#header_open|Grammar#}
7785 {#syntax_block|peg|grammar.peg#}7785 {#grammar#}
7786Root <- skip ContainerMembers eof
7787
7788# *** Top level ***
7789ContainerMembers <- container_doc_comment? ContainerDeclaration* (ContainerField COMMA)* (ContainerField / ContainerDeclaration*)
7790
7791ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl
7792
7793TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block
7794
7795ComptimeDecl <- KEYWORD_comptime Block
7796
7797Decl
7798 <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)
7799 / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON
7800 / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl
7801
7802FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix
7803
7804VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection?
7805
7806GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON
7807
7808ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)?
7809
7810# *** Block Level ***
7811BlockStatement
7812 <- Statement
7813 / KEYWORD_defer BlockExprStatement
7814 / KEYWORD_errdefer BlockExprStatement
7815 / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
7816
7817Statement
7818 <- ExprStatement
7819 / KEYWORD_suspend BlockExprStatement
7820 / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON
7821
7822ExprStatement
7823 <- IfStatement
7824 / LabeledStatement
7825 / KEYWORD_nosuspend BlockExprStatement
7826 / KEYWORD_comptime BlockExpr
7827
7828IfStatement
7829 <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
7830 / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
7831
7832LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)
7833
7834LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
7835
7836ForStatement
7837 <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )
7838 / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement )
7839
7840WhileStatement
7841 <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
7842 / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
7843
7844BlockExprStatement
7845 <- BlockExpr
7846 / !BlockExpr AssignExpr SEMICOLON
7847
7848BlockExpr <- BlockLabel? Block
7849
7850# An assignment or a destructure whose LHS are all lvalue expressions or variable declarations.
7851VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON
7852
7853# *** Expression Level ***
7854
7855# An assignment or a destructure whose LHS are all lvalue expressions.
7856AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)?
7857
7858SingleAssignExpr <- Expr (AssignOp Expr)?
7859
7860Expr <- BoolOrExpr
7861
7862BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
7863
7864BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
7865
7866CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
7867
7868BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
7869
7870BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
7871
7872AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
7873
7874MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
7875
7876PrefixExpr <- PrefixOp* PrimaryExpr
7877
7878PrimaryExpr
7879 <- AsmExpr
7880 / IfExpr
7881 / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
7882 / KEYWORD_comptime Expr !ExprSuffix
7883 / KEYWORD_nosuspend Expr !ExprSuffix
7884 / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
7885 / KEYWORD_resume Expr !ExprSuffix
7886 / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart)
7887 / BlockLabel? LoopExpr
7888 / Block
7889 / CurlySuffixExpr
7890
7891IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
7892
7893Block <- LBRACE BlockStatement* RBRACE
7894
7895LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
7896
7897ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix
7898
7899WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
7900
7901CurlySuffixExpr <- TypeExpr InitList?
7902
7903InitList
7904 <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
7905 / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
7906 / LBRACE RBRACE
7907
7908TypeExpr <- PrefixTypeOp* ErrorUnionExpr
7909
7910ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
7911
7912SuffixExpr
7913 <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
7914
7915PrimaryTypeExpr
7916 <- BUILTINIDENTIFIER FnCallArguments
7917 / CHAR_LITERAL
7918 / ContainerDecl
7919 / DOT IDENTIFIER
7920 / DOT InitList
7921 / ErrorSetDecl
7922 / FLOAT
7923 / FnProto
7924 / GroupedExpr
7925 / LabeledTypeExpr
7926 / IDENTIFIER !(COLON LabelableExpr)
7927 / IfTypeExpr
7928 / INTEGER
7929 / KEYWORD_comptime TypeExpr !ExprSuffix
7930 / KEYWORD_error DOT IDENTIFIER
7931 / KEYWORD_anyframe
7932 / KEYWORD_unreachable
7933 / STRINGLITERAL
7934
7935ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
7936
7937ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
7938
7939GroupedExpr <- LPAREN Expr RPAREN
7940
7941IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
7942
7943LabeledTypeExpr
7944 <- BlockLabel Block
7945 / BlockLabel? LoopTypeExpr
7946 / BlockLabel? SwitchExpr
7947
7948LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
7949
7950ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix
7951
7952WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
7953
7954SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
7955
7956# *** Assembly ***
7957AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
7958
7959AsmOutput <- COLON AsmOutputList AsmInput?
7960
7961AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
7962
7963AsmInput <- COLON AsmInputList AsmClobbers?
7964
7965AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN
7966
7967AsmClobbers <- COLON Expr
7968
7969# *** Helper grammar ***
7970BreakLabel <- COLON IDENTIFIER
7971
7972BlockLabel <- IDENTIFIER COLON
7973
7974FieldInit <- DOT IDENTIFIER EQUAL Expr
7975
7976WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
7977
7978LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
7979
7980AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
7981
7982# Fn specific
7983CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
7984
7985ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime / !KEYWORD_comptime) (IDENTIFIER COLON / !(IDENTIFIER COLON)) ParamType
7986
7987ParamType
7988 <- KEYWORD_anytype
7989 / TypeExpr
7990
7991# Control flow prefixes
7992IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
7993
7994WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
7995
7996ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload
7997
7998# Payloads
7999Payload <- PIPE IDENTIFIER PIPE
8000
8001PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
8002
8003PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
8004
8005PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE
8006
8007# Switch specific
8008SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr
8009
8010SwitchCase
8011 <- SwitchItem (COMMA SwitchItem)* COMMA?
8012 / KEYWORD_else
8013
8014SwitchItem <- Expr (DOT3 Expr)?
8015
8016# For specific
8017ForArgumentsList <- ForItem (COMMA ForItem)* COMMA?
8018
8019ForItem <- Expr (DOT2 Expr?)?
8020
8021# Operators
8022AssignOp
8023 <- ASTERISKEQUAL
8024 / ASTERISKPIPEEQUAL
8025 / SLASHEQUAL
8026 / PERCENTEQUAL
8027 / PLUSEQUAL
8028 / PLUSPIPEEQUAL
8029 / MINUSEQUAL
8030 / MINUSPIPEEQUAL
8031 / LARROW2EQUAL
8032 / LARROW2PIPEEQUAL
8033 / RARROW2EQUAL
8034 / AMPERSANDEQUAL
8035 / CARETEQUAL
8036 / PIPEEQUAL
8037 / ASTERISKPERCENTEQUAL
8038 / PLUSPERCENTEQUAL
8039 / MINUSPERCENTEQUAL
8040 / EQUAL
8041
8042CompareOp
8043 <- EQUALEQUAL
8044 / EXCLAMATIONMARKEQUAL
8045 / LARROW
8046 / RARROW
8047 / LARROWEQUAL
8048 / RARROWEQUAL
8049
8050BitwiseOp
8051 <- AMPERSAND
8052 / CARET
8053 / PIPE
8054 / KEYWORD_orelse
8055 / KEYWORD_catch Payload?
8056
8057BitShiftOp
8058 <- LARROW2
8059 / RARROW2
8060 / LARROW2PIPE
8061
8062AdditionOp
8063 <- PLUS
8064 / MINUS
8065 / PLUS2
8066 / PLUSPERCENT
8067 / MINUSPERCENT
8068 / PLUSPIPE
8069 / MINUSPIPE
8070
8071MultiplyOp
8072 <- PIPE2
8073 / ASTERISK
8074 / SLASH
8075 / PERCENT
8076 / ASTERISKPERCENT
8077 / ASTERISKPIPE
8078
8079PrefixOp
8080 <- EXCLAMATIONMARK
8081 / MINUS
8082 / TILDE
8083 / MINUSPERCENT
8084 / AMPERSAND
8085 / KEYWORD_try
8086
8087PrefixTypeOp
8088 <- QUESTIONMARK
8089 / KEYWORD_anyframe MINUSRARROW
8090 / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
8091 / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
8092 / ArrayTypeStart
8093
8094SuffixOp
8095 <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET
8096 / DOT IDENTIFIER
8097 / DOTASTERISK
8098 / DOTQUESTIONMARK
8099
8100FnCallArguments <- LPAREN ExprList RPAREN
8101
8102ExprSuffix
8103 <- KEYWORD_or
8104 / KEYWORD_and
8105 / CompareOp
8106 / BitwiseOp
8107 / BitShiftOp
8108 / AdditionOp
8109 / MultiplyOp
8110 / EXCLAMATIONMARK
8111 / SuffixOp
8112 / FnCallArguments
8113
8114LabelableExpr
8115 <- Block
8116 / SwitchExpr
8117 / LoopExpr
8118
8119# Ptr specific
8120SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
8121
8122SinglePtrTypeStart <- ASTERISK
8123
8124ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
8125
8126ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET
8127
8128# ContainerDecl specific
8129ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
8130
8131ContainerDeclType
8132 <- KEYWORD_struct (LPAREN Expr RPAREN)?
8133 / KEYWORD_opaque
8134 / KEYWORD_enum (LPAREN Expr RPAREN)?
8135 / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / !KEYWORD_enum Expr) RPAREN)?
8136
8137# Alignment
8138ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
8139
8140BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
8141
8142# Lists
8143IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?
8144
8145SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
8146
8147AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
8148
8149AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
8150
8151ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)?
8152
8153ExprList <- (Expr COMMA)* Expr?
8154
8155# *** Tokens ***
8156eof <- !.
8157bin <- [01]
8158bin_ <- '_'? bin
8159oct <- [0-7]
8160oct_ <- '_'? oct
8161hex <- [0-9a-fA-F]
8162hex_ <- '_'? hex
8163dec <- [0-9]
8164dec_ <- '_'? dec
8165
8166bin_int <- bin bin_*
8167oct_int <- oct oct_*
8168dec_int <- dec dec_*
8169hex_int <- hex hex_*
8170
8171ox80_oxBF <- [\200-\277]
8172oxF4 <- '\364'
8173ox80_ox8F <- [\200-\217]
8174oxF1_oxF3 <- [\361-\363]
8175oxF0 <- '\360'
8176ox90_0xBF <- [\220-\277]
8177oxEE_oxEF <- [\356-\357]
8178oxED <- '\355'
8179ox80_ox9F <- [\200-\237]
8180oxE1_oxEC <- [\341-\354]
8181oxE0 <- '\340'
8182oxA0_oxBF <- [\240-\277]
8183oxC2_oxDF <- [\302-\337]
8184
8185# From https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/
8186# First Byte Second Byte Third Byte Fourth Byte
8187# [0x00,0x7F]
8188# [0xC2,0xDF] [0x80,0xBF]
8189# 0xE0 [0xA0,0xBF] [0x80,0xBF]
8190# [0xE1,0xEC] [0x80,0xBF] [0x80,0xBF]
8191# 0xED [0x80,0x9F] [0x80,0xBF]
8192# [0xEE,0xEF] [0x80,0xBF] [0x80,0xBF]
8193# 0xF0 [0x90,0xBF] [0x80,0xBF] [0x80,0xBF]
8194# [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF]
8195# 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF]
8196
8197multibyte_utf8 <-
8198 oxF4 ox80_ox8F ox80_oxBF ox80_oxBF
8199 / oxF1_oxF3 ox80_oxBF ox80_oxBF ox80_oxBF
8200 / oxF0 ox90_0xBF ox80_oxBF ox80_oxBF
8201 / oxEE_oxEF ox80_oxBF ox80_oxBF
8202 / oxED ox80_ox9F ox80_oxBF
8203 / oxE1_oxEC ox80_oxBF ox80_oxBF
8204 / oxE0 oxA0_oxBF ox80_oxBF
8205 / oxC2_oxDF ox80_oxBF
8206
8207non_control_ascii <- [\040-\176]
8208non_control_utf8 <- [\040-\377]
8209
8210char_escape
8211 <- "\\x" hex hex
8212 / "\\u{" hex+ "}"
8213 / "\\" [nr\\t'"]
8214char_char
8215 <- multibyte_utf8
8216 / char_escape
8217 / ![\\'\n] non_control_ascii
8218
8219string_char
8220 <- multibyte_utf8
8221 / char_escape
8222 / ![\\"\n] non_control_ascii
8223
8224container_doc_comment <- ('//!' non_control_utf8* [ \n]* skip)+
8225doc_comment <- ('///' non_control_utf8* [ \n]* skip)+
8226line_comment <- '//' ![!/] non_control_utf8* / '////' non_control_utf8*
8227line_string <- '\\\\' non_control_utf8* [ \n]*
8228skip <- ([ \n] / line_comment)*
8229
8230CHAR_LITERAL <- ['] char_char ['] skip
8231FLOAT
8232 <- '0x' hex_int '.' hex_int ([pP] [-+]? dec_int)? skip
8233 / dec_int '.' dec_int ([eE] [-+]? dec_int)? skip
8234 / '0x' hex_int [pP] [-+]? dec_int skip
8235 / dec_int [eE] [-+]? dec_int skip
8236INTEGER
8237 <- '0b' bin_int skip
8238 / '0o' oct_int skip
8239 / '0x' hex_int skip
8240 / dec_int skip
8241STRINGLITERALSINGLE <- ["] string_char* ["] skip
8242STRINGLITERAL
8243 <- STRINGLITERALSINGLE
8244 / (line_string skip)+
8245IDENTIFIER
8246 <- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
8247 / '@' STRINGLITERALSINGLE
8248BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip
8249
8250
8251AMPERSAND <- '&' ![=] skip
8252AMPERSANDEQUAL <- '&=' skip
8253ASTERISK <- '*' ![%=|] skip
8254ASTERISKEQUAL <- '*=' skip
8255ASTERISKPERCENT <- '*%' ![=] skip
8256ASTERISKPERCENTEQUAL <- '*%=' skip
8257ASTERISKPIPE <- '*|' ![=] skip
8258ASTERISKPIPEEQUAL <- '*|=' skip
8259CARET <- '^' ![=] skip
8260CARETEQUAL <- '^=' skip
8261COLON <- ':' skip
8262COMMA <- ',' skip
8263DOT <- '.' ![*.?] skip
8264DOT2 <- '..' ![.] skip
8265DOT3 <- '...' skip
8266DOTASTERISK <- '.*' skip
8267DOTQUESTIONMARK <- '.?' skip
8268EQUAL <- '=' ![>=] skip
8269EQUALEQUAL <- '==' skip
8270EQUALRARROW <- '=>' skip
8271EXCLAMATIONMARK <- '!' ![=] skip
8272EXCLAMATIONMARKEQUAL <- '!=' skip
8273LARROW <- '<' ![<=] skip
8274LARROW2 <- '<<' ![=|] skip
8275LARROW2EQUAL <- '<<=' skip
8276LARROW2PIPE <- '<<|' ![=] skip
8277LARROW2PIPEEQUAL <- '<<|=' skip
8278LARROWEQUAL <- '<=' skip
8279LBRACE <- '{' skip
8280LBRACKET <- '[' skip
8281LPAREN <- '(' skip
8282MINUS <- '-' ![%=>|] skip
8283MINUSEQUAL <- '-=' skip
8284MINUSPERCENT <- '-%' ![=] skip
8285MINUSPERCENTEQUAL <- '-%=' skip
8286MINUSPIPE <- '-|' ![=] skip
8287MINUSPIPEEQUAL <- '-|=' skip
8288MINUSRARROW <- '->' skip
8289PERCENT <- '%' ![=] skip
8290PERCENTEQUAL <- '%=' skip
8291PIPE <- '|' ![|=] skip
8292PIPE2 <- '||' skip
8293PIPEEQUAL <- '|=' skip
8294PLUS <- '+' ![%+=|] skip
8295PLUS2 <- '++' skip
8296PLUSEQUAL <- '+=' skip
8297PLUSPERCENT <- '+%' ![=] skip
8298PLUSPERCENTEQUAL <- '+%=' skip
8299PLUSPIPE <- '+|' ![=] skip
8300PLUSPIPEEQUAL <- '+|=' skip
8301LETTERC <- 'c' skip
8302QUESTIONMARK <- '?' skip
8303RARROW <- '>' ![>=] skip
8304RARROW2 <- '>>' ![=] skip
8305RARROW2EQUAL <- '>>=' skip
8306RARROWEQUAL <- '>=' skip
8307RBRACE <- '}' skip
8308RBRACKET <- ']' skip
8309RPAREN <- ')' skip
8310SEMICOLON <- ';' skip
8311SLASH <- '/' ![=] skip
8312SLASHEQUAL <- '/=' skip
8313TILDE <- '~' skip
8314
8315end_of_word <- ![a-zA-Z0-9_] skip
8316KEYWORD_addrspace <- 'addrspace' end_of_word
8317KEYWORD_align <- 'align' end_of_word
8318KEYWORD_allowzero <- 'allowzero' end_of_word
8319KEYWORD_and <- 'and' end_of_word
8320KEYWORD_anyframe <- 'anyframe' end_of_word
8321KEYWORD_anytype <- 'anytype' end_of_word
8322KEYWORD_asm <- 'asm' end_of_word
8323KEYWORD_break <- 'break' end_of_word
8324KEYWORD_callconv <- 'callconv' end_of_word
8325KEYWORD_catch <- 'catch' end_of_word
8326KEYWORD_comptime <- 'comptime' end_of_word
8327KEYWORD_const <- 'const' end_of_word
8328KEYWORD_continue <- 'continue' end_of_word
8329KEYWORD_defer <- 'defer' end_of_word
8330KEYWORD_else <- 'else' end_of_word
8331KEYWORD_enum <- 'enum' end_of_word
8332KEYWORD_errdefer <- 'errdefer' end_of_word
8333KEYWORD_error <- 'error' end_of_word
8334KEYWORD_export <- 'export' end_of_word
8335KEYWORD_extern <- 'extern' end_of_word
8336KEYWORD_fn <- 'fn' end_of_word
8337KEYWORD_for <- 'for' end_of_word
8338KEYWORD_if <- 'if' end_of_word
8339KEYWORD_inline <- 'inline' end_of_word
8340KEYWORD_noalias <- 'noalias' end_of_word
8341KEYWORD_nosuspend <- 'nosuspend' end_of_word
8342KEYWORD_noinline <- 'noinline' end_of_word
8343KEYWORD_opaque <- 'opaque' end_of_word
8344KEYWORD_or <- 'or' end_of_word
8345KEYWORD_orelse <- 'orelse' end_of_word
8346KEYWORD_packed <- 'packed' end_of_word
8347KEYWORD_pub <- 'pub' end_of_word
8348KEYWORD_resume <- 'resume' end_of_word
8349KEYWORD_return <- 'return' end_of_word
8350KEYWORD_linksection <- 'linksection' end_of_word
8351KEYWORD_struct <- 'struct' end_of_word
8352KEYWORD_suspend <- 'suspend' end_of_word
8353KEYWORD_switch <- 'switch' end_of_word
8354KEYWORD_test <- 'test' end_of_word
8355KEYWORD_threadlocal <- 'threadlocal' end_of_word
8356KEYWORD_try <- 'try' end_of_word
8357KEYWORD_union <- 'union' end_of_word
8358KEYWORD_unreachable <- 'unreachable' end_of_word
8359KEYWORD_var <- 'var' end_of_word
8360KEYWORD_volatile <- 'volatile' end_of_word
8361KEYWORD_while <- 'while' end_of_word
8362
8363keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and
8364 / KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm
8365 / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch
8366 / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer
8367 / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export
8368 / KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if
8369 / KEYWORD_inline / KEYWORD_noalias / KEYWORD_nosuspend / KEYWORD_noinline
8370 / KEYWORD_opaque / KEYWORD_or / KEYWORD_orelse / KEYWORD_packed
8371 / KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
8372 / KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch / KEYWORD_test
8373 / KEYWORD_threadlocal / KEYWORD_try / KEYWORD_union / KEYWORD_unreachable
8374 / KEYWORD_var / KEYWORD_volatile / KEYWORD_while
8375 {#end_syntax_block#}
8376 {#header_close#}7786 {#header_close#}
8377 {#header_open|Zen#}7787 {#header_open|Zen#}
8378 <ul>7788 <ul>
doc/langref/grammar.peg created+589
...@@ -0,0 +1,589 @@
1Root <- skip ContainerMembers eof
2
3# *** Top level ***
4ContainerMembers <- container_doc_comment? ContainerDeclaration* (ContainerField COMMA)* (ContainerField / ContainerDeclaration*)
5
6ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl
7
8TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block
9
10ComptimeDecl <- KEYWORD_comptime Block
11
12Decl
13 <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)
14 / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON
15 / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl
16
17FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix
18
19VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection?
20
21GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON
22
23ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn (IDENTIFIER COLON / !(IDENTIFIER COLON))? TypeExpr ByteAlign? (EQUAL Expr)?
24
25# *** Block Level ***
26BlockStatement
27 <- Statement
28 / KEYWORD_defer BlockExprStatement
29 / KEYWORD_errdefer BlockExprStatement
30 / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
31
32Statement
33 <- ExprStatement
34 / KEYWORD_suspend BlockExprStatement
35 / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON
36
37ExprStatement
38 <- IfStatement
39 / LabeledStatement
40 / KEYWORD_nosuspend BlockExprStatement
41 / KEYWORD_comptime BlockExpr
42
43IfStatement
44 <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
45 / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
46
47LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)
48
49LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
50
51ForStatement
52 <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )
53 / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement )
54
55WhileStatement
56 <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
57 / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
58
59BlockExprStatement
60 <- BlockExpr
61 / !BlockExpr AssignExpr SEMICOLON
62
63BlockExpr <- BlockLabel? Block
64
65# An assignment or a destructure whose LHS are all lvalue expressions or variable declarations.
66VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON
67
68# *** Expression Level ***
69
70# An assignment or a destructure whose LHS are all lvalue expressions.
71AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)?
72
73SingleAssignExpr <- Expr (AssignOp Expr)?
74
75Expr <- BoolOrExpr
76
77BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
78
79BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
80
81CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
82
83BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
84
85BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
86
87AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
88
89MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
90
91PrefixExpr <- PrefixOp* PrimaryExpr
92
93PrimaryExpr
94 <- AsmExpr
95 / IfExpr
96 / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
97 / KEYWORD_comptime Expr !ExprSuffix
98 / KEYWORD_nosuspend Expr !ExprSuffix
99 / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
100 / KEYWORD_resume Expr !ExprSuffix
101 / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart)
102 / BlockLabel? LoopExpr
103 / Block
104 / CurlySuffixExpr
105
106IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
107
108Block <- LBRACE BlockStatement* RBRACE
109
110LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
111
112ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix
113
114WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
115
116CurlySuffixExpr <- TypeExpr InitList?
117
118InitList
119 <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
120 / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
121 / LBRACE RBRACE
122
123TypeExpr <- PrefixTypeOp* ErrorUnionExpr
124
125ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
126
127SuffixExpr
128 <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
129
130PrimaryTypeExpr
131 <- BUILTINIDENTIFIER FnCallArguments
132 / CHAR_LITERAL
133 / ContainerDecl
134 / DOT IDENTIFIER
135 / DOT InitList
136 / ErrorSetDecl
137 / FLOAT
138 / FnProto
139 / GroupedExpr
140 / LabeledTypeExpr
141 / IDENTIFIER !(COLON LabelableExpr)
142 / IfTypeExpr
143 / INTEGER
144 / KEYWORD_comptime TypeExpr !ExprSuffix
145 / KEYWORD_error DOT IDENTIFIER
146 / KEYWORD_anyframe
147 / KEYWORD_unreachable
148 / STRINGLITERAL
149
150ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
151
152ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
153
154GroupedExpr <- LPAREN Expr RPAREN
155
156IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
157
158LabeledTypeExpr
159 <- BlockLabel Block
160 / BlockLabel? LoopTypeExpr
161 / BlockLabel? SwitchExpr
162
163LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
164
165ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix
166
167WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
168
169SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
170
171# *** Assembly ***
172AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
173
174AsmOutput <- COLON AsmOutputList AsmInput?
175
176AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
177
178AsmInput <- COLON AsmInputList AsmClobbers?
179
180AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN
181
182AsmClobbers <- COLON Expr
183
184# *** Helper grammar ***
185BreakLabel <- COLON IDENTIFIER
186
187BlockLabel <- IDENTIFIER COLON
188
189FieldInit <- DOT IDENTIFIER EQUAL Expr
190
191WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
192
193LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
194
195AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
196
197# Fn specific
198CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
199
200ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime / !KEYWORD_comptime) (IDENTIFIER COLON / !(IDENTIFIER COLON)) ParamType
201
202ParamType
203 <- KEYWORD_anytype
204 / TypeExpr
205
206# Control flow prefixes
207IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
208
209WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
210
211ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload
212
213# Payloads
214Payload <- PIPE IDENTIFIER PIPE
215
216PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
217
218PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
219
220PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE
221
222# Switch specific
223SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr
224
225SwitchCase
226 <- SwitchItem (COMMA SwitchItem)* COMMA?
227 / KEYWORD_else
228
229SwitchItem <- Expr (DOT3 Expr)?
230
231# For specific
232ForArgumentsList <- ForItem (COMMA ForItem)* COMMA?
233
234ForItem <- Expr (DOT2 Expr?)?
235
236# Operators
237AssignOp
238 <- ASTERISKEQUAL
239 / ASTERISKPIPEEQUAL
240 / SLASHEQUAL
241 / PERCENTEQUAL
242 / PLUSEQUAL
243 / PLUSPIPEEQUAL
244 / MINUSEQUAL
245 / MINUSPIPEEQUAL
246 / LARROW2EQUAL
247 / LARROW2PIPEEQUAL
248 / RARROW2EQUAL
249 / AMPERSANDEQUAL
250 / CARETEQUAL
251 / PIPEEQUAL
252 / ASTERISKPERCENTEQUAL
253 / PLUSPERCENTEQUAL
254 / MINUSPERCENTEQUAL
255 / EQUAL
256
257CompareOp
258 <- EQUALEQUAL
259 / EXCLAMATIONMARKEQUAL
260 / LARROW
261 / RARROW
262 / LARROWEQUAL
263 / RARROWEQUAL
264
265BitwiseOp
266 <- AMPERSAND
267 / CARET
268 / PIPE
269 / KEYWORD_orelse
270 / KEYWORD_catch Payload?
271
272BitShiftOp
273 <- LARROW2
274 / RARROW2
275 / LARROW2PIPE
276
277AdditionOp
278 <- PLUS
279 / MINUS
280 / PLUS2
281 / PLUSPERCENT
282 / MINUSPERCENT
283 / PLUSPIPE
284 / MINUSPIPE
285
286MultiplyOp
287 <- PIPE2
288 / ASTERISK
289 / SLASH
290 / PERCENT
291 / ASTERISKPERCENT
292 / ASTERISKPIPE
293
294PrefixOp
295 <- EXCLAMATIONMARK
296 / MINUS
297 / TILDE
298 / MINUSPERCENT
299 / AMPERSAND
300 / KEYWORD_try
301
302PrefixTypeOp
303 <- QUESTIONMARK
304 / KEYWORD_anyframe MINUSRARROW
305 / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
306 / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace? KEYWORD_const? KEYWORD_volatile?
307 / ArrayTypeStart
308
309SuffixOp
310 <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET
311 / DOT IDENTIFIER
312 / DOTASTERISK
313 / DOTQUESTIONMARK
314
315FnCallArguments <- LPAREN ExprList RPAREN
316
317ExprSuffix
318 <- KEYWORD_or
319 / KEYWORD_and
320 / CompareOp
321 / BitwiseOp
322 / BitShiftOp
323 / AdditionOp
324 / MultiplyOp
325 / EXCLAMATIONMARK
326 / SuffixOp
327 / FnCallArguments
328
329LabelableExpr
330 <- Block
331 / SwitchExpr
332 / LoopExpr
333
334# Ptr specific
335SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
336
337SinglePtrTypeStart <- ASTERISK
338
339ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
340
341ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET
342
343# ContainerDecl specific
344ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
345
346ContainerDeclType
347 <- KEYWORD_struct (LPAREN Expr RPAREN)?
348 / KEYWORD_opaque
349 / KEYWORD_enum (LPAREN Expr RPAREN)?
350 / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / !KEYWORD_enum Expr) RPAREN)?
351
352# Alignment
353ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
354
355BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
356
357# Lists
358IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?
359
360SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
361
362AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
363
364AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
365
366ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)?
367
368ExprList <- (Expr COMMA)* Expr?
369
370# *** Tokens ***
371eof <- !.
372bin <- [01]
373bin_ <- '_'? bin
374oct <- [0-7]
375oct_ <- '_'? oct
376hex <- [0-9a-fA-F]
377hex_ <- '_'? hex
378dec <- [0-9]
379dec_ <- '_'? dec
380
381bin_int <- bin bin_*
382oct_int <- oct oct_*
383dec_int <- dec dec_*
384hex_int <- hex hex_*
385
386ox80_oxBF <- [\200-\277]
387oxF4 <- '\364'
388ox80_ox8F <- [\200-\217]
389oxF1_oxF3 <- [\361-\363]
390oxF0 <- '\360'
391ox90_0xBF <- [\220-\277]
392oxEE_oxEF <- [\356-\357]
393oxED <- '\355'
394ox80_ox9F <- [\200-\237]
395oxE1_oxEC <- [\341-\354]
396oxE0 <- '\340'
397oxA0_oxBF <- [\240-\277]
398oxC2_oxDF <- [\302-\337]
399
400# From https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/
401# First Byte Second Byte Third Byte Fourth Byte
402# [0x00,0x7F]
403# [0xC2,0xDF] [0x80,0xBF]
404# 0xE0 [0xA0,0xBF] [0x80,0xBF]
405# [0xE1,0xEC] [0x80,0xBF] [0x80,0xBF]
406# 0xED [0x80,0x9F] [0x80,0xBF]
407# [0xEE,0xEF] [0x80,0xBF] [0x80,0xBF]
408# 0xF0 [0x90,0xBF] [0x80,0xBF] [0x80,0xBF]
409# [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF]
410# 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF]
411
412multibyte_utf8 <-
413 oxF4 ox80_ox8F ox80_oxBF ox80_oxBF
414 / oxF1_oxF3 ox80_oxBF ox80_oxBF ox80_oxBF
415 / oxF0 ox90_0xBF ox80_oxBF ox80_oxBF
416 / oxEE_oxEF ox80_oxBF ox80_oxBF
417 / oxED ox80_ox9F ox80_oxBF
418 / oxE1_oxEC ox80_oxBF ox80_oxBF
419 / oxE0 oxA0_oxBF ox80_oxBF
420 / oxC2_oxDF ox80_oxBF
421
422non_control_ascii <- [\040-\176]
423non_control_utf8 <- [\040-\377]
424
425char_escape
426 <- "\\x" hex hex
427 / "\\u{" hex+ "}"
428 / "\\" [nr\\t'"]
429char_char
430 <- multibyte_utf8
431 / char_escape
432 / ![\\'\n] non_control_ascii
433
434string_char
435 <- multibyte_utf8
436 / char_escape
437 / ![\\"\n] non_control_ascii
438
439container_doc_comment <- ('//!' non_control_utf8* [ \n]* skip)+
440doc_comment <- ('///' non_control_utf8* [ \n]* skip)+
441line_comment <- '//' ![!/] non_control_utf8* / '////' non_control_utf8*
442line_string <- '\\\\' non_control_utf8* [ \n]*
443skip <- ([ \n] / line_comment)*
444
445CHAR_LITERAL <- ['] char_char ['] skip
446FLOAT
447 <- '0x' hex_int '.' hex_int ([pP] [-+]? dec_int)? skip
448 / dec_int '.' dec_int ([eE] [-+]? dec_int)? skip
449 / '0x' hex_int [pP] [-+]? dec_int skip
450 / dec_int [eE] [-+]? dec_int skip
451INTEGER
452 <- '0b' bin_int skip
453 / '0o' oct_int skip
454 / '0x' hex_int skip
455 / dec_int skip
456STRINGLITERALSINGLE <- ["] string_char* ["] skip
457STRINGLITERAL
458 <- STRINGLITERALSINGLE
459 / (line_string skip)+
460IDENTIFIER
461 <- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
462 / '@' STRINGLITERALSINGLE
463BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip
464
465
466AMPERSAND <- '&' ![=] skip
467AMPERSANDEQUAL <- '&=' skip
468ASTERISK <- '*' ![%=|] skip
469ASTERISKEQUAL <- '*=' skip
470ASTERISKPERCENT <- '*%' ![=] skip
471ASTERISKPERCENTEQUAL <- '*%=' skip
472ASTERISKPIPE <- '*|' ![=] skip
473ASTERISKPIPEEQUAL <- '*|=' skip
474CARET <- '^' ![=] skip
475CARETEQUAL <- '^=' skip
476COLON <- ':' skip
477COMMA <- ',' skip
478DOT <- '.' ![*.?] skip
479DOT2 <- '..' ![.] skip
480DOT3 <- '...' skip
481DOTASTERISK <- '.*' skip
482DOTQUESTIONMARK <- '.?' skip
483EQUAL <- '=' ![>=] skip
484EQUALEQUAL <- '==' skip
485EQUALRARROW <- '=>' skip
486EXCLAMATIONMARK <- '!' ![=] skip
487EXCLAMATIONMARKEQUAL <- '!=' skip
488LARROW <- '<' ![<=] skip
489LARROW2 <- '<<' ![=|] skip
490LARROW2EQUAL <- '<<=' skip
491LARROW2PIPE <- '<<|' ![=] skip
492LARROW2PIPEEQUAL <- '<<|=' skip
493LARROWEQUAL <- '<=' skip
494LBRACE <- '{' skip
495LBRACKET <- '[' skip
496LPAREN <- '(' skip
497MINUS <- '-' ![%=>|] skip
498MINUSEQUAL <- '-=' skip
499MINUSPERCENT <- '-%' ![=] skip
500MINUSPERCENTEQUAL <- '-%=' skip
501MINUSPIPE <- '-|' ![=] skip
502MINUSPIPEEQUAL <- '-|=' skip
503MINUSRARROW <- '->' skip
504PERCENT <- '%' ![=] skip
505PERCENTEQUAL <- '%=' skip
506PIPE <- '|' ![|=] skip
507PIPE2 <- '||' skip
508PIPEEQUAL <- '|=' skip
509PLUS <- '+' ![%+=|] skip
510PLUS2 <- '++' skip
511PLUSEQUAL <- '+=' skip
512PLUSPERCENT <- '+%' ![=] skip
513PLUSPERCENTEQUAL <- '+%=' skip
514PLUSPIPE <- '+|' ![=] skip
515PLUSPIPEEQUAL <- '+|=' skip
516LETTERC <- 'c' skip
517QUESTIONMARK <- '?' skip
518RARROW <- '>' ![>=] skip
519RARROW2 <- '>>' ![=] skip
520RARROW2EQUAL <- '>>=' skip
521RARROWEQUAL <- '>=' skip
522RBRACE <- '}' skip
523RBRACKET <- ']' skip
524RPAREN <- ')' skip
525SEMICOLON <- ';' skip
526SLASH <- '/' ![=] skip
527SLASHEQUAL <- '/=' skip
528TILDE <- '~' skip
529
530end_of_word <- ![a-zA-Z0-9_] skip
531KEYWORD_addrspace <- 'addrspace' end_of_word
532KEYWORD_align <- 'align' end_of_word
533KEYWORD_allowzero <- 'allowzero' end_of_word
534KEYWORD_and <- 'and' end_of_word
535KEYWORD_anyframe <- 'anyframe' end_of_word
536KEYWORD_anytype <- 'anytype' end_of_word
537KEYWORD_asm <- 'asm' end_of_word
538KEYWORD_break <- 'break' end_of_word
539KEYWORD_callconv <- 'callconv' end_of_word
540KEYWORD_catch <- 'catch' end_of_word
541KEYWORD_comptime <- 'comptime' end_of_word
542KEYWORD_const <- 'const' end_of_word
543KEYWORD_continue <- 'continue' end_of_word
544KEYWORD_defer <- 'defer' end_of_word
545KEYWORD_else <- 'else' end_of_word
546KEYWORD_enum <- 'enum' end_of_word
547KEYWORD_errdefer <- 'errdefer' end_of_word
548KEYWORD_error <- 'error' end_of_word
549KEYWORD_export <- 'export' end_of_word
550KEYWORD_extern <- 'extern' end_of_word
551KEYWORD_fn <- 'fn' end_of_word
552KEYWORD_for <- 'for' end_of_word
553KEYWORD_if <- 'if' end_of_word
554KEYWORD_inline <- 'inline' end_of_word
555KEYWORD_noalias <- 'noalias' end_of_word
556KEYWORD_nosuspend <- 'nosuspend' end_of_word
557KEYWORD_noinline <- 'noinline' end_of_word
558KEYWORD_opaque <- 'opaque' end_of_word
559KEYWORD_or <- 'or' end_of_word
560KEYWORD_orelse <- 'orelse' end_of_word
561KEYWORD_packed <- 'packed' end_of_word
562KEYWORD_pub <- 'pub' end_of_word
563KEYWORD_resume <- 'resume' end_of_word
564KEYWORD_return <- 'return' end_of_word
565KEYWORD_linksection <- 'linksection' end_of_word
566KEYWORD_struct <- 'struct' end_of_word
567KEYWORD_suspend <- 'suspend' end_of_word
568KEYWORD_switch <- 'switch' end_of_word
569KEYWORD_test <- 'test' end_of_word
570KEYWORD_threadlocal <- 'threadlocal' end_of_word
571KEYWORD_try <- 'try' end_of_word
572KEYWORD_union <- 'union' end_of_word
573KEYWORD_unreachable <- 'unreachable' end_of_word
574KEYWORD_var <- 'var' end_of_word
575KEYWORD_volatile <- 'volatile' end_of_word
576KEYWORD_while <- 'while' end_of_word
577
578keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and
579 / KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm
580 / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch
581 / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer
582 / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export
583 / KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if
584 / KEYWORD_inline / KEYWORD_noalias / KEYWORD_nosuspend / KEYWORD_noinline
585 / KEYWORD_opaque / KEYWORD_or / KEYWORD_orelse / KEYWORD_packed
586 / KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
587 / KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch / KEYWORD_test
588 / KEYWORD_threadlocal / KEYWORD_try / KEYWORD_union / KEYWORD_unreachable
589 / KEYWORD_var / KEYWORD_volatile / KEYWORD_while
tools/docgen.zig+28-4
...@@ -25,6 +25,7 @@ const usage =...@@ -25,6 +25,7 @@ const usage =
25 \\25 \\
26 \\Options:26 \\Options:
27 \\ --code-dir dir Path to directory containing code example outputs27 \\ --code-dir dir Path to directory containing code example outputs
28 \\ --grammar file Path to the PEG grammar definition
28 \\ -h, --help Print this help and exit29 \\ -h, --help Print this help and exit
29 \\30 \\
30;31;
...@@ -37,6 +38,7 @@ pub fn main(init: std.process.Init) !void {...@@ -37,6 +38,7 @@ pub fn main(init: std.process.Init) !void {
37 if (!args_it.skip()) @panic("expected self arg");38 if (!args_it.skip()) @panic("expected self arg");
3839
39 var opt_code_dir: ?[]const u8 = null;40 var opt_code_dir: ?[]const u8 = null;
41 var opt_grammar: ?[]const u8 = null;
40 var opt_input: ?[]const u8 = null;42 var opt_input: ?[]const u8 = null;
41 var opt_output: ?[]const u8 = null;43 var opt_output: ?[]const u8 = null;
4244
...@@ -51,6 +53,12 @@ pub fn main(init: std.process.Init) !void {...@@ -51,6 +53,12 @@ pub fn main(init: std.process.Init) !void {
51 } else {53 } else {
52 fatal("expected parameter after --code-dir", .{});54 fatal("expected parameter after --code-dir", .{});
53 }55 }
56 } else if (mem.eql(u8, arg, "--grammar")) {
57 if (args_it.next()) |param| {
58 opt_grammar = param;
59 } else {
60 fatal("expected parameter after --grammar", .{});
61 }
54 } else {62 } else {
55 fatal("unrecognized option: '{s}'", .{arg});63 fatal("unrecognized option: '{s}'", .{arg});
56 }64 }
...@@ -65,6 +73,7 @@ pub fn main(init: std.process.Init) !void {...@@ -65,6 +73,7 @@ pub fn main(init: std.process.Init) !void {
65 const input_path = opt_input orelse fatal("missing input file", .{});73 const input_path = opt_input orelse fatal("missing input file", .{});
66 const output_path = opt_output orelse fatal("missing output file", .{});74 const output_path = opt_output orelse fatal("missing output file", .{});
67 const code_dir_path = opt_code_dir orelse fatal("missing --code-dir argument", .{});75 const code_dir_path = opt_code_dir orelse fatal("missing --code-dir argument", .{});
76 const grammar_path = opt_grammar orelse fatal("missing --grammar argument", .{});
6877
69 var in_file = try Dir.cwd().openFile(io, input_path, .{});78 var in_file = try Dir.cwd().openFile(io, input_path, .{});
70 defer in_file.close(io);79 defer in_file.close(io);
...@@ -82,13 +91,16 @@ pub fn main(init: std.process.Init) !void {...@@ -82,13 +91,16 @@ pub fn main(init: std.process.Init) !void {
82 };91 };
83 defer code_dir.root_dir.handle.close(io);92 defer code_dir.root_dir.handle.close(io);
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
85 var in_file_reader = in_file.reader(io, &.{});97 var in_file_reader = in_file.reader(io, &.{});
86 const input_file_bytes = try in_file_reader.interface.allocRemaining(arena, .limited(max_doc_file_size));98 const input_file_bytes = try in_file_reader.interface.allocRemaining(arena, .limited(max_doc_file_size));
8799
88 var tokenizer = Tokenizer.init(input_path, input_file_bytes);100 var tokenizer = Tokenizer.init(input_path, input_file_bytes);
89 var toc = try genToc(arena, &tokenizer);101 var toc = try genToc(arena, &tokenizer);
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);
92 try out_file_writer.end();104 try out_file_writer.end();
93}105}
94106
...@@ -326,6 +338,7 @@ const Node = union(enum) {...@@ -326,6 +338,7 @@ const Node = union(enum) {
326 HeaderOpen: HeaderOpen,338 HeaderOpen: HeaderOpen,
327 SeeAlso: []const SeeAlsoItem,339 SeeAlso: []const SeeAlsoItem,
328 Code: Code,340 Code: Code,
341 Grammar,
329 Link: Link,342 Link: Link,
330 InlineSyntax: Token,343 InlineSyntax: Token,
331 Shell: Token,344 Shell: Token,
...@@ -513,6 +526,9 @@ fn genToc(gpa: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -513,6 +526,9 @@ fn genToc(gpa: Allocator, tokenizer: *Tokenizer) !Toc {
513 .token = name_tok,526 .token = name_tok,
514 },527 },
515 });528 });
529 } else if (mem.eql(u8, tag_name, "grammar")) {
530 _ = try eatToken(tokenizer, .bracket_close);
531 try nodes.append(.Grammar);
516 } else if (mem.eql(u8, tag_name, "syntax")) {532 } else if (mem.eql(u8, tag_name, "syntax")) {
517 _ = try eatToken(tokenizer, .bracket_close);533 _ = try eatToken(tokenizer, .bracket_close);
518 const content_tok = try eatToken(tokenizer, .content);534 const content_tok = try eatToken(tokenizer, .content);
...@@ -924,14 +940,14 @@ fn tokenizeAndPrint(...@@ -924,14 +940,14 @@ fn tokenizeAndPrint(
924 return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src);940 return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src);
925}941}
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 {
928 const source_type = @tagName(syntax_block.source_type);944 const source_type = @tagName(syntax_block.source_type);
929945
930 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name });946 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name });
931 switch (syntax_block.source_type) {947 switch (syntax_block.source_type) {
932 .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token),948 .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token),
933 else => {949 else => {
934 const raw_source = docgen_tokenizer.buffer[syntax_block.source_token.start..syntax_block.source_token.end];950 const raw_source = content orelse docgen_tokenizer.buffer[syntax_block.source_token.start..syntax_block.source_token.end];
935 const trimmed_raw_source = mem.trim(u8, raw_source, " \r\n");951 const trimmed_raw_source = mem.trim(u8, raw_source, " \r\n");
936952
937 try out.writeAll("<code>");953 try out.writeAll("<code>");
...@@ -995,6 +1011,7 @@ fn genHtml(...@@ -995,6 +1011,7 @@ fn genHtml(
995 tokenizer: *Tokenizer,1011 tokenizer: *Tokenizer,
996 toc: *Toc,1012 toc: *Toc,
997 code_dir: Path,1013 code_dir: Path,
1014 grammar: []const u8,
998 out: *Writer,1015 out: *Writer,
999) !void {1016) !void {
1000 for (toc.nodes) |node| {1017 for (toc.nodes) |node| {
...@@ -1042,7 +1059,7 @@ fn genHtml(...@@ -1042,7 +1059,7 @@ fn genHtml(
1042 try printShell(out, raw_shell_content, true);1059 try printShell(out, raw_shell_content, true);
1043 },1060 },
1044 .SyntaxBlock => |syntax_block| {1061 .SyntaxBlock => |syntax_block| {
1045 try printSourceBlock(allocator, tokenizer, out, syntax_block);1062 try printSourceBlock(allocator, tokenizer, out, syntax_block, null);
1046 },1063 },
1047 .Code => |code| {1064 .Code => |code| {
1048 const out_basename = try std.fmt.allocPrint(allocator, "{s}.out", .{1065 const out_basename = try std.fmt.allocPrint(allocator, "{s}.out", .{
...@@ -1062,6 +1079,13 @@ fn genHtml(...@@ -1062,6 +1079,13 @@ fn genHtml(
10621079
1063 try out.writeAll(contents);1080 try out.writeAll(contents);
1064 },1081 },
1082 .Grammar => {
1083 try printSourceBlock(allocator, tokenizer, out, .{
1084 .source_type = .peg,
1085 .name = "grammar.peg",
1086 .source_token = undefined,
1087 }, grammar);
1088 },
1065 }1089 }
1066 }1090 }
1067}1091}