Root <- container_doc_comment? container_members eof

container_members <- container_declarations (container_field COMMA)* (container_field / container_declarations)

container_declarations
    <- test_decl container_declarations
     / top_level_comptime container_declarations
     / doc_comment? KEYWORD_PUB? top_level_decl container_declarations
     / end_of_word

test_decl <- doc_comment? KEYWORD_TEST block

top_level_comptime <- doc_comment? KEYWORD_COMPTIME block_expr

top_level_decl
    <- (KEYWORD_EXPORT / KEYWORD_EXTERN / (KEYWORD_INLINE / KEYWORD_NOINLINE))? fn_proto (SEMICOLON / block)
     / (KEYWORD_EXPORT / KEYWORD_EXTERN )? KEYWORD_THREADLOCAL? var_decl
     / KEYWORD_USINGNAMESPACE expr SEMICOLON

fn_proto <- KEYWORD_FN IDENTIFIER? LPAREN param_decl_list RPAREN byte_align? link_section? call_conv? EXCLAMATIONMARK? type_expr

var_decl <- (KEYWORD_CONST / KEYWORD_VAR) IDENTIFIER (COLON type_expr)? byte_align? link_section? (EQUAL expr)? SEMICOLON

container_field <- doc_comment? KEYWORD_COMPTIME? IDENTIFIER (COLON (KEYWORD_ANYTYPE / type_expr) byte_align?)? (EQUAL expr)?

statement
    <- KEYWORD_COMPTIME? var_decl
     / KEYWORD_COMPTIME block_expr_satement
     / KEYWORD_NOSUSPEND block_expr_satement
     / KEYWORD_SUSPEND block_expr_satement
     / KEYWORD_DEFER block_expr_satement
     / KEYWORD_ERRDEFER payload? block_expr_satement
     / if_statement
     / labeled_statement
     / switch_expr
     / assign_expr SEMICOLON

if_statement
    <- if_prefix block_expr ( KEYWORD_ELSE payload? statement )?
     / if_prefix assign_expr ( SEMICOLON / KEYWORD_ELSE payload? statement )

labeled_statement <- block_label? (block / loop_statement)

loop_statement <- KEYWORD_INLINE? (for_statement / while_statement)

for_statement
    <- for_prefix block_expr ( KEYWORD_ELSE statement )?
     / for_prefix assign_expr ( SEMICOLON / KEYWORD_ELSE statement )

while_statement
    <- WhilePrefix block_expr ( KEYWORD_ELSE payload? statement )?
     / WhilePrefix assign_expr ( SEMICOLON / KEYWORD_ELSE payload? statement )

block_expr_satement
    <- block_expr
     / assign_expr SEMICOLON

block_expr <- block_label? block

assign_expr <- expr (AssignOp expr)?

expr <- bool_or_expr

bool_or_expr <- BoolAndExpr (KEYWORD_OR BoolAndExpr)*

BoolAndExpr <- CompareExpr (KEYWORD_AND CompareExpr)*

CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?

BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*

BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*

AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*

MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*

PrefixExpr <- PrefixOp* PrimaryExpr

PrimaryExpr
    <- AsmExpr
     / IfExpr
     / KEYWORD_BREAK BreakLabel? expr?
     / KEYWORD_COMPTIME expr
     / KEYWORD_NOSUSPEND expr
     / KEYWORD_CONTINUE BreakLabel?
     / KEYWORD_RESUME expr
     / KEYWORD_RETURN expr?
     / block_label? LoopExpr
     / block
     / CurlySuffixExpr

IfExpr <- if_prefix expr (KEYWORD_ELSE payload? expr)?

block <- LBRACE statement* RBRACE

LoopExpr <- KEYWORD_INLINE? (ForExpr / WhileExpr)

ForExpr <- for_prefix expr (KEYWORD_ELSE expr)?

WhileExpr <- WhilePrefix expr (KEYWORD_ELSE payload? expr)?

CurlySuffixExpr <- type_expr InitList?

InitList
    <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
     / LBRACE expr (COMMA expr)* COMMA? RBRACE
     / LBRACE RBRACE

type_expr <- PrefixTypeOp* ErrorUnionExpr

ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK type_expr)?

