Created
December 14, 2025 04:07
-
-
Save cschram/af7281e07de488f10e33dfd26595eff7 to your computer and use it in GitHub Desktop.
Otter Pest Grammer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Module = { SOI ~ (Declaration* | EOI) } | |
| // Indentation | |
| // Uses the Pest stack to check indentation level | |
| Indent = _{ PUSH(" "+ | "\t"+) } | |
| Dedent = _{ NEWLINE ~ DROP } | |
| CurrentIndent = _{ PEEK_ALL } | |
| // Identifiers | |
| TypeIdentifier = { Identifier ~ Generics? } | |
| Identifier = @{ !Keyword ~ (NonDigitCharacter ~ (NonDigitCharacter | ASCII_DIGIT)*) } | |
| NonDigitCharacter = { ASCII_ALPHA | "_" } | |
| // Top-level Declarations | |
| Declaration = { | |
| ( | |
| ImportDeclaration | | |
| StructDeclaration | | |
| EnumDeclaration | | |
| TraitDeclaration | | |
| ImplDeclaration | | |
| FunctionDeclaration | | |
| TypeAliasDeclaration | |
| ) ~ | |
| (NEWLINE | EOI) | |
| } | |
| // Imports | |
| ImportDeclaration = @{ Pub? ~ Use ~ WHITESPACE ~ Identifier ~ ( Colon ~ Identifier)* } | |
| // Structs | |
| StructDeclaration = { | |
| Struct ~ WHITESPACE ~ | |
| TypeIdentifier ~ | |
| Colon ~ NEWLINE ~ | |
| StructBody | |
| } | |
| StructBody = { Indent ~ StructField ~ (NEWLINE ~ CurrentIndent ~ StructField)* ~ Dedent } | |
| StructField = { Identifier ~ Colon ~ Identifier } | |
| // Enums | |
| EnumDeclaration = @{ | |
| Enum ~ WHITESPACE ~ | |
| TypeIdentifier ~ | |
| Colon ~ NEWLINE ~ | |
| EnumBody | |
| } | |
| EnumBody = { Indent ~ EnumVariant ~ (NEWLINE ~ CurrentIndent ~ EnumVariant)* ~ Dedent } | |
| EnumVariant = { Identifier ~ (Colon ~ LParen ~ Params)? } | |
| // Traits | |
| TraitDeclaration = @{ | |
| Trait ~ WHITESPACE ~ | |
| Type ~ | |
| Colon ~ NEWLINE ~ | |
| TraitBody | |
| } | |
| TraitBody = { Indent ~ TraitMethod ~ (NEWLINE ~ CurrentIndent ~ TraitMethod)* ~ Dedent } | |
| TraitMethod = { FunctionDeclaration | FunctionSignature } | |
| // Impls | |
| ImplDeclaration = @{ | |
| Impl ~ WHITESPACE ~ | |
| TypeIdentifier ~ | |
| (WHITESPACE ~ For ~ TypeIdentifier)? ~ | |
| Colon ~ NEWLINE ~ | |
| ImplBody | |
| } | |
| ImplBody = { | |
| Indent ~ FunctionDeclaration ~ | |
| (NEWLINE ~ CurrentIndent ~ FunctionDeclaration)* ~ | |
| Dedent | |
| } | |
| // Functions | |
| FunctionDeclaration = { FunctionSignature ~ Colon ~ NEWLINE ~ Block } | |
| FunctionSignature = { | |
| Pub? ~ Fn ~ | |
| Identifier ~ | |
| LParen ~ TypedParams ~ RParen ~ | |
| Arrow ~ Type | |
| } | |
| // Type aliases | |
| TypeAliasDeclaration = { Type ~ WHITESPACE ~ TypeIdentifier ~ Eq ~ TypeIdentifier } | |
| // Parameters | |
| Params = { Identifier ~ (Comma ~ Identifier)* } | |
| StructParams = { StructParam ~ (Comma ~ StructParam)* } | |
| StructParam = { Identifier ~ Eq ~ Expression } | |
| TypedParams = { TypedParam ~ (Comma ~ TypedParam)* } | |
| TypedParam = { Identifier ~ Colon ~ TypeIdentifier } | |
| // Generic parameters | |
| Generics = { Lt ~ Params ~ Gt } | |
| // Blocks | |
| Block = { Indent ~ Statement ~ (CurrentIndent ~ Statement)* ~ Dedent } | |
| // Statements | |
| Statement = { | |
| ( | |
| LetStatement | | |
| Assignment | | |
| IfStatement | | |
| ForStatement | | |
| WhileStatement | | |
| ReturnStatement | | |
| Break | | |
| Continue | | |
| Pass | | |
| Expression | |
| ) ~ NEWLINE | |
| } | |
| LetStatement = { Let ~ WHITESPACE ~ Identifier ~ Eq ~ Expression } | |
| Assignment = { Access ~ Eq ~ Expression } | |
| IfStatement = { | |
| If ~ WHITESPACE ~ Expression ~ | |
| Colon ~ NEWLINE ~ | |
| Block ~ | |
| ElIfStatement* ~ | |
| ElseStatement? | |
| } | |
| ElifStatement = { | |
| ElIf ~ WHITESPACE ~ Expression ~ | |
| Colon ~ NEWLINE ~ | |
| Block | |
| } | |
| ElseStatement = { Else ~ Colon ~ NEWLINE ~ Block } | |
| ForStatement = { | |
| For ~ WHITESPACE ~ | |
| Identifier ~ WHITESPACE ~ In ~ WHITESPACE ~ Expression ~ | |
| Colon ~ NEWLINE ~ | |
| Block | |
| } | |
| WhileStatement = { | |
| While ~ WHITESPACE ~ Expression ~ | |
| Colon ~ NEWLINE ~ | |
| Block | |
| } | |
| ReturnStatement = { Return ~ (WHITESPACE ~ Expression)? } | |
| // Expressions | |
| Expression = { | |
| Literal | | |
| BinaryExpression | | |
| UnaryExpression | | |
| CallExpression | | |
| AccessExpression | | |
| ParenExpression | |
| } | |
| BinaryExpression = { Expression ~ BinaryOp ~ Expression } | |
| BinaryOp = { | |
| Plus ~ | |
| Minus ~ | |
| Star ~ | |
| Slash ~ | |
| Percent ~ | |
| EqEq ~ | |
| Neq ~ | |
| Lt ~ | |
| Gt ~ | |
| LtEq ~ | |
| GtEq ~ | |
| (Is ~ Not) ~ | |
| Is ~ | |
| And ~ | |
| Or | |
| } | |
| UnaryExpression = { UnaryOp ~ Expression } | |
| UnaryOp = { Bang ~ Not ~ Minus } | |
| CallExpression = { AccessExpression ~ LParen ~ (StructParams | Params) ~ RParen } | |
| AccessExpression = { Identifier ~ (Dot ~ Identifier)* } | |
| ParenExpression = { LParen ~ Expression ~ RParen } | |
| // Literals | |
| Literal = { | |
| UnitLiteral | | |
| NumberLiteral | | |
| StringLiteral | | |
| BoolLiteral | | |
| ArrayLiteral | | |
| DictLiteral | |
| } | |
| UnitLiteral = { LParen ~ RParen } | |
| NumberLiteral = { ASCII_DIGIT+ ( Dot ~ ASCII_DIGIT+) } | |
| StringLiteral = { PUSH(Quote | DoubleQuote) ~ StringCharacter* ~ POP } | |
| StringCharacter = { | |
| !PEEK ~ | |
| (WHITESPACE | StringUnicode | EscapedQuote | AllowedQuote | EscapedNewline) | |
| } | |
| // Unicode allowed in stirngs | |
| StringUnicode = { LETTER | MARK | NUMBER | PUNCTUATION | SYMBOL | SEPARATOR } | |
| // Escaped version of the quote being used for the string | |
| EscapedQuote = { Escape ~ PEEK } | |
| // Matches whichever quote is not being used for the string | |
| AllowedQuote = { !PEEK ~ (Quote | DoubleQuote) } | |
| EscapedNewline = { Escape ~ NEWLINE } | |
| BoolLiteral = { True | False } | |
| ArrayLiteral = { | |
| LBracket ~ | |
| ( | |
| Expression ~ | |
| (Comma ~ Expression)* | |
| )? ~ | |
| RBracket | |
| } | |
| DictLiteral = { | |
| LBrace ~ | |
| ( | |
| DictEntry ~ | |
| (Comma ~ DictEntry)* | |
| )? ~ | |
| RBrace | |
| } | |
| DictEntry = { StringLiteral ~ Colon ~ Expression } | |
| // Keywords | |
| Keyword = { | |
| Use | | |
| As | | |
| Pub | | |
| Fn | | |
| Struct | | |
| Enum | | |
| Trait | | |
| Impl | | |
| Return | | |
| Let | | |
| If | | |
| Else | | |
| Elif | | |
| For | | |
| While | | |
| Break | | |
| Continue | | |
| Pass | | |
| In | | |
| Is | | |
| Not | | |
| And | | |
| Or | | |
| Match | | |
| Case | | |
| Await | | |
| Spawn | | |
| True | | |
| False | |
| } | |
| Use = _{ "use" } | |
| As = _{ "as" } | |
| Pub = _{ "pub" } | |
| Fn = _{ "fn" } | |
| Struct = _{ "struct" } | |
| Enum = _{ "enum" } | |
| Trait = _{ "trait" } | |
| Type = _{ "type" } | |
| Impl = _{ "impl" } | |
| Return = _{ "return" } | |
| Let = _{ "let" } | |
| If = _{ "if" } | |
| Else = _{ "else" } | |
| Elif = _{ "elif" } | |
| For = _{ "for" } | |
| While = _{ "while" } | |
| Break = _{ "break" } | |
| Continue = _{ "continue" } | |
| Pass = _{ "pass" } | |
| In = _{ "in" } | |
| Is = _{ "is" } | |
| Not = _{ "not" } | |
| And = _{ "and" } | |
| Or = _{ "or" } | |
| Match = _{ "match" } | |
| Case = _{ "case" } | |
| Await = _{ "await" } | |
| Spawn = _{ "spawn" } | |
| True = _{ "true" } | |
| False = _{ "false" } | |
| // Structural characters | |
| Colon = _{ ":" } | |
| LParen = _{ "(" } | |
| RParen = _{ ")" } | |
| LBrace = _{ "{" } | |
| RBrace = _{ "}" } | |
| LBracket = { "[" } | |
| RBracket = { "]" } | |
| Comma = _{ "," } | |
| Dot = _{ "." } | |
| Quote = _{ "'" } | |
| DoubleQuote = _{ '"' } | |
| Escape = _{ "\\" } | |
| // Operators | |
| Arrow = _{ "->" } | |
| Eq = _{ "=" } | |
| EqEq = _@{ Eq ~ Eq } | |
| Bang = _{ "!" } | |
| Neq = _@{ Bang ~ Eq } | |
| Lt = _{ "<" } | |
| Gt = _{ ">" } | |
| LtEq = _@{ Lt ~ Eq } | |
| GtEq = _@{ Gt ~ Eq } | |
| Plus = _{ "+" } | |
| Minus = _{ "-" } | |
| Star = _{ "*" } | |
| Slash = _{ "/" } | |
| Percent = _{ "%" } | |
| Pipe = _{ "|" } | |
| Amp = _{ "&" } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment