Table of Contents

Grammar

The following is the non-normative EBNF grammar for Raven.

Source file

(* Raven language EBNF grammar
   This grammar captures the structural form of Raven source code.
   Contextual rules and parsing details are described in the language specification.
   NOTE: Non-normative. Context-sensitive parsing and validation live outside this EBNF. *)

CompilationUnit          ::= {ImportDirective} {AliasDirective} {TopLevelItem} EOF ;
TopLevelItem             ::= Declaration | Statement ;
(* `#pragma` and the conditional `#if` / `#elif` / `#else` / `#endif`
   forms are structured directive trivia handled by the lexer. `#[` starts an
   attached macro. Freestanding macros use the `Name!` envelope. *)

ImportDirective          ::= 'import' QualifiedName ('.' '*')? ; (* Namespace imports require '.*'; applying '.*' to a type imports its static members and nested types *)
AliasDirective           ::= 'alias' Identifier '=' Type ; (* Target may be a fully qualified name, type expression, or predefined type: bool | byte | char | decimal | double | float | int | long | nint | nuint | object | sbyte | short | string | uint | ulong | unit | ushort | '()' *)

(* ---------- Modifiers ---------- *)

MemberModifiers          ::= { MemberModifier } ;
MemberModifier           ::= AccessModifier
                           | 'static' | 'abstract' | 'virtual' | 'override' | 'final' | 'sealed' | 'new'
                           | 'readonly' | 'required'
                           | 'async' | 'extern' | 'partial' ;  (* Contextual restriction: 'partial' currently applies to methods, properties, and events *)

AccessModifier           ::= 'public' | 'internal' | 'protected' | 'private' ;

AccessorModifier         ::= AccessModifier | 'async' | 'ref' | 'out' | 'in' ;

TypeModifiers            ::= { TypeModifier } ;
TypeModifier             ::= AccessModifier | 'fileprivate' | 'abstract' | 'sealed' | 'open' | 'partial' | 'static' | 'ref' | 'readonly' ;

TopLevelFunctionModifiers ::= { TopLevelFunctionModifier } ;
TopLevelFunctionModifier  ::= AccessModifier | 'fileprivate' | 'async' | 'extern' | 'unsafe' | 'static' ;
TopLevelConstModifiers    ::= { TopLevelConstModifier } ;
TopLevelConstModifier     ::= AccessModifier | 'fileprivate' | 'static' ;
(* Contextual restriction: top-level members accept public/internal/fileprivate
   accessibility. `static` is parsed for recovery but is semantically invalid
   because top-level members are already implicitly static. *)
(* Semantic note: a type declaration marked with [TopLevel] remains a normal
   type declaration syntactically; the marker promotes accessible static
   members through namespace lookup when top-level member imports are enabled. *)

(* ---------- Declarations ---------- *)

Declaration              ::= NamespaceDeclaration
                           | TopLevelFunctionDeclaration
                           | MacroDeclaration
                           | TopLevelConstDeclaration
                           | ExtensionDeclaration
                           | EnumDeclaration
                           | UnionDeclaration
                           | ClassDeclaration
                           | StructDeclaration
                           | InterfaceDeclaration
                           | DelegateDeclaration ;

NamespaceDeclaration     ::= 'namespace' Identifier '{' {ImportDirective} {AliasDirective} {TopLevelItem} '}' ;

TopLevelFunctionDeclaration
                          ::= {AttributeList | MacroAttributeList}
                             TopLevelFunctionModifiers?
                             'func' Identifier TypeParameterList?
                             '(' ParameterList? ')'
                             ReturnTypeClause?
                             WhereClauseList?
                             ( Block | '=>' Expression ) ;

MacroDeclaration         ::= {AttributeList}
                             TopLevelFunctionModifiers?
                             'macro' Identifier TypeParameterList?
                             '(' MacroParameterList? ')'
                             ReturnTypeClause?
                             WhereClauseList?
                             {MacroCapabilityClause}
                             ( Block | '=>' Expression ) ;
MacroCapabilityClause   ::= MacroCapabilityKeyword 'by' Expression ;
MacroCapabilityKeyword  ::= 'keywords' | 'tokens' | 'tokenKinds'
                           | 'highlighting' | 'fragments' | 'symbols'
                           | 'completion' | 'projection' ;
MacroParameterList       ::= MacroParameter {',' MacroParameter} ;
MacroParameter           ::= {AttributeList} 'on'? AccessModifier? ScopedModifier? RefKindModifier? ParamsModifier? ParameterBindingKeyword?
                             Identifier ':' Type VarParamsSuffix? ['=' Expression] ;
(* Exactly one `on` parameter selects attached application. It is supplied by
   the compiler and must name a supported Raven.CodeAnalysis syntax type. *)

TopLevelConstDeclaration ::= {AttributeList | MacroAttributeList}
                             TopLevelConstModifiers?
                             'const' VariableDeclarators TypeTerminator? ;

ExtensionKeyword         ::= 'extension'

(* The extension identifier is optional. When omitted, the compiler synthesizes an internal name (e.g., via mangling) and the declaration cannot be referenced by name. *)
(* Named `fileprivate` extensions also emit a mangled container metadata name so the generated type does not expose a stable cross-file/importable identity. *)
(* Unnamed extensions are intended for local/assembly-private augmentation; public APIs should use a stable explicit name. *)
ExtensionDeclaration     ::= ExtensionKeyword Identifier? TypeParameterList?
                             'for' Type
                             WhereClauseList?
                             ExtensionBody ;