SuffixExpr
    <- KEYWORD_ASYNC PrimaryTypeExpr SuffixOp* FnCallArguments
     / PrimaryTypeExpr (SuffixOp / FnCallArguments)*

PrimaryTypeExpr
    <- BUILTINIDENTIFIER FnCallArguments
     / CHAR_LITERAL
     / ContainerDecl
     / DOT IDENTIFIER
     / DOT InitList
     / ErrorSetDecl
     / FLOAT
     / fn_proto
     / GroupedExpr
     / LabeledTypeExpr
     / IDENTIFIER
     / IfTypeExpr
     / INTEGER
     / KEYWORD_COMPTIME type_expr
     / KEYWORD_ERROR DOT IDENTIFIER
     / KEYWORD_ANYFRAME
     / KEYWORD_UNREACHABLE
     / STRINGLITERAL
     / switch_expr

ContainerDecl <- (KEYWORD_EXTERN / KEYWORD_PACKED)? ContainerDeclAuto

ErrorSetDecl <- KEYWORD_ERROR LBRACE IdentifierList RBRACE

GroupedExpr <- LPAREN expr RPAREN

IfTypeExpr <- if_prefix type_expr (KEYWORD_ELSE payload? type_expr)?

LabeledTypeExpr
    <- block_label block
     / block_label? LoopTypeExpr

LoopTypeExpr <- KEYWORD_INLINE? (ForTypeExpr / WhileTypeExpr)

ForTypeExpr <- for_prefix type_expr (KEYWORD_ELSE type_expr)?

WhileTypeExpr <- WhilePrefix type_expr (KEYWORD_ELSE payload? type_expr)?

switch_expr <- KEYWORD_SWITCH LPAREN expr RPAREN LBRACE switch_prong_list RBRACE

AsmExpr <- KEYWORD_ASM KEYWORD_VOLATILE? LPAREN expr AsmOutput? RPAREN

AsmOutput <- COLON AsmOutputList AsmInput?

AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW type_expr / IDENTIFIER) RPAREN

AsmInput <- COLON AsmInputList AsmClobbers?

AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN expr RPAREN

AsmClobbers <- COLON StringList

BreakLabel <- COLON IDENTIFIER

block_label <- IDENTIFIER COLON

FieldInit <- DOT IDENTIFIER EQUAL expr

while_continue_expr <- COLON LPAREN assign_expr RPAREN

link_section <- KEYWORD_LINKSECTION LPAREN expr RPAREN

call_conv <- KEYWORD_CALLCONV LPAREN expr RPAREN

param_decl
    <- doc_comment? (KEYWORD_NOALIAS / KEYWORD_COMPTIME)? (IDENTIFIER COLON)? param_type
     / DOT3

param_type
    <- KEYWORD_ANYTYPE
     / type_expr

if_prefix <- KEYWORD_IF LPAREN expr RPAREN PtrPayload?

WhilePrefix <- KEYWORD_WHILE LPAREN expr RPAREN PtrPayload? while_continue_expr?

for_prefix <- KEYWORD_FOR LPAREN expr RPAREN ptr_index_payload

payload <- PIPE IDENTIFIER PIPE

PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE

ptr_index_payload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE


SwitchProng <- SwitchCase EQUALRARROW PtrPayload? assign_expr

SwitchCase
    <- SwitchItem (COMMA SwitchItem)* COMMA?
     / KEYWORD_ELSE

SwitchItem <- expr (DOT3 expr)?

AssignOp
    <- ASTERISKEQUAL
     / SLASHEQUAL
     / PERCENTEQUAL
     / PLUSEQUAL
     / MINUSEQUAL
     / LARROW2EQUAL
     / RARROW2EQUAL
     / AMPERSANDEQUAL
     / CARETEQUAL
     / PIPEEQUAL
     / ASTERISKPERCENTEQUAL
     / PLUSPERCENTEQUAL
     / MINUSPERCENTEQUAL
     / EQUAL

CompareOp
    <- EQUALEQUAL
     / EXCLAMATIONMARKEQUAL
     / LARROW
     / RARROW
     / LARROWEQUAL
     / RARROWEQUAL

BitwiseOp
    <- AMPERSAND
     / CARET
     / PIPE
     / KEYWORD_ORELSE
     / KEYWORD_CATCH payload?

BitShiftOp
    <- LARROW2
     / RARROW2

AdditionOp
    <- PLUS
     / MINUS
     / PLUS2
     / PLUSPERCENT
     / MINUSPERCENT

MultiplyOp
    <- PIPE2
     / ASTERISK
     / SLASH
     / PERCENT
     / ASTERISK2
     / ASTERISKPERCENT

PrefixOp
    <- EXCLAMATIONMARK
     / MINUS
     / TILDE
     / MINUSPERCENT
     / AMPERSAND
     / KEYWORD_TRY
     / KEYWORD_AWAIT

PrefixTypeOp
    <- QUESTIONMARK
     / KEYWORD_ANYFRAME MINUSRARROW
     / SliceTypeStart (byte_align / KEYWORD_CONST / KEYWORD_VOLATILE / KEYWORD_ALLOWZERO)*
     / PtrTypeStart (KEYWORD_ALIGN LPAREN expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_CONST / KEYWORD_VOLATILE / KEYWORD_ALLOWZERO)*
     / ArrayTypeStart

SuffixOp
    <- LBRACKET expr (DOT2 (expr? (COLON expr)?)?)? RBRACKET
     / DOT IDENTIFIER
     / DOTASTERISK
     / DOTQUESTIONMARK

FnCallArguments <- LPAREN expr_list RPAREN

SliceTypeStart <- LBRACKET (COLON expr)? RBRACKET

PtrTypeStart
    <- ASTERISK
     / ASTERISK2
     / LBRACKET ASTERISK (LETTERC / COLON expr)? RBRACKET

ArrayTypeStart <- LBRACKET expr (COLON expr)? RBRACKET

ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? container_members RBRACE

ContainerDeclType
    <- KEYWORD_STRUCT
     / KEYWORD_OPAQUE
     / KEYWORD_ENUM (LPAREN expr RPAREN)?
     / KEYWORD_UNION (LPAREN (KEYWORD_ENUM (LPAREN expr RPAREN)? / expr) RPAREN)?

byte_align <- KEYWORD_ALIGN LPAREN expr RPAREN

IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?

switch_prong_list <- (SwitchProng COMMA)* SwitchProng?

AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?

AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?

StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?

param_decl_list <- (param_decl COMMA)* param_decl?

expr_list <- (expr COMMA)* expr?

eof <- !.
bin <- [01]
bin_ <- '_'? bin
oct <- [0-7]
oct_ <- '_'? oct
hex <- [0-9a-fA-F]
hex_ <- '_'? hex
dec <- [0-9]
dec_ <- '_'? dec

bin_int <- bin bin_*
oct_int <- oct oct_*
dec_int <- dec dec_*
hex_int <- hex hex_*

ox80_oxBF <- [\200-\277]
oxF4 <- '\364'
ox80_ox8F <- [\200-\217]
oxF1_oxF3 <- [\361-\363]
oxF0 <- '\360'
ox90_0xBF <- [\220-\277]
oxEE_oxEF <- [\356-\357]
oxED <- '\355'
ox80_ox9F <- [\200-\237]
oxE1_oxEC <- [\341-\354]
oxE0 <- '\340'
oxA0_oxBF <- [\240-\277]
oxC2_oxDF <- [\302-\337]

mb_utf8_literal <-
       oxF4      ox80_ox8F ox80_oxBF ox80_oxBF
     / oxF1_oxF3 ox80_oxBF ox80_oxBF ox80_oxBF
     / oxF0      ox90_0xBF ox80_oxBF ox80_oxBF
     / oxEE_oxEF ox80_oxBF ox80_oxBF
     / oxED      ox80_ox9F ox80_oxBF
     / oxE1_oxEC ox80_oxBF ox80_oxBF
     / oxE0      oxA0_oxBF ox80_oxBF
     / oxC2_oxDF ox80_oxBF

ascii_char_not_nl_slash_squote <- [\000-\011\013-\046-\050-\133\135-\177]

