@top Source { Statement* } Statement { FieldDefinition Semicolon? | Expression Semicolon? } Expression { DefaultExpression } DefaultExpression { PatchExpression | PatchExpression !default Default DefaultExpression } PatchExpression { ComposeExpression | PatchExpression !patch SlashSlash ComposeExpression } ComposeExpression { LogicalOrExpression | ComposeExpression !compose Amp LogicalOrExpression } LogicalOrExpression { LogicalAndExpression | LogicalOrExpression !or PipePipe LogicalAndExpression } LogicalAndExpression { ComparisonExpression | LogicalAndExpression !and AmpAmp ComparisonExpression } ComparisonExpression { ConcatExpression | ConcatExpression !compare CompareOperator ConcatExpression } ConcatExpression { AdditiveExpression | ConcatExpression !concat PlusPlus AdditiveExpression } AdditiveExpression { MultiplicativeExpression | AdditiveExpression !add (Plus | Minus) MultiplicativeExpression } MultiplicativeExpression { UnaryExpression | MultiplicativeExpression !multiply (Star | Slash) UnaryExpression } UnaryExpression { PostfixExpression | (Bang | Minus) !unary UnaryExpression } PostfixExpression { PrimaryExpression | PostfixExpression !call CallSuffix | PostfixExpression !path Dot Identifier } CallSuffix { LParen ArgumentList? RParen } ArgumentList { Expression (Comma Expression)* Comma? } PrimaryExpression { Literal | Identifier | ComparisonConstraint | Object | Array | LetExpression | FunctionExpression | MatchExpression | ImportExpression | LParen Expression RParen } Literal { String | Integer | Float | True | False | Regex } CompareOperator { EqualEqual | BangEqual | Lt | Lte | Gt | Gte } ComparisonConstraint { (Lt | Lte | Gt | Gte) Expression } Object { LBrace (FieldDefinition (Semicolon FieldDefinition)* Semicolon?)? RBrace } FieldDefinition { FieldPath Equal Expression } FieldPath { Identifier !fieldPath (Dot Identifier)* } Array { LBracket (Expression (Comma Expression)* Comma?)? RBracket } LetExpression { Let FieldDefinitionList In Expression } FieldDefinitionList { (FieldDefinition Semicolon)* } FunctionExpression { LParen ParameterList? RParen Arrow Expression } ParameterList { Parameter (Comma Parameter)* Comma? } Parameter { Identifier Colon Expression } MatchExpression { Match Expression LBrace (MatchArm (Semicolon MatchArm)* Semicolon?)? RBrace } MatchArm { Pattern Colon Expression } Pattern { Underscore | Expression } ImportExpression { Import String } @precedence { fieldPath @left, default @right, patch @left, compose @left, or @left, and @left, compare @left, concat @left, add @left, multiply @left, unary, call @left, path @left } @tokens { Let { "let" } In { "in" } Match { "match" } Import { "import" } Default { "default" } True { "true" } False { "false" } Identifier { $[A-Za-z_] $[A-Za-z0-9_]* } Integer { $[0-9]+ } Float { $[0-9]+ "." $[0-9]+ } String { '"' (!["\\\n] | "\\" _)* '"' } Regex { "/" (![/\\\n] | "\\" _)+ "/" } Comment { "#" ![\n]* } LBrace { "{" } RBrace { "}" } LBracket { "[" } RBracket { "]" } LParen { "(" } RParen { ")" } Semicolon { ";" } Comma { "," } Dot { "." } Colon { ":" } Equal { "=" } EqualEqual { "==" } Bang { "!" } BangEqual { "!=" } Arrow { "=>" } Amp { "&" } AmpAmp { "&&" } PipePipe { "||" } Plus { "+" } PlusPlus { "++" } Minus { "-" } Star { "*" } Slash { "/" } SlashSlash { "//" } Gt { ">" } Gte { ">=" } Lt { "<" } Lte { "<=" } Underscore { "_" } whitespace { @whitespace+ } @precedence { Let, In, Match, Import, Default, True, False, Float, Integer, Underscore, Identifier } } @skip { whitespace | Comment }