ExtensionBody            ::= '{' {ExtensionMember} '}' ;
ExtensionMember          ::= ExtensionMethodDeclaration
                           | ExtensionPropertyDeclaration
                           | OperatorDeclaration
                           | ConversionOperatorDeclaration ;

ExtensionMethodDeclaration
                           ::= ExtensionMethodModifiers?
                               'func' Identifier TypeParameterList?
                               '(' ParameterList? ')'
                               ReturnTypeClause?
                               WhereClauseList?
                               ( Block | '=>' Expression ) ;

ExtensionMethodModifiers ::= AccessModifier ;

ExtensionPropertyDeclaration
                           ::= ExtensionPropertyModifiers?
                               PropertyBindingKeyword
                               Identifier ':' Type PropertyBody ;

ExtensionPropertyModifiers ::= AccessModifier ;

ReturnTypeClause         ::= '->' Type ;

ParameterList            ::= Parameter {',' Parameter} ;
Parameter                ::= {AttributeList} AccessModifier? ScopedModifier? RefKindModifier? ParamsModifier? ParameterBindingKeyword?
                             Identifier ':' Type VarParamsSuffix? ['=' Expression] ;
ScopedModifier           ::= 'scoped' ;
ParamsModifier           ::= 'params' ;
VarParamsSuffix          ::= '...' ; (* Convenience collector marker. `params` and `...` are mutually exclusive on the same parameter. *)
RefKindModifier          ::= 'ref' | 'out' | 'in' ;
ParameterBindingKeyword  ::= 'let' | 'val' | 'var' | 'const' ;

AttributeList            ::= '[' Attribute {',' Attribute} ']' ;
Attribute                ::= QualifiedName [AttributeArgumentList] ;
MacroAttributeList       ::= '#[' MacroAttribute {',' MacroAttribute} ']' ;
MacroAttribute           ::= Identifier [TypeArgumentList] [AttributeArgumentList] ;

EnumDeclaration          ::= TypeModifiers?
                             'enum' Identifier EnumBaseList?
                             '{' EnumMembers? '}' ;

EnumBaseList             ::= ':' Type ;
EnumMembers              ::= EnumMember {',' EnumMember} [','] ;
EnumMember               ::= Identifier ['=' Expression] ;

ClassDeclaration         ::= TypeModifiers? 'class' Identifier TypeParameterList?
                             PrimaryConstructorAccessibility? PrimaryConstructor? BaseList?
                             WhereClauseList? PermitsClause?
                             ClassBody? ;

RecordDeclaration        ::= TypeModifiers? 'record' ['class' | 'struct'] Identifier TypeParameterList?
                             PrimaryConstructorAccessibility? PrimaryConstructor? BaseList?
                             WhereClauseList? PermitsClause?
                             ClassBody? ;

PermitsClause            ::= 'permits' Type {',' Type} ;

PrimaryConstructor       ::= '(' ParameterList? ')' ;
PrimaryConstructorAccessibility ::= AccessModifier ;

StructDeclaration        ::= TypeModifiers? 'struct' Identifier TypeParameterList?
                             PrimaryConstructorAccessibility? PrimaryConstructor? BaseList?
                             WhereClauseList?
                             ClassBody? ;

InterfaceDeclaration     ::= TypeModifiers? 'interface' Identifier TypeParameterList?
                             BaseList?
                             WhereClauseList?
                             ClassBody? ;

UnionDeclaration         ::= TypeModifiers? 'union' ('class' | 'struct')? Identifier TypeParameterList?
                             UnionPrimaryList? BaseList?
                             WhereClauseList?
                             UnionDeclarationBody?
                             TypeTerminator? ;

UnionDeclarationBody     ::= '{' UnionCaseList '}' ;

UnionPrimaryList.        ::= '(' UnionAlternativeTypeList ')' ;

UnionAlternativeTypeList ::= UnionAlternativeType ('|' UnionAlternativeType)* ;
UnionAlternativeType     ::= Type | 'null' ; (* 'null' is union-declaration-only syntax for nullable active contents, not a general Type *)

DelegateDeclaration      ::= TypeModifiers? 'delegate' Identifier TypeParameterList?
                             '(' ParameterList? ')'
                             ReturnTypeClause?
                             WhereClauseList?
                             TypeTerminator? ;

UnionCaseList            ::= {UnionCaseClause} ;
UnionCaseClause          ::= 'case' Identifier (UnionCaseParameterList | CaseFieldClause)? UnionCaseTerminator? ;
UnionCaseParameterList   ::= '(' UnionCaseParameter {',' UnionCaseParameter} ')' ;
UnionCaseParameter       ::= Parameter | Type ;
CaseFieldClause          ::= '{' {CaseField} '}' ;
CaseField                ::= Identifier ':' Type ('=' Expression)? UnionCaseTerminator? ;
UnionCaseTerminator      ::= ',' | TypeTerminator ;
(* Case-construction surface forms are semantically equivalent:
     Ok(2)
     Ok<int>(2)
     Result<int, E>.Ok(2)
     .Ok(2)                    (target-typed member binding)
   Unqualified `Ok` forms are valid only when case resolution is unambiguous;
   otherwise qualification (or an alias) is required.
   Resolution of `.Ok` / `Result.Ok` is performed by the binder against the
   union's declared case set.
   Commas are optional between cases; newline separators remain valid. *)

BaseList                 ::= ':' Type {',' Type} ;
(* In declaration-oriented separated lists such as parameter lists, type
   parameter lists, type argument lists, and enum-member lists, Raven also
   accepts newline as a boundary. Some lists, such as enum-member lists, also
   admit alternate explicit separators like `;`. The syntax tree keeps the
   separated-list shape and records `SyntaxKind.None` for implicit separator
   slots. Same-line omission is still an error and recovers with a missing
   expected separator token. *)

ClassBody                ::= '{' {ClassMember} '}' ;

TypeTerminator           ::= end-of-line-trivia | ';' ;

ClassMember              ::= FieldDeclaration
                           | ConstDeclaration
                           | ParameterlessConstructorDeclaration
                           | FinallyDeclaration
                           | MethodDeclaration
                           | ConversionOperatorDeclaration
                           | OperatorDeclaration
                           | InvocationOperatorDeclaration
                           | ConstructorDeclaration
                           | EventDeclaration
                           | PropertyDeclaration
                           | IndexerDeclaration
                           | DelegateDeclaration
                           | MacroMemberInvocation ;

MacroMemberInvocation    ::= QualifiedName '!'
                             ( ArgumentList
                             | [ArgumentList] MacroTokenTree )
                             TypeTerminator? ;

FieldDeclaration         ::= MemberModifiers? 'field' VariableDeclarators ';' ;  (* `readonly`/`required` are MemberModifiers *)
ConstDeclaration         ::= MemberModifiers? 'const' VariableDeclarators ';' ;

VariableDeclarators      ::= VariableDeclarator {',' VariableDeclarator} ;
VariableDeclarator       ::= Identifier (':' Type)? ['=' Expression] ;

ParameterlessConstructorDeclaration          ::= MemberModifiers?
                             'init'
                             ( Block | '=>' Expression ) ;

ConstructorDeclaration   ::= MemberModifiers?
                             'init' '(' ParameterList? ')'
                             ConstructorInitializer?
                             ( Block | '=>' Expression ) ;

FinallyDeclaration       ::= MemberModifiers?
                             'finally'
                             Block ;

ConstructorInitializer   ::= ':' 'base' ArgumentList ;

MethodDeclaration        ::= MemberModifiers?
                             'func'
                             ExplicitInterfaceSpecifier?
                             Identifier TypeParameterList?
                             '(' ParameterList? ')'
                             ReturnTypeClause?
                             WhereClauseList?
                             ( Block | '=>' Expression ) ;

ConversionOperatorDeclaration
                         ::= MemberModifiers?
                             'func' ( 'explicit' | 'implicit' )
                             '(' ParameterList? ')'
                             ReturnTypeClause?
                             ( Block | '=>' Expression ) ;

OperatorDeclaration      ::= MemberModifiers?
                             'func' OverloadableOperator
                             '(' ParameterList? ')'
                             ReturnTypeClause?
                             ( Block | '=>' Expression ) ;

OverloadableOperator     ::= '+' | '-' | '*' | '/' | '%' | '^' | '&' | '&&' | 'and'
                           | '|' | '||' | 'or' | '==' | '!=' | '<' | '<=' | '>'
                           | '>=' | '!' | '++' | '--' ;

ExplicitInterfaceSpecifier ::= Type '.' ;

InvocationOperatorDeclaration
                           ::= MemberModifiers?
                               'self' TypeParameterList?
                               '(' ParameterList? ')'
                               ReturnTypeClause?
                               WhereClauseList?
                               ( Block | '=>' Expression ) ;

PropertyDeclaration      ::= MemberModifiers?
                             PropertyBindingKeyword
                             ExplicitInterfaceSpecifier? Identifier ':' Type PropertyBody ;  (* `required` is a MemberModifier *)

PropertyBindingKeyword   ::= 'val' | 'var' ;
PropertyBody             ::= AccessorList
                           | '=>' Expression
                           | '=' Expression ;

IndexerDeclaration       ::= MemberModifiers?
                             ExplicitInterfaceSpecifier? Identifier BracketedParameterList ':' Type AccessorList ;

EventDeclaration         ::= MemberModifiers?
                             ExplicitInterfaceSpecifier? 'event' Identifier ':' Type ( EventAccessorList | ';' ) ;

AccessorList             ::= '{' Accessor {Accessor} '}' ;
Accessor                 ::= AccessorModifier? ('get' | 'set' | 'init')
                             ( Block | '=>' Expression | ';' ) ;

EventAccessorList        ::= '{' EventAccessor {EventAccessor} '}' ;
EventAccessor            ::= AccessorModifier? ('add' | 'remove')
                             ( Block | '=>' Expression | ';' ) ;

BracketedParameterList   ::= '[' ParameterList? ']' ;

(* ---------- Generics & constraints ---------- *)

TypeParameterList        ::= '<' TypeParameter {',' TypeParameter} '>' ;

TypeParameter            ::= Variance? Identifier InlineConstraints? ;

InlineConstraints        ::= ':' TypeParameterConstraintList ;

Variance                 ::= 'out' | 'in' ;

WhereClauseList          ::= WhereClause { WhereClause } ;

WhereClause              ::= 'where' Identifier ':' TypeParameterConstraintList ;

TypeParameterConstraintList
                         ::= TypeParameterConstraint {',' TypeParameterConstraint} ;

TypeParameterConstraint  ::= 'class'            (* reference type constraint *)
                           | 'struct'           (* value type constraint *)
                           | 'notnull'          (* non-null constraint *)
                           | 'unmanaged'        (* unmanaged constraint *)
                           | 'new' '(' ')'      (* public parameterless ctor *)
                           | 'allows' 'ref' 'struct'
                           | Type ;             (* base class / interface constraint *)

(* ---------- Statements ---------- *)

(* Newline tokens act as implicit statement terminators unless the parser is
   in a continuation context that still requires more of the current
   expression—such as immediately after '=' or a binary operator. In those
   cases the newline is preserved as trivia on the next token instead of
   ending the statement. Other terminators, including ';', '}', and keywords
   like 'else' that conclude the enclosing construct, serve the same role when
   they appear. *)

Statement                ::= LocalDeclaration
                           | LetElseStatement
                           | ReturnStatement
                           | ThrowStatement
                           | BreakStatement
                           | ContinueStatement
                           | FunctionStatement
                           | BlockStatement
                           | IfStatement
                           | IfPatternStatement
                           | LoopStatement
                           | WhileStatement
                           | WhilePatternStatement
                           | ForStatement
                           | TryStatement
                           | LockStatement
                           | UnsafeStatement
                           | MacroContributionStatement
                           | AssignmentStatement
                           | ExpressionStatement ;

BlockStatement           ::= Block ;

LocalDeclaration         ::= ScopedModifier? ('let' | 'val' | 'var' | 'const') LocalVariableDeclarators ;
LetElseStatement         ::= BindingKeyword Pattern '=' Expression 'else' DivergingStatement ;
(* Semantic rule: DivergingStatement must not have a reachable endpoint. It
   exits through return, throw, break, or continue; successful pattern
   bindings are introduced into the surrounding block scope. *)
DivergingStatement       ::= EmbeddedStatement ;
UseDeclarationStatement  ::= 'use' LocalVariableDeclarators ['in' Block] ;
LocalVariableDeclarators ::= LocalVariableDeclarator {',' LocalVariableDeclarator} ;
LocalVariableDeclarator  ::= Identifier (':' Type)? '=' Expression ;

ReturnStatement          ::= 'return' Expression? ;
ThrowStatement           ::= 'throw' Expression ;
BreakStatement           ::= 'break' [Identifier] ;
ContinueStatement        ::= 'continue' [Identifier] ;
MacroContributionStatement
                         ::= ('expand' | 'replace' | 'introduce' | 'fragment' | 'token') Expression ;
(* Macro contribution words are contextual and these statement forms are
   available only inside macro declarations. *)

FunctionStatement        ::= {AttributeList | MacroAttributeList}
                             ('async' | 'unsafe' | 'extern')*
                             'func' Identifier TypeParameterList?
                             '(' ParameterList? ')'
                             ReturnTypeClause?
                             WhereClauseList?
                             Block ;

ExpressionStatement      ::= Expression ;

IfStatement              ::= 'if' Expression EmbeddedStatement ['else' ElseEmbeddedStatement] ;
IfPatternStatement       ::= 'if' BindingKeyword Pattern '=' Expression EmbeddedStatement ['else' ElseEmbeddedStatement] ;

(* NOTE: In statement contexts, '{' that starts a new statement (for example after a newline,
   or after headers such as if/while/for) begins a block statement/body and is not parsed as an object initializer.
   This disambiguation is performed by the parser (context-sensitive), not by this EBNF. *)
WhileStatement           ::= 'while' Expression EmbeddedStatement ;
WhilePatternStatement    ::= 'while' BindingKeyword Pattern '=' Expression EmbeddedStatement ;
LoopStatement            ::= 'loop' EmbeddedStatement ;
LockStatement            ::= 'lock' Expression EmbeddedStatement ;
ForStatement             ::= 'await'? 'for' ForBindingKeyword? ForIterationTarget? 'in' Expression ForStepClause? EmbeddedStatement ;
ForBindingKeyword        ::= 'val' | 'let' | 'var' ;
ForIterationTarget       ::= TypedForIdentifierTarget | Identifier | Pattern ;
TypedForIdentifierTarget ::= Identifier ':' Type ;
ForStepClause            ::= 'by' Expression ;
(* Parser rule: a non-block embedded statement must start on the next line.
   `else if` remains a dedicated exception and may stay on the same line. *)
EmbeddedStatement        ::= Block | Statement ;
ElseEmbeddedStatement    ::= Block | IfStatement | Statement ;

TryStatement             ::= 'try' Block (CatchClauseList [FinallyClause] | FinallyClause) ;
CatchClauseList          ::= CatchClause {CatchClause} ;
CatchClause              ::= 'catch' CatchPattern? [WhenClause] Block ;
CatchPattern             ::= Pattern | '(' Pattern ')' ;
FinallyClause            ::= 'finally' Block ;
UnsafeStatement          ::= 'unsafe' Block ;

(* Keep statement assignments consistent with expression assignments:
   - LHS must be assignable OR a deconstruction designation.
   - General patterns are NOT assignment targets.
   - Only deconstruction-shaped designations (`(...)`, `[...]`, nested variable
     designations) participate on the LHS. Property patterns, member/case
     patterns, nominal deconstruction heads, comparison/range heads, and other
     match-only pattern forms do not. *)
AssignmentStatement      ::= Assignable AssignmentOperator Expression
                           | DeconstructionAssignmentStatement ;

DeconstructionAssignmentStatement
                         ::= VariableDesignation AssignmentOperator Expression ;

(* ---------- Expressions & precedence (lowest → highest) ---------- *)

Expression               ::= MatchExpression
                           | AssignmentExpression {PostfixMatchExpressionSuffix} ;

MatchExpression          ::= 'match' Expression '{' MatchArmList '}' ;
PostfixMatchExpressionSuffix
                         ::= 'match' '{' MatchArmList '}' ;
MatchArmList             ::= MatchArm {MatchArm} ;
MatchArm                 ::= MatchArmBindingKeyword? Pattern MatchGuardClause? '=>' Expression MatchArmTerminator? ;
MatchArmBindingKeyword   ::= 'val' | 'let' | 'var' ;
MatchGuardClause         ::= 'when' Expression ;
MatchArmTerminator       ::= end-of-line-trivia | ';' ;

AssignmentExpression     ::= Assignable AssignmentOperator AssignmentExpression
                           | DeconstructionAssignment
                           | ConditionalNullCoalesceExpression ;

DeconstructionAssignment ::= VariableDesignation AssignmentOperator AssignmentExpression ;

AssignmentOperator       ::= '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '??=' ;

Assignable               ::= Identifier
                           | MemberAccessExpression
                           | MemberBindingExpression
                           | ElementAccessExpression ;

(* ---------- Patterns ---------- *)

Pattern                  ::= OrPattern [PatternGuardClause] ;
PatternGuardClause       ::= 'when' (Pattern | Expression) ;

OrPattern                ::= AndPattern {'or' AndPattern} ;
AndPattern               ::= UnaryPattern {'and' UnaryPattern} ;
UnaryPattern             ::= 'not' UnaryPattern | PrimaryPattern ;

PrimaryPattern           ::= ParenthesizedPattern
                           | RangePattern
                           | ComparisonPattern
                           | ConstantPattern
                           | VariablePattern
                           | DeclarationPattern
                           | PositionalPattern
                           | SequencePattern
                           | DictionaryPattern
                           | DiscardPattern
                           | MemberPattern
                           | NominalDeconstructionPattern
                           | PropertyPattern ;

ConstantPattern          ::= Literal | ConstantPatternOperand ;

ConstantPatternOperand    ::= Identifier ;

(* A bare identifier in pattern position never introduces a binding.
   Bindings require an explicit BindingKeyword (let/val/var).

   A bare identifier is context-sensitive:
   - If the scrutinee is a discriminated union and the identifier matches a case name
     in the union's declared case set, it is treated as a DU case pattern.
   - If it binds to an in-scope value, it is a value/constant pattern (matches by equality).
   - Otherwise it is interpreted as a type name and forms a DeclarationPattern.
   This disambiguation is performed by the binder. *)
   
BindingKeyword           ::= 'let' | 'val' | 'var' ;

VariablePattern          ::= BindingKeyword VariableDesignation ;

(* NOTE: A single Identifier can be parsed as either ConstantPatternOperand or as the `Type` in a
   DeclarationPattern. The binder resolves the ambiguity by preferring a value/constant pattern
   when the identifier resolves to a value symbol in scope; otherwise it is treated as a type. *)
DeclarationPattern       ::= Type [VariableDesignation] ;

PositionalPattern        ::= '(' PatternElement ',' PatternElement {',' PatternElement} ')' [PatternWholeDesignation] ;
PatternElement           ::= [PatternElementName] Pattern ;

SequencePattern          ::= '[' SequencePatternElementList? ']' [PatternWholeDesignation] ;
SequencePatternElementList
                         ::= SequencePatternElement {',' SequencePatternElement} ;
SequencePatternElement   ::= [SequencePatternPrefix] Pattern
                          | '...' ;
SequencePatternPrefix    ::= '..' [IntegerLiteral]
                           | '...' ;

DictionaryPattern        ::= '[' DictionaryPatternEntryList? ']' [PatternWholeDesignation] ;
DictionaryPatternEntryList
                         ::= DictionaryPatternEntry {',' DictionaryPatternEntry} ;
DictionaryPatternEntry   ::= Expression ':' Pattern ;

(* Pattern elements may be named with `name: pattern`.
   When the pattern is a declaration/capture pattern, the nested pattern still
   controls whether a binding keyword is required. Examples:
   - (Age: 42, Name: val name)
   - Person(Items: val items, Name: val name, Age: 42)
   For tuple-backed positional patterns, the name is descriptive metadata.
   For `Deconstruct`-backed positional/nominal patterns, the binder matches
   named elements against deconstruction parameters/members by name. *)
PatternElementName       ::= Identifier ':' ;

(* Binder note: at most one open-ended rest segment (`.. pattern`, `... pattern`,
   or bare `...`) is permitted in a sequence pattern. Fixed-length array
   captures may arise from these segments, while fixed-size segments use
   `..N pattern` and may appear multiple times. *)

DiscardPattern           ::= '_' | Type '_' ;

MemberPattern            ::= MemberPath [ '(' PatternList? ')' ] [PatternWholeDesignation] ;
MemberPath               ::= '.' Identifier
                           | Type '.' Identifier ;

PatternList              ::= Pattern {',' Pattern} ;
PatternElementList       ::= PatternElement {',' PatternElement} ;

NominalDeconstructionPattern
                         ::= Type '(' PatternElementList? ')' [PatternWholeDesignation] ;
(* Binder note: when Type resolves to a discriminated-union case name for the
   current scrutinee, this form is interpreted as a DU case deconstruction
   pattern rather than a regular nominal deconstruction pattern. Otherwise the type must be
   deconstructable (for example a record type or a nominal type with an
   accessible `Deconstruct` method). *)

PropertyPattern          ::= Type? '{' PropertySubpatternList? '}' PatternWholeDesignation? ;
PropertySubpatternList   ::= PropertySubpattern {',' PropertySubpattern} ;
PropertySubpattern       ::= PropertyMemberPath ':' Pattern ;
PropertyMemberPath       ::= Identifier {'.' Identifier} ;

PatternWholeDesignation  ::= VariableDesignation ;

ParenthesizedPattern     ::= '(' Pattern ')' ;

ComparisonPattern        ::= RelationalOperator ComparisonPatternOperand ;
RelationalOperator       ::= '<' | '<=' | '>' | '>=' | '==' | '!=' ;
ComparisonPatternOperand ::= Expression ; (* binder should enforce “constant-ish” rules *)

RangePattern             ::= RangeLower '..' RangeUpper ;
RangeLower               ::= RangePatternOperand? ;
RangeUpper               ::= RangePatternOperand? ;
RangePatternOperand      ::= Expression ; (* binder should enforce “constant-ish” rules; parser stops at `..` when parsing the lower bound *)

VariableDesignation      ::= VariableDesignationCore [':' Type] ; (* Whole-pattern designations may omit the BindingKeyword when an outer construct (for example `if let`, `while let`, `for let`, or a match-arm binding keyword) supplies the binding mode. Without an outer binding keyword, omitted binding defaults to an immutable capture. *)
VariableDesignationCore  ::= SingleVariableDesignation | ParenthesizedVariableDesignation ;
SingleVariableDesignation ::= [BindingKeyword] Identifier ;

ParenthesizedVariableDesignation
                         ::= '(' VariableDesignation {',' VariableDesignation} ')' ;

ConditionalNullCoalesceExpression
                         ::= LogicalOrExpression {'??' LogicalOrExpression} ;

LogicalOrExpression      ::= LogicalAndExpression {'||' LogicalAndExpression} ;
LogicalAndExpression     ::= BitwiseOrExpression {'&&' BitwiseOrExpression} ;
BitwiseOrExpression      ::= BitwiseXorExpression {'|' BitwiseXorExpression} ;
BitwiseXorExpression     ::= BitwiseAndExpression {'^' BitwiseAndExpression} ;
BitwiseAndExpression     ::= EqualityExpression {'&' EqualityExpression} ;
EqualityExpression       ::= RelationalExpression {('==' | '!=') RelationalExpression} ;
RelationalExpression     ::= TypeTestExpression
                             {('<' | '>' | '<=' | '>=') TypeTestExpression} ;

TypeTestExpression       ::= RangeExpression { 'as' Type } [ 'is' Pattern ] ;

RangeExpression          ::= RangeStart '..' RangeEnd
                           | ShiftExpression ;

RangeStart               ::= RangeIndex? ;
RangeEnd                 ::= RangeIndex? ;

RangeIndex               ::= '^'? AdditiveExpression ;

ShiftExpression          ::= AdditiveExpression {('<<' | '>>') AdditiveExpression} ;

AdditiveExpression       ::= MultiplicativeExpression {('+' | '-') MultiplicativeExpression} ;
MultiplicativeExpression ::= UnaryExpression {('*' | '/' | '%') UnaryExpression} ;

UnaryExpression          ::= LambdaExpression
                           | PostfixExpression
                           | ('+' | '-' | '!') UnaryExpression
                           | 'fixed' UnaryExpression
                           | StackAllocExpression
                           | 'await' UnaryExpression
                           | CastExpression ;

StackAllocExpression     ::= 'stackalloc' Type '[' Expression ']' ;

LambdaExpression         ::= 'async'? LambdaParameterClause ReturnTypeClause? '=>' Expression ;
LambdaParameterClause    ::= '(' LambdaParameterList? ')' | Parameter ;
LambdaParameterList      ::= LambdaParameter {',' LambdaParameter} ;
LambdaParameter          ::= Parameter
                           | PositionalPattern
                           | SequencePattern ;

CastExpression           ::= '(' Type ')' UnaryExpression ;

PostfixExpression        ::= PrimaryExpression { PostfixTrailer } ;

PostfixTrailer           ::= ArgumentList
                           | MemberAccessTrailer
                           | ElementAccessTrailer
                           | SuppressNullableWarningTrailer
                           | PropagateTrailer
                           | ConditionalAccessTrailer
                           | ObjectInitializer
                           | WithExpression ;

ArgumentList             ::= '(' [Argument {',' Argument}] ')' ;
Argument                 ::= [Identifier ':'] ArgumentSpread? Expression ;
ArgumentSpread           ::= '...' ;
AttributeArgumentList    ::= '(' [AttributeArgument {',' AttributeArgument}] ')' ;
AttributeArgument        ::= [Identifier ':'] Expression ; (* Attribute named arguments must use ':'; '=' is not valid syntax. *)

MemberAccessTrailer      ::= '.' Identifier ;
ElementAccessTrailer     ::= '[' Expression ']' ;
SuppressNullableWarningTrailer
                         ::= '!' ;

(* `?` is context-sensitive in postfix position:
   - If followed by `.`, `(`, or `[`, it forms conditional access: `?.`, `?(`, `?[`.
   - Otherwise it is the Result-propagation postfix operator: `<expr>?`. *)