char_escape
    <- "\\x" hex hex
     / "\\u{" hex+ "}"
     / "\\" [nr\\t'"]
char_char
    <- mb_utf8_literal
     / char_escape
     / ascii_char_not_nl_slash_squote

string_char
    <- char_escape
     / [^\\"\n]

container_doc_comment <- ('//!' [^\n]* [ \n]*)+
doc_comment <- ('///' [^\n]* [ \n]*)+
line_comment <- '//' ![!/][^\n]* / '////' [^\n]*
line_string <- ("\\\\" [^\n]* [ \n]*)+

CHAR_LITERAL <- "'" char_char "'" 
FLOAT
    <- "0x" hex_int "." hex_int ([pP] [-+]? dec_int)? 
     /      dec_int "." dec_int ([eE] [-+]? dec_int)? 
     / "0x" hex_int [pP] [-+]? dec_int 
     /      dec_int [eE] [-+]? dec_int 
INTEGER
    <- "0b" bin_int 
     / "0o" oct_int 
     / "0x" hex_int 
     /      dec_int   
STRINGLITERALSINGLE <- '"' string_char* '"'
STRINGLITERAL
    <- STRINGLITERALSINGLE
     / (line_string)+
IDENTIFIER
    <- !KEYWORD [A-Za-z_] [A-Za-z0-9_]* 
BUILTINIDENTIFIER <- "@"[A-Za-z_][A-Za-z0-9_]* 


AMPERSAND            <- '&'      ![=]      
AMPERSANDEQUAL       <- '&='               
ASTERISK             <- '*'      ![*%=]    
ASTERISK2            <- '**'               
ASTERISKEQUAL        <- '*='               
ASTERISKPERCENT      <- '*%'     ![=]      
ASTERISKPERCENTEQUAL <- '*%='              
CARET                <- '^'      ![=]      
CARETEQUAL           <- '^='               
COLON                <- ':'                
COMMA                <- ','                
DOT                  <- '.'      ![*.?]    
DOT2                 <- '..'     ![.]      
DOT3                 <- '...'              
DOTASTERISK          <- '.*'               
DOTQUESTIONMARK      <- '.?'               
EQUAL                <- '='      ![>=]     
EQUALEQUAL           <- '=='               
EQUALRARROW          <- '=>'               
EXCLAMATIONMARK      <- '!'      ![=]      
EXCLAMATIONMARKEQUAL <- '!='               
LARROW               <- '<'      ![<=]     
LARROW2              <- '<<'     ![=]      
LARROW2EQUAL         <- '<<='              
LARROWEQUAL          <- '<='               
LBRACE               <- '{'                
LBRACKET             <- '['                
LPAREN               <- '('                
MINUS                <- '-'      ![%=>]    
MINUSEQUAL           <- '-='               
MINUSPERCENT         <- '-%'     ![=]      
MINUSPERCENTEQUAL    <- '-%='              
MINUSRARROW          <- '->'               
PERCENT              <- '%'      ![=]      
PERCENTEQUAL         <- '%='               
PIPE                 <- '|'      ![|=]     
PIPE2                <- '||'               
PIPEEQUAL            <- '|='               
PLUS                 <- '+'      ![%+=]    
PLUS2                <- '++'               
PLUSEQUAL            <- '+='               
PLUSPERCENT          <- '+%'     ![=]      
PLUSPERCENTEQUAL     <- '+%='              
LETTERC              <- 'c'                
QUESTIONMARK         <- '?'                
RARROW               <- '>'      ![>=]     
RARROW2              <- '>>'     ![=]      
RARROW2EQUAL         <- '>>='              
RARROWEQUAL          <- '>='               
RBRACE               <- '}'                
RBRACKET             <- ']'                
RPAREN               <- ')'                
SEMICOLON            <- ';'                
SLASH                <- '/'      ![=]      
SLASHEQUAL           <- '/='               
TILDE                <- '~'                

fragment end_of_word <- ![a-zA-Z0-9_] 
KEYWORD_ALIGN       <- 'align'       end_of_word
KEYWORD_ALLOWZERO   <- 'allowzero'   end_of_word
KEYWORD_AND         <- 'and'         end_of_word
KEYWORD_ANYFRAME    <- 'anyframe'    end_of_word
KEYWORD_ANYTYPE     <- 'anytype'     end_of_word
KEYWORD_ASM         <- 'asm'         end_of_word
KEYWORD_ASYNC       <- 'async'       end_of_word
KEYWORD_AWAIT       <- 'await'       end_of_word
KEYWORD_BREAK       <- 'break'       end_of_word
KEYWORD_CALLCONV    <- 'callconv'    end_of_word
KEYWORD_CATCH       <- 'catch'       end_of_word
KEYWORD_COMPTIME    <- 'comptime'    end_of_word
KEYWORD_CONST       <- 'const'       end_of_word
KEYWORD_CONTINUE    <- 'continue'    end_of_word
KEYWORD_DEFER       <- 'defer'       end_of_word
KEYWORD_ELSE        <- 'else'        end_of_word
KEYWORD_ENUM        <- 'enum'        end_of_word
KEYWORD_ERRDEFER    <- 'errdefer'    end_of_word
KEYWORD_ERROR       <- 'error'       end_of_word
KEYWORD_EXPORT      <- 'export'      end_of_word
KEYWORD_EXTERN      <- 'extern'      end_of_word
KEYWORD_FN          <- 'fn'          end_of_word
KEYWORD_FOR         <- 'for'         end_of_word
KEYWORD_IF          <- 'if'          end_of_word
KEYWORD_INLINE      <- 'inline'      end_of_word
KEYWORD_NOALIAS     <- 'noalias'     end_of_word
KEYWORD_NOSUSPEND   <- 'nosuspend'   end_of_word
KEYWORD_NOINLINE    <- 'noinline'    end_of_word
KEYWORD_OPAQUE      <- 'opaque'      end_of_word
KEYWORD_OR          <- 'or'          end_of_word
KEYWORD_ORELSE      <- 'orelse'      end_of_word
KEYWORD_PACKED      <- 'packed'      end_of_word
KEYWORD_PUB         <- 'pub'         end_of_word
KEYWORD_RESUME      <- 'resume'      end_of_word
KEYWORD_RETURN      <- 'return'      end_of_word
KEYWORD_LINKSECTION <- 'linksection' end_of_word
KEYWORD_STRUCT      <- 'struct'      end_of_word
KEYWORD_SUSPEND     <- 'suspend'     end_of_word
KEYWORD_SWITCH      <- 'switch'      end_of_word
KEYWORD_TEST        <- 'test'        end_of_word
KEYWORD_THREADLOCAL <- 'threadlocal' end_of_word
KEYWORD_TRY         <- 'try'         end_of_word
KEYWORD_UNION       <- 'union'       end_of_word
KEYWORD_UNREACHABLE <- 'unreachable' end_of_word
KEYWORD_USINGNAMESPACE <- 'usingnamespace' end_of_word
KEYWORD_VAR         <- 'var'         end_of_word
KEYWORD_VOLATILE    <- 'volatile'    end_of_word
KEYWORD_WHILE       <- 'while'       end_of_word

KEYWORD <- KEYWORD_ALIGN / KEYWORD_ALLOWZERO / KEYWORD_AND / KEYWORD_ANYFRAME
         / KEYWORD_ANYTYPE / KEYWORD_ASM / KEYWORD_ASYNC / KEYWORD_AWAIT
         / KEYWORD_BREAK / KEYWORD_CALLCONV / KEYWORD_CATCH / KEYWORD_COMPTIME
         / KEYWORD_CONST / KEYWORD_CONTINUE / KEYWORD_DEFER / KEYWORD_ELSE
         / KEYWORD_ENUM / KEYWORD_ERRDEFER / KEYWORD_ERROR / KEYWORD_EXPORT
         / KEYWORD_EXTERN / KEYWORD_FN / KEYWORD_FOR / KEYWORD_IF
         / KEYWORD_INLINE / KEYWORD_NOALIAS / KEYWORD_NOSUSPEND / KEYWORD_NOINLINE
         / KEYWORD_OPAQUE / KEYWORD_OR / KEYWORD_ORELSE / KEYWORD_PACKED
         / KEYWORD_PUB / KEYWORD_RESUME / KEYWORD_RETURN / KEYWORD_LINKSECTION
         / KEYWORD_STRUCT / KEYWORD_SUSPEND / KEYWORD_SWITCH / KEYWORD_TEST
         / KEYWORD_THREADLOCAL / KEYWORD_TRY / KEYWORD_UNION / KEYWORD_UNREACHABLE
         / KEYWORD_USINGNAMESPACE / KEYWORD_VAR / KEYWORD_VOLATILE / KEYWORD_WHILE