Root = { SOI ~ ContainerMembers ~ EOI } ContainerMembers = { ExternalHeaderList ~ (ContainerDeclaration ~ (COMMA | SEMICOLON)*)* } HeaderItem = { (AT | SHARP) ~ IDENTIFIER ~ (LPAREN ~ ExprList? ~ RPAREN)? } HeaderList = { HeaderItem* } DeclHeader = { HeaderList? ~ KEYWORD_pub? } ExternalHeaderItem = { (AT | SHARP) ~ BANG ~ IDENTIFIER ~ (LPAREN ~ ExprList? ~ RPAREN)? } ExternalHeaderList = { ExternalHeaderItem* } BindingIdent = { IDENTIFIER | UNDERSCORE } ContainerDeclaration = { FnDecl | VarDecl | ConstDecl | TypeDecl | MemberDecl | ComptimeDecl | HeaderList ~ Block } ComptimeDecl = { KEYWORD_comptime ~ (Block | Expr) } FnDecl = { DeclHeader ~ KEYWORD_comptime? ~ KEYWORD_fn ~ IDENTIFIER ~ LPAREN ~ ParamDeclList ~ RPAREN ~ (COLON ~ TypeExpr)? ~ (SEMICOLON | Block) } ParamDeclList = { (ParamDecl ~ COMMA)* ~ (ParamDecl | DOT3)? } ParamDecl = { HeaderList? ~ BindingIdent ~ COLON ~ TypeExpr } VarDecl = { DeclHeader ~ KEYWORD_var ~ VarBody } ConstDecl = { DeclHeader ~ KEYWORD_const ~ VarBody } VarBody = { Pattern ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? } TypeDecl = { DeclHeader ~ KEYWORD_type ~ Pattern ~ EQUAL ~ TypeExpr } MemberDecl = { DeclHeader ~ IDENTIFIER ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? } Pattern = { PatternAtom ~ (COMMA ~ PatternAtom)* } PatternAtom = { UNDERSCORE | AnonymousAggregatePattern | DOT ~ IDENTIFIER ~ (LPAREN ~ Pattern? ~ RPAREN)? | LPAREN ~ Pattern? ~ RPAREN | PatternLiteral | IDENTIFIER } AnonymousAggregatePattern = { DOT ~ LBRACE ~ PatternFieldList? ~ RBRACE } PatternFieldList = { PatternField ~ ((COMMA | SEMICOLON) ~ PatternField)* ~ (COMMA | SEMICOLON)? } PatternField = { DOT ~ IDENTIFIER ~ (EQUAL ~ PatternAtom)? } PatternLiteral = { FLOAT_LITERAL | INTEGER_LITERAL | CHAR_LITERAL | STRING_LITERAL | KEYWORD_true | KEYWORD_false | KEYWORD_null } Block = { LBRACE ~ Statement* ~ Expr? ~ RBRACE } Statement = { RetStatement | BreakStatement | ContinueStatement | DeferStatement | DeclStatement | ExprStatement | ComptimeStatement } DeclStatement = { (VarDecl | ConstDecl | TypeDecl) ~ (COMMA | SEMICOLON)? } ExprStatement = { Expr ~ (COMMA | SEMICOLON)? } ComptimeStatement = { ComptimeDecl ~ (COMMA | SEMICOLON)? } RetStatement = { KEYWORD_ret ~ Expr? ~ (COMMA | SEMICOLON)? } BreakStatement = { KEYWORD_break ~ Label? ~ Expr? ~ (COMMA | SEMICOLON)? } ContinueStatement = { KEYWORD_continue ~ Label? ~ (COMMA | SEMICOLON)? } DeferStatement = { KEYWORD_defer ~ (Block | Statement) ~ (COMMA | SEMICOLON)? } Label = { DOLLAR ~ IDENTIFIER } Expr = { AssignExpr } AssignExpr = { BoolOrExpr ~ (AssignOp ~ AssignExpr)? } BoolOrExpr = { BoolAndExpr ~ (BOOL_OR ~ BoolAndExpr)* } BoolAndExpr = { BitOrExpr ~ (BOOL_AND ~ BitOrExpr)* } BitOrExpr = { BitXorExpr ~ (PIPE ~ BitXorExpr)* } BitXorExpr = { BitAndExpr ~ (CARET ~ BitAndExpr)* } BitAndExpr = { CmpEqExpr ~ (AMPERSAND ~ CmpEqExpr)* } CmpEqExpr = { CmpExpr ~ ((EQ_EQ | BANG_EQUAL) ~ CmpExpr)* } CmpExpr = { ArrowExpr ~ ((L_ARROW_EQ | L_ARROW | R_ARROW_EQ | R_ARROW) ~ ArrowExpr)* } ArrowExpr = { RangeExpr ~ ((THIN_R_ARROW | THIN_L_ARROW | FAT_D_ARROW | THIN_D_ARROW) ~ RangeExpr)* } RangeExpr = { ShiftExpr ~ (DOT2 ~ ShiftExpr?)? } ShiftExpr = { AddExpr ~ ((L_ARROW2_EQ | L_ARROW2 | R_ARROW2_EQ | R_ARROW2) ~ AddExpr)* } AddExpr = { MulExpr ~ ((PLUS | MINUS) ~ MulExpr)* } MulExpr = { CastExpr ~ ((ASTERISK | SLASH | PERCENT) ~ CastExpr)* } CastExpr = { PrefixExpr ~ (KEYWORD_as ~ TypeExpr)* } PrefixExpr = { PrefixOp* ~ PostfixExpr } PrefixOp = { MINUS | BANG | TILDE | AMPERSAND } PostfixExpr = { PrimaryExpr ~ (LPAREN ~ ExprList ~ RPAREN | DOT ~ IDENTIFIER | DOT ~ ASTERISK | LBRACKET ~ Expr ~ RBRACKET | LBRACKET ~ Expr ~ DOT2 ~ Expr? ~ RBRACKET)* } ExprList = { (Expr ~ COMMA)* ~ Expr? } PrimaryExpr = { FLOAT_LITERAL | INTEGER_LITERAL | CHAR_LITERAL | STRING_LITERAL | KEYWORD_true | KEYWORD_false | KEYWORD_null | TupleLiteral | AggregateLiteral | AnonymousAggregateLiteral | ArrayLiteral | AnonymousArrayLiteral | VariantConstruct | ComptimeCallExpr | IDENTIFIER | Block | IfExpr | IfVarExpr | WhileExpr | LoopExpr | ForExpr | MatchExpr | FnTypeExpr } TupleLiteral = { ParenExpr } AggregateLiteral = { IDENTIFIER ~ LBRACE ~ StructInitList? ~ RBRACE } AnonymousAggregateLiteral = { DOT ~ LBRACE ~ StructInitList? ~ RBRACE } StructInitList = { StructInit ~ ((COMMA | SEMICOLON) ~ StructInit)* ~ (COMMA | SEMICOLON)? } StructInit = { DOT ~ IDENTIFIER ~ (EQUAL ~ Expr)? } VariantConstruct = { DOT ~ IDENTIFIER ~ (LPAREN ~ ExprList? ~ RPAREN)? } ArrayLiteral = { LBRACKET ~ RBRACKET ~ TypeExpr ~ LBRACKET ~ ExprList? ~ RBRACKET | LBRACKET ~ (INTEGER_LITERAL | UNDERSCORE) ~ RBRACKET ~ TypeExpr ~ LBRACKET ~ ExprList? ~ RBRACKET } AnonymousArrayLiteral = { DOT ~ LBRACKET ~ ExprList? ~ RBRACKET } ExprNoStruct = { AssignExprNoStruct } AssignExprNoStruct = { BoolOrExprNoStruct ~ (AssignOp ~ AssignExprNoStruct)? } BoolOrExprNoStruct = { BoolAndExprNoStruct ~ (BOOL_OR ~ BoolAndExprNoStruct)* } BoolAndExprNoStruct = { BitOrExprNoStruct ~ (BOOL_AND ~ BitOrExprNoStruct)* } BitOrExprNoStruct = { BitXorExprNoStruct ~ (PIPE ~ BitXorExprNoStruct)* } BitXorExprNoStruct = { BitAndExprNoStruct ~ (CARET ~ BitAndExprNoStruct)* } BitAndExprNoStruct = { CmpEqExprNoStruct ~ (AMPERSAND ~ CmpEqExprNoStruct)* } CmpEqExprNoStruct = { CmpExprNoStruct ~ ((EQ_EQ | BANG_EQUAL) ~ CmpExprNoStruct)* } CmpExprNoStruct = { ArrowExprNoStruct ~ ((L_ARROW_EQ | L_ARROW | R_ARROW_EQ | R_ARROW) ~ ArrowExprNoStruct)* } ArrowExprNoStruct = { RangeExprNoStruct ~ ((THIN_R_ARROW | THIN_L_ARROW | FAT_D_ARROW | THIN_D_ARROW) ~ RangeExprNoStruct)* } RangeExprNoStruct = { ShiftExprNoStruct ~ (DOT2 ~ ShiftExprNoStruct?)? } ShiftExprNoStruct = { AddExprNoStruct ~ ((L_ARROW2_EQ | L_ARROW2 | R_ARROW2_EQ | R_ARROW2) ~ AddExprNoStruct)* } AddExprNoStruct = { MulExprNoStruct ~ ((PLUS | MINUS) ~ MulExprNoStruct)* } MulExprNoStruct = { CastExprNoStruct ~ ((ASTERISK | SLASH | PERCENT) ~ CastExprNoStruct)* } CastExprNoStruct = { PrefixExprNoStruct ~ (KEYWORD_as ~ TypeExpr)* } PrefixExprNoStruct = { PrefixOp* ~ PostfixExprNoStruct } PostfixExprNoStruct = { PrimaryExprNoStruct ~ (LPAREN ~ ExprList ~ RPAREN | DOT ~ IDENTIFIER | DOT ~ ASTERISK | LBRACKET ~ Expr ~ RBRACKET | LBRACKET ~ Expr ~ DOT2 ~ Expr? ~ RBRACKET)* } PrimaryExprNoStruct = { FLOAT_LITERAL | INTEGER_LITERAL | CHAR_LITERAL | STRING_LITERAL | KEYWORD_true | KEYWORD_false | KEYWORD_null | TupleLiteral | AnonymousAggregateLiteral | ArrayLiteral | AnonymousArrayLiteral | VariantConstruct | ComptimeCallExpr | IDENTIFIER | Block | IfExpr | IfVarExpr | WhileExpr | LoopExpr | ForExpr | MatchExpr | FnTypeExpr } VarBodyNoStruct = { Pattern ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ ExprNoStruct)? } TypeExpr = { HeaderList? ~ TypePrefixExpr } TypePrefixExpr = { ASTERISK* ~ TypePostfixExpr } TypePostfixExpr = { TypePrimary ~ (LPAREN ~ TypeExprList ~ RPAREN | DOT ~ IDENTIFIER | LBRACKET ~ TypeExpr ~ RBRACKET | KEYWORD_as ~ TypeExpr)* } TypePrimary = { AT ~ IDENTIFIER // @self 等自引用/内置类型 | ComptimeCallExpr // @import("...") 等导入即类型 | IDENTIFIER | KEYWORD_i8 | KEYWORD_u8 | KEYWORD_i16 | KEYWORD_u16 | KEYWORD_i32 | KEYWORD_u32 | KEYWORD_i64 | KEYWORD_u64 | KEYWORD_f32 | KEYWORD_f64 | KEYWORD_isize | KEYWORD_usize | KEYWORD_bool | KEYWORD_void | KEYWORD_ptr | FnTypeExpr | AggregateTypeExpr | TypeParenExpr | ArrayTypeExpr } ArrayTypeExpr = { LBRACKET ~ RBRACKET ~ TypeExpr | LBRACKET ~ (INTEGER_LITERAL | UNDERSCORE) ~ RBRACKET ~ TypeExpr } TypeParenExpr = { LPAREN ~ RPAREN | LPAREN ~ TypeExpr ~ COMMA ~ (TypeExpr ~ COMMA)* ~ TypeExpr? ~ RPAREN | LPAREN ~ TypeExpr ~ RPAREN } TypeExprList = { (TypeExpr ~ COMMA)* ~ TypeExpr? } FnTypeExpr = { KEYWORD_comptime? ~ KEYWORD_fn ~ LPAREN ~ TypeExprList? ~ RPAREN ~ (COLON ~ TypeExpr)? } AggregateTypeExpr = { (KEYWORD_struct | KEYWORD_union | KEYWORD_enum | KEYWORD_shape) ~ LBRACE ~ ContainerMembers ~ RBRACE } IfExpr = { KEYWORD_if ~ ExprNoStruct ~ Block ~ (KEYWORD_else ~ (Block | IfExpr | IfVarExpr))? } IfVarExpr = { KEYWORD_if ~ KEYWORD_var ~ VarBodyNoStruct ~ Block ~ (KEYWORD_else ~ (Block | IfExpr | IfVarExpr))? } WhileExpr = { Label? ~ KEYWORD_while ~ ExprNoStruct ~ Block ~ (KEYWORD_else ~ (Block | Expr))? } LoopExpr = { Label? ~ KEYWORD_loop ~ Block } ForExpr = { Label? ~ KEYWORD_for ~ Pattern ~ COLON ~ ExprNoStruct ~ (COMMA ~ ExprNoStruct)* ~ Block ~ (KEYWORD_else ~ (Block | Expr))? } MatchExpr = { KEYWORD_match ~ ExprNoStruct ~ LBRACE ~ MatchArm* ~ RBRACE } MatchArm = { Pattern ~ FAT_R_ARROW ~ Block ~ COMMA? } ComptimeCallExpr = { AT ~ IDENTIFIER ~ LPAREN ~ ExprList? ~ RPAREN } ParenExpr = { LPAREN ~ RPAREN | LPAREN ~ Expr ~ COMMA ~ (Expr ~ COMMA)* ~ Expr? ~ RPAREN | LPAREN ~ Expr ~ RPAREN } AssignOp = { EQUAL | PLUS_EQ | MINUS_EQ | ASTERISK_EQ | SLASH_EQ | PERCENT_EQ | AMPERSAND_EQ | PIPE_EQ | CARET_EQ | L_ARROW2_EQ | R_ARROW2_EQ } BOOL_OR = { PIPE ~ PIPE } BOOL_AND = { AMPERSAND ~ AMPERSAND } EQ_EQ = { EQUAL ~ EQUAL } BANG_EQUAL = { BANG ~ EQUAL } keyword_suffix = _{ !(ASCII_ALPHANUMERIC | "_") } KEYWORD_fn = @{ "fn" ~ keyword_suffix } KEYWORD_type = @{ "type" ~ keyword_suffix } KEYWORD_pub = @{ "pub" ~ keyword_suffix } KEYWORD_var = @{ "var" ~ keyword_suffix } KEYWORD_const = @{ "const" ~ keyword_suffix } KEYWORD_if = @{ "if" ~ keyword_suffix } KEYWORD_else = @{ "else" ~ keyword_suffix } KEYWORD_while = @{ "while" ~ keyword_suffix } KEYWORD_loop = @{ "loop" ~ keyword_suffix } KEYWORD_for = @{ "for" ~ keyword_suffix } KEYWORD_as = @{ "as" ~ keyword_suffix } KEYWORD_match = @{ "match" ~ keyword_suffix } KEYWORD_ret = @{ "ret" ~ keyword_suffix } KEYWORD_break = @{ "break" ~ keyword_suffix } KEYWORD_continue = @{ "continue" ~ keyword_suffix } KEYWORD_defer = @{ "defer" ~ keyword_suffix } KEYWORD_shape = @{ "shape" ~ keyword_suffix } KEYWORD_struct = @{ "struct" ~ keyword_suffix } KEYWORD_union = @{ "union" ~ keyword_suffix } KEYWORD_enum = @{ "enum" ~ keyword_suffix } KEYWORD_comptime = @{ "comptime" ~ keyword_suffix } KEYWORD_void = @{ "void" ~ keyword_suffix } KEYWORD_bool = @{ "bool" ~ keyword_suffix } KEYWORD_isize = @{ "isize" ~ keyword_suffix } KEYWORD_usize = @{ "usize" ~ keyword_suffix } KEYWORD_ptr = @{ "ptr" ~ keyword_suffix } KEYWORD_true = @{ "true" ~ keyword_suffix } KEYWORD_false = @{ "false" ~ keyword_suffix } KEYWORD_null = @{ "null" ~ keyword_suffix } KEYWORD_undefined = @{ "undefined" ~ keyword_suffix } KEYWORD_i8 = @{ "i8" ~ keyword_suffix } KEYWORD_u8 = @{ "u8" ~ keyword_suffix } KEYWORD_i16 = @{ "i16" ~ keyword_suffix } KEYWORD_u16 = @{ "u16" ~ keyword_suffix } KEYWORD_i32 = @{ "i32" ~ keyword_suffix } KEYWORD_u32 = @{ "u32" ~ keyword_suffix } KEYWORD_i64 = @{ "i64" ~ keyword_suffix } KEYWORD_u64 = @{ "u64" ~ keyword_suffix } KEYWORD_f32 = @{ "f32" ~ keyword_suffix } KEYWORD_f64 = @{ "f64" ~ keyword_suffix } FAT_D_ARROW = { "<=>" } THIN_D_ARROW = { "<->" } L_ARROW2_EQ = { "<<=" } R_ARROW2_EQ = { ">>=" } DOT3 = { "..." } THIN_R_ARROW = { "<-" } THIN_L_ARROW = { "->" } L_ARROW_EQ = { "<=" } R_ARROW_EQ = { ">=" } L_ARROW2 = { "<<" } R_ARROW2 = { ">>" } FAT_R_ARROW = { "=>" } PLUS_EQ = { "+=" } MINUS_EQ = { "-=" } ASTERISK_EQ = { "*=" } SLASH_EQ = { "/=" } PERCENT_EQ = { "%=" } AMPERSAND_EQ = { "&=" } PIPE_EQ = { "|=" } CARET_EQ = { "^=" } DOT2 = { ".." } LPAREN = { "(" } RPAREN = { ")" } LBRACKET = { "[" } RBRACKET = { "]" } LBRACE = { "{" } RBRACE = { "}" } COMMA = { "," } SEMICOLON = { ";" } COLON = { ":" } DOT = { "." } AT = { "@" } SHARP = { "#" } DOLLAR = { "$" } EQUAL = { "=" } PLUS = { "+" } MINUS = { "-" } ASTERISK = { "*" } SLASH = { "/" } PERCENT = { "%" } AMPERSAND = { "&" } PIPE = { "|" } CARET = { "^" } TILDE = { "~" } BANG = { "!" } L_ARROW = { "<" } R_ARROW = { ">" } UNDERSCORE = { "_" } keyword = _{ KEYWORD_fn | KEYWORD_type | KEYWORD_var | KEYWORD_const | KEYWORD_if | KEYWORD_else | KEYWORD_while | KEYWORD_loop | KEYWORD_for | KEYWORD_as | KEYWORD_match | KEYWORD_ret | KEYWORD_break | KEYWORD_continue | KEYWORD_defer | KEYWORD_shape | KEYWORD_struct | KEYWORD_union | KEYWORD_enum | KEYWORD_comptime | KEYWORD_void | KEYWORD_bool | KEYWORD_true | KEYWORD_false | KEYWORD_null | KEYWORD_undefined | KEYWORD_i8 | KEYWORD_u8 | KEYWORD_i16 | KEYWORD_u16 | KEYWORD_i32 | KEYWORD_u32 | KEYWORD_i64 | KEYWORD_u64 | KEYWORD_f32 | KEYWORD_f64 | KEYWORD_isize | KEYWORD_usize | KEYWORD_ptr } IDENTIFIER = @{ !(keyword ~ !(ASCII_ALPHANUMERIC | "_")) ~ (ASCII_ALPHA | "_" ~ (ASCII_ALPHANUMERIC | "_")) ~ (ASCII_ALPHANUMERIC | "_")* } INTEGER_LITERAL = { DECIMAL | HEX | BINARY | OCTAL | "0" } DECIMAL = { ASCII_NONZERO_DIGIT ~ (ASCII_DIGIT | "_")* } HEX = { "0" ~ ("x" | "X") ~ ASCII_HEX_DIGIT ~ (ASCII_HEX_DIGIT | "_")* } BINARY = { "0" ~ ("b" | "B") ~ ASCII_BIN_DIGIT ~ (ASCII_BIN_DIGIT | "_")* } OCTAL = { "0" ~ ("o" | "O") ~ ASCII_OCT_DIGIT ~ (ASCII_OCT_DIGIT | "_")* } FLOAT_LITERAL = { ASCII_DIGIT ~ "." ~ ASCII_DIGIT ~ (ASCII_DIGIT | "_")* } CHAR_LITERAL = { "'" ~ (!"'" ~ ANY) ~ "'" } STRING_LITERAL = { "\"" ~ ANY* ~ "\"" } COMMENT = _{ LINE_COMMENT | BLOCK_COMMENT } LINE_COMMENT = { "//" ~ (!"\n" ~ ANY)* } BLOCK_COMMENT = { "/*" ~ ANY* ~ "*/" } WHITESPACE = _{ " " | "\t" | "\r" | "\n" }