PropagateTrailer          ::= '?' ;
ConditionalAccessTrailer ::= '?' (MemberAccessTrailer | ElementAccessTrailer | ArgumentList) ;

(* ---------- Object initializers and with expressions ---------- *)

ObjectInitializer         ::= '{' { ObjectInitializerEntry } '}' ;

ObjectInitializerEntry    ::= ObjectInitializerAssignmentEntry
                            | ObjectInitializerExpressionEntry ;

ObjectInitializerAssignmentEntry
                           ::= Identifier AssignmentOperator Expression WithEntryTerminator? ;

ObjectInitializerExpressionEntry
                           ::= Expression WithEntryTerminator? ;

WithExpression           ::= 'with' '{' { WithEntry } '}' ;

WithEntry                ::= WithAssignment
                           | WithExpressionEntry ;

WithAssignment           ::= Identifier AssignmentOperator Expression WithEntryTerminator? ;

WithExpressionEntry      ::= Expression WithEntryTerminator? ;

WithEntryTerminator      ::= ',' | end-of-line-trivia | ';' ;
MemberBindingExpression  ::= '.' Identifier ;
(* Member binding is target-typed; for discriminated unions, `.Case(...)` binds
   to a case on the expected union type. *)

(* ---------- Primaries ----------
   NOTE: Block and IfExpression can appear as expressions.
         While and for constructs exist only as statements. *)

PrimaryExpression        ::= Literal
                           | DefaultExpression
                           | TypeOfExpression
                           | NameOfExpression
                           | FreestandingMacroExpression
                           | CollectionExpression
                           | ArrayExpression
                           | Identifier
                           | MemberBindingExpression
                           | TupleExpression
                           | ParenthesizedExpression
                           | TryExpression
                           | UnsafeExpression
                           | ReturnExpression
                           | ThrowExpression
                           | BreakExpression
                           | ContinueExpression
                           | YieldExpression
                           | MacroContributionExpression
                           | Block
                           | IfExpression
                           | IfPatternExpression
                           | InterpolatedStringExpression ;

DefaultExpression        ::= 'default' | 'default' '(' Type ')' ;

TypeOfExpression         ::= 'typeof' '(' Type ')' ;
NameOfExpression         ::= 'nameof' '(' NameOfOperand ')' ;
FreestandingMacroExpression ::= QualifiedName '!'
                             ( ArgumentList
                             | [ArgumentList] MacroTokenTree ) ;

MacroTokenTree           ::= '{' /* lossless raw source with balanced braces */ '}' ;

(* `nameof` is a compile-time-only expression that produces the unqualified name of the referenced symbol.
   The operand is syntactic and is validated by the binder. *)
NameOfOperand            ::= Identifier
                           | MemberAccessExpression
                           | MemberBindingExpression
                           | QualifiedName ;

TryExpression            ::= 'try' ['?'] Expression ;
UnsafeExpression         ::= 'unsafe' Block ;
ReturnExpression         ::= 'return' Expression ;
ThrowExpression          ::= 'throw' Expression ;
BreakExpression          ::= 'break' [Identifier] ;
ContinueExpression       ::= 'continue' [Identifier] ;
YieldExpression          ::= 'yield' ['from'] Expression ;
MacroContributionExpression
                         ::= ('expand' | 'replace' | 'introduce') Expression ;
(* Macro contribution expressions are contextual to macro declarations. *)

Block                    ::= '{' {Statement} '}' ;

IfExpression             ::= 'if' Expression Expression 'else' Expression ;
IfPatternExpression      ::= 'if' BindingKeyword Pattern '=' Expression Expression 'else' Expression ;

InterpolatedStringExpression
                         ::= '"' {InterpolatedStringContent} '"' ;
InterpolatedStringContent ::= InterpolatedStringText | Interpolation ;
InterpolatedStringText   ::= /* text segment without ${ or closing quote */ ;
Interpolation            ::= '${' Expression '}' ;

(* Collection elements may also be separated by an implicit newline boundary.
   In the syntax tree that boundary is represented by `SyntaxKind.None`,
   not a concrete newline token. *)
CollectionExpression     ::= ['!'] '[' [CollectionElement {CollectionSeparator CollectionElement} [CollectionSeparator]] ']' ;
ArrayExpression          ::= '[|' [CollectionElement {CollectionSeparator CollectionElement} [CollectionSeparator]] '|]' ;
CollectionSeparator      ::= ',' ;
CollectionElement        ::= Expression
                           | Expression ':' Expression
                           | '...' Expression
                           | '...' Expression ':' Expression
                           | CollectionComprehensionElement ;
ComprehensionTarget     ::= Identifier | Pattern ;
CollectionComprehensionElement
                         ::= 'for' ['let' | 'val' | 'var'] ComprehensionTarget 'in' Expression ['if' Expression] '=>' Expression
                           | 'for' ['let' | 'val' | 'var'] ComprehensionTarget 'in' Expression ['if' Expression] '=>' Expression ':' Expression ;

TupleExpression          ::= '(' TupleElement {',' TupleElement} ')' ;
TupleElement             ::= [Identifier ':'] Expression ;

ParenthesizedExpression  ::= '(' Expression ')' ;

Literal                  ::= NumericLiteral
                           | StringLiteral
                           | EncodedStringLiteral
                           | MultilineStringLiteral
                           | 'true' | 'false' | 'null' ;

(* ---------- Types ---------- *)

Type                     ::= UnionType ;

UnionType                ::= FunctionType {'|' FunctionType} ;

ByRefType                ::= '&' Type ;
PointerType              ::= '*' Type ;

FunctionType             ::= FunctionParameterClause '->' Type
                           | NullableType ;

FunctionParameterClause  ::= FunctionTypeParameterList | NullableType ;

FunctionTypeParameterList
                         ::= '(' [Type {',' Type}] ')' ;

NullableType             ::= PrimaryType ['?'] ;

PrimaryType              ::= TupleType
                           | GenericType
                           | SimpleType
                           | ParenthesizedType ;

SimpleType               ::= BuiltinType | QualifiedName ;
BuiltinType              ::= 'bool'
                           | 'char'
                           | 'sbyte'
                           | 'byte'
                           | 'short'
                           | 'ushort'
                           | 'int'
                           | 'uint'
                           | 'long'
                           | 'ulong'
                           | 'nint'
                           | 'nuint'
                           | 'float'
                           | 'double'
                           | 'decimal'
                           | 'string'
                           | 'object'
                           | 'unit'
                           | '(' ')' ;

GenericType              ::= QualifiedName '<' TypeList '>' ;
TypeList                 ::= Type {',' Type} ;

TupleType                ::= '(' TupleTypeElement {',' TupleTypeElement} ')' ;
TupleTypeElement         ::= [Identifier ':'] Type ;

ParenthesizedType        ::= '(' Type ')' ;

QualifiedName            ::= Identifier {'.' Identifier} ;
(* `Union.Case` is parsed as a QualifiedName/member chain and may be rebound by
   semantics as a discriminated-union case reference. *)

Identifier               ::= /* ASCII letter, '_' or '$' followed by letters, digits, '_' or '$'.
                               The single '_' token is reserved for discards. */ ;


StringLiteral            ::= '"' {InterpolatedStringText | Interpolation} '"' ;
EncodedStringLiteral     ::= (StringLiteral | MultilineStringLiteral) EncodingSuffix ;
EncodingSuffix           ::= 'u8' | 'ascii' ; (* suffix must be adjacent to the closing delimiter; interpolation is not permitted in encoded literals *)
InterpolatedStringText   ::= /* content with escapes */ ;
Interpolation            ::= '$' Identifier | '$' '{' Expression '}' ;

(* Multiline string literals are triple-quoted strings that may span multiple lines.
   They are raw (no escape-sequence decoding). Interpolation is permitted using the same
   forms as regular strings: `$Identifier` and `${ Expression }`.

   NOTE: Non-normative. The lexer produces the triple-quoted literal as a single token;
   the parser/binder interpret interpolation within its raw text. *)
MultilineStringLiteral        ::= '"""' {MultilineInterpolatedContent} '"""' ;
MultilineInterpolatedContent  ::= MultilineInterpolatedText | Interpolation ;
MultilineInterpolatedText     ::= /* raw text segment; may include newlines; stops before an interpolation start or closing delimiter */ ;

(* ---------- Numeric literals (lexical forms) ---------- *)

(* Numeric literals are lexically resolved by the lexer. This grammar documents the allowed surface forms.

   Examples:
     1        (* integer *)
     1.0      (* decimal-point real *)
     .0       (* leading-dot real *)
     1e3      (* exponent real *)
     0xFF     (* hex integer *)
     0b1010   (* binary integer *)

   Suffixes (optional, case-insensitive):
     B  -> byte
     L  -> long
     F  -> float
     D  -> double
     M  -> decimal

   If no suffix is present, the default type is determined by the lexer:
     - integer literals default to int (or a wider integral type if specified/required by the binder)
     - real literals default to double
*)

NumericLiteral           ::= IntegerLiteral NumericSuffix?
                           | RealLiteral NumericSuffix? ;

NumericSuffix            ::=  'b' | 'B'
                           | 'l' | 'L'
                           | 'f' | 'F'
                           | 'd' | 'D'
                           | 'm' | 'M' ;

IntegerLiteral           ::= DecimalIntegerLiteral
                           | HexIntegerLiteral
                           | BinaryIntegerLiteral ;

DecimalIntegerLiteral    ::= DecimalDigits ;
HexIntegerLiteral        ::= '0' ('x' | 'X') HexDigits ;
BinaryIntegerLiteral     ::= '0' ('b' | 'B') BinaryDigits ;

(* Real literals support:
   - a decimal point: 1.0, 1., .0
   - an exponent: 1e3, 1.0e-3, .5E+2
   A real literal must contain either a '.' or an exponent part (or both). *)
RealLiteral              ::= RealWithDot ExponentPart?
                           | DecimalDigits ExponentPart ;

RealWithDot              ::= DecimalDigits '.' DecimalDigits?
                           | '.' DecimalDigits ;

ExponentPart             ::= ('e' | 'E') Sign? DecimalDigits ;
Sign                     ::= '+' | '-' ;

DecimalDigits            ::= DecimalDigit { DecimalDigit | '_' } ;
HexDigits                ::= HexDigit { HexDigit | '_' } ;
BinaryDigits             ::= BinaryDigit { BinaryDigit | '_' } ;

DecimalDigit             ::= '0'..'9' ;
HexDigit                 ::= DecimalDigit | 'a'..'f' | 'A'..'F' ;
BinaryDigit              ::= '0' | '1' ;