Skip to content

RCE language specification, draft 0.5

3. Syntactic grammar

This section is the complete grammar: which token sequences are programs. Its EBNF is read by the machine check (3.12) and checked to be LALR(1) (parsable left to right with one token of lookahead and no conflicts), so every program has exactly one parse. Example: fn half(x: u64) -> u64 = x / 2 is a function declaration with an arrow body.

The grammar is LALR(1) with no conflicts (checked, 3.12). Where a reader might see two parses, the grammar admits exactly one; the resolutions are listed in 3.11.

3.1 Modules

Grammar SourceFile, ModuleHeader, Path, Item, UseDecl
SourceFile={ NEWLINE } [ ModuleHeader ] { Item } .ModuleHeader="module" Path NEWLINE .Path=NAME { "." NAME } .Item=UseDecl ∣ IntentDecl ∣ ExampleDecl ∣ CheckDecl∣ [ "pub" ] ( ConstDecl ∣ TypeDecl ∣ StructDecl ∣ KindDecl∣ TraitDecl ∣ FnDecl ∣ ActorDecl )∣ StateDecl ∣ EventDecl ∣ ErrorDecl ∣ StepDecl ∣ ImplDecl∣ ExternDecl .UseDecl="use" Path [ "as" NAME ] NEWLINE .\begin{array}{rcl}\textsf{SourceFile} & = & \{\ \texttt{NEWLINE}\ \}\ [\ \texttt{ModuleHeader}\ ]\ \{\ \texttt{Item}\ \}\ . \\ \textsf{ModuleHeader} & = & \texttt{"module"}\ \texttt{Path}\ \texttt{NEWLINE}\ . \\ \textsf{Path} & = & \texttt{NAME}\ \{\ \texttt{"."}\ \texttt{NAME}\ \}\ . \\ \textsf{Item} & = & \texttt{UseDecl}\ |\ \texttt{IntentDecl}\ |\ \texttt{ExampleDecl}\ |\ \texttt{CheckDecl} \\ & & |\ [\ \texttt{"pub"}\ ]\ (\ \texttt{ConstDecl}\ |\ \texttt{TypeDecl}\ |\ \texttt{StructDecl}\ |\ \texttt{KindDecl} \\ & & |\ \texttt{TraitDecl}\ |\ \texttt{FnDecl}\ |\ \texttt{ActorDecl}\ ) \\ & & |\ \texttt{StateDecl}\ |\ \texttt{EventDecl}\ |\ \texttt{ErrorDecl}\ |\ \texttt{StepDecl}\ |\ \texttt{ImplDecl} \\ & & |\ \texttt{ExternDecl}\ . \\ \textsf{UseDecl} & = & \texttt{"use"}\ \texttt{Path}\ [\ \texttt{"as"}\ \texttt{NAME}\ ]\ \texttt{NEWLINE}\ . \\\end{array}
Plain text of this block
SourceFile   = { NEWLINE } [ ModuleHeader ] { Item } .
ModuleHeader = "module" Path NEWLINE .
Path         = NAME { "." NAME } .
Item         = UseDecl | IntentDecl | ExampleDecl | CheckDecl
             | [ "pub" ] ( ConstDecl | TypeDecl | StructDecl | KindDecl
                         | TraitDecl | FnDecl | ActorDecl )
             | StateDecl | EventDecl | ErrorDecl | StepDecl | ImplDecl
             | ExternDecl .
UseDecl      = "use" Path [ "as" NAME ] NEWLINE .

3.2 Intent

Grammar IntentDecl, IntentLine, ExampleDecl, EventRef, Outcome, CheckDecl
IntentDecl="intent" STRING NEWLINE [ INDENT IntentLine { IntentLine } DEDENT ] .IntentLine=ExampleDecl ∣ CheckDecl ∣ STRING NEWLINE .ExampleDecl="example" [ EventRef { "," EventRef } ] "->" Outcome NEWLINE .EventRef=NAME [ "(" [ Args ] ")" ] .Outcome=Expr ∣ "refused" ":" NAME .CheckDecl="check" Expr NEWLINE .\begin{array}{rcl}\textsf{IntentDecl} & = & \texttt{"intent"}\ \texttt{STRING}\ \texttt{NEWLINE}\ [\ \texttt{INDENT}\ \texttt{IntentLine}\ \{\ \texttt{IntentLine}\ \}\ \texttt{DEDENT}\ ]\ . \\ \textsf{IntentLine} & = & \texttt{ExampleDecl}\ |\ \texttt{CheckDecl}\ |\ \texttt{STRING}\ \texttt{NEWLINE}\ . \\ \textsf{ExampleDecl} & = & \texttt{"example"}\ [\ \texttt{EventRef}\ \{\ \texttt{","}\ \texttt{EventRef}\ \}\ ]\ \texttt{"->"}\ \texttt{Outcome}\ \texttt{NEWLINE}\ . \\ \textsf{EventRef} & = & \texttt{NAME}\ [\ \texttt{"("}\ [\ \texttt{Args}\ ]\ \texttt{")"}\ ]\ . \\ \textsf{Outcome} & = & \texttt{Expr}\ |\ \texttt{"refused"}\ \texttt{":"}\ \texttt{NAME}\ . \\ \textsf{CheckDecl} & = & \texttt{"check"}\ \texttt{Expr}\ \texttt{NEWLINE}\ . \\\end{array}
Plain text of this block
IntentDecl  = "intent" STRING NEWLINE [ INDENT IntentLine { IntentLine } DEDENT ] .
IntentLine  = ExampleDecl | CheckDecl | STRING NEWLINE .
ExampleDecl = "example" [ EventRef { "," EventRef } ] "->" Outcome NEWLINE .
EventRef    = NAME [ "(" [ Args ] ")" ] .
Outcome     = Expr | "refused" ":" NAME .
CheckDecl   = "check" Expr NEWLINE .

3.3 Data declarations

Grammar ConstDecl, TypeDecl, StructDecl, Field, StateDecl, EventDecl, ErrorDecl, Payload, and 3 more
ConstDecl="const" NAME [ ":" Type ] "=" Expr NEWLINE .TypeDecl="type" NAME [ Generics ] "=" Type [ "where" Expr ] NEWLINE .StructDecl=[ "linear" ] "struct" NAME [ Generics ] NEWLINE [ INDENT Field { Field } DEDENT ] .Field=NAME ":" Type [ "=" Expr ] NEWLINE .StateDecl="state" NAME NEWLINE INDENT Field { Field } DEDENT .EventDecl="event" NAME [ Payload ] NEWLINE .ErrorDecl="error" NAME [ Payload ] NEWLINE .Payload="(" [ FieldItem { "," FieldItem } [ "," ] ] ")" .FieldItem=NAME ":" Type .KindDecl="kind" NAME [ Generics ] NEWLINE INDENT Variant { Variant } DEDENT .Variant=NAME [ Payload ] NEWLINE .\begin{array}{rcl}\textsf{ConstDecl} & = & \texttt{"const"}\ \texttt{NAME}\ [\ \texttt{":"}\ \texttt{Type}\ ]\ \texttt{"="}\ \texttt{Expr}\ \texttt{NEWLINE}\ . \\ \textsf{TypeDecl} & = & \texttt{"type"}\ \texttt{NAME}\ [\ \texttt{Generics}\ ]\ \texttt{"="}\ \texttt{Type}\ [\ \texttt{"where"}\ \texttt{Expr}\ ]\ \texttt{NEWLINE}\ . \\ \textsf{StructDecl} & = & [\ \texttt{"linear"}\ ]\ \texttt{"struct"}\ \texttt{NAME}\ [\ \texttt{Generics}\ ]\ \texttt{NEWLINE}\ [\ \texttt{INDENT}\ \texttt{Field}\ \{\ \texttt{Field}\ \}\ \texttt{DEDENT}\ ]\ . \\ \textsf{Field} & = & \texttt{NAME}\ \texttt{":"}\ \texttt{Type}\ [\ \texttt{"="}\ \texttt{Expr}\ ]\ \texttt{NEWLINE}\ . \\ \textsf{StateDecl} & = & \texttt{"state"}\ \texttt{NAME}\ \texttt{NEWLINE}\ \texttt{INDENT}\ \texttt{Field}\ \{\ \texttt{Field}\ \}\ \texttt{DEDENT}\ . \\ \textsf{EventDecl} & = & \texttt{"event"}\ \texttt{NAME}\ [\ \texttt{Payload}\ ]\ \texttt{NEWLINE}\ . \\ \textsf{ErrorDecl} & = & \texttt{"error"}\ \texttt{NAME}\ [\ \texttt{Payload}\ ]\ \texttt{NEWLINE}\ . \\ \textsf{Payload} & = & \texttt{"("}\ [\ \texttt{FieldItem}\ \{\ \texttt{","}\ \texttt{FieldItem}\ \}\ [\ \texttt{","}\ ]\ ]\ \texttt{")"}\ . \\ \textsf{FieldItem} & = & \texttt{NAME}\ \texttt{":"}\ \texttt{Type}\ . \\ \textsf{KindDecl} & = & \texttt{"kind"}\ \texttt{NAME}\ [\ \texttt{Generics}\ ]\ \texttt{NEWLINE}\ \texttt{INDENT}\ \texttt{Variant}\ \{\ \texttt{Variant}\ \}\ \texttt{DEDENT}\ . \\ \textsf{Variant} & = & \texttt{NAME}\ [\ \texttt{Payload}\ ]\ \texttt{NEWLINE}\ . \\\end{array}
Plain text of this block
ConstDecl  = "const" NAME [ ":" Type ] "=" Expr NEWLINE .
TypeDecl   = "type" NAME [ Generics ] "=" Type [ "where" Expr ] NEWLINE .
StructDecl = [ "linear" ] "struct" NAME [ Generics ] NEWLINE [ INDENT Field { Field } DEDENT ] .
Field      = NAME ":" Type [ "=" Expr ] NEWLINE .
StateDecl  = "state" NAME NEWLINE INDENT Field { Field } DEDENT .
EventDecl  = "event" NAME [ Payload ] NEWLINE .
ErrorDecl  = "error" NAME [ Payload ] NEWLINE .
Payload    = "(" [ FieldItem { "," FieldItem } [ "," ] ] ")" .
FieldItem  = NAME ":" Type .
KindDecl   = "kind" NAME [ Generics ] NEWLINE INDENT Variant { Variant } DEDENT .
Variant    = NAME [ Payload ] NEWLINE .

3.4 Traits and implementations

Grammar TraitDecl, TraitMember, ImplDecl, ImplMember, Generics, GParam, Bounds
TraitDecl="trait" NAME [ Generics ] [ ":" Bounds ] NEWLINEINDENT TraitMember { TraitMember } DEDENT .TraitMember="type" NAME [ ":" Bounds ] NEWLINE ∣ FnSig NEWLINE .ImplDecl="impl" [ "forall" Generics ] Type [ "for" Type ] NEWLINEINDENT ImplMember { ImplMember } DEDENT .ImplMember=TypeDecl ∣ FnDecl .Generics="[" GParam { "," GParam } "]" .GParam=[ "comptime" ] NAME [ ":" Bounds ] .Bounds=TypePath { "+" TypePath } .\begin{array}{rcl}\textsf{TraitDecl} & = & \texttt{"trait"}\ \texttt{NAME}\ [\ \texttt{Generics}\ ]\ [\ \texttt{":"}\ \texttt{Bounds}\ ]\ \texttt{NEWLINE} \\ & & \texttt{INDENT}\ \texttt{TraitMember}\ \{\ \texttt{TraitMember}\ \}\ \texttt{DEDENT}\ . \\ \textsf{TraitMember} & = & \texttt{"type"}\ \texttt{NAME}\ [\ \texttt{":"}\ \texttt{Bounds}\ ]\ \texttt{NEWLINE}\ |\ \texttt{FnSig}\ \texttt{NEWLINE}\ . \\ \textsf{ImplDecl} & = & \texttt{"impl"}\ [\ \texttt{"forall"}\ \texttt{Generics}\ ]\ \texttt{Type}\ [\ \texttt{"for"}\ \texttt{Type}\ ]\ \texttt{NEWLINE} \\ & & \texttt{INDENT}\ \texttt{ImplMember}\ \{\ \texttt{ImplMember}\ \}\ \texttt{DEDENT}\ . \\ \textsf{ImplMember} & = & \texttt{TypeDecl}\ |\ \texttt{FnDecl}\ . \\ \textsf{Generics} & = & \texttt{"["}\ \texttt{GParam}\ \{\ \texttt{","}\ \texttt{GParam}\ \}\ \texttt{"]"}\ . \\ \textsf{GParam} & = & [\ \texttt{"comptime"}\ ]\ \texttt{NAME}\ [\ \texttt{":"}\ \texttt{Bounds}\ ]\ . \\ \textsf{Bounds} & = & \texttt{TypePath}\ \{\ \texttt{"+"}\ \texttt{TypePath}\ \}\ . \\\end{array}
Plain text of this block
TraitDecl   = "trait" NAME [ Generics ] [ ":" Bounds ] NEWLINE
              INDENT TraitMember { TraitMember } DEDENT .
TraitMember = "type" NAME [ ":" Bounds ] NEWLINE | FnSig NEWLINE .
ImplDecl    = "impl" [ "forall" Generics ] Type [ "for" Type ] NEWLINE
              INDENT ImplMember { ImplMember } DEDENT .
ImplMember  = TypeDecl | FnDecl .
Generics    = "[" GParam { "," GParam } "]" .
GParam      = [ "comptime" ] NAME [ ":" Bounds ] .
Bounds      = TypePath { "+" TypePath } .

impl Show for Point implements trait Show for Point; impl Point (no for) adds inherent functions. forall [T: Show] binds the impl's type parameters (3.11 R6 says why the keyword is needed).

3.5 Functions, steps and actors

Grammar FnSig, FnDecl, ExternDecl, Params, Param, SelfParam, StepDecl, StepBody, and 3 more
FnSig=[ "comptime" ] "fn" NAME [ Generics ] "(" [ Params ] ")" [ "->" Type ][ "bound" INT ] .(6.7)FnDecl=FnSig ( Block ∣ "=" Expr NEWLINE ) .ExternDecl="extern" STRING FnSig NEWLINE .(5.11)Params=Param { "," Param } [ "," ] .Param=[ "comptime" ] [ NAME ] NAME ":" Type ∣ SelfParam .SelfParam="self" ∣ "&" "self" ∣ "&" "mut" "self" .StepDecl="step" NAME "on" Pattern [ "if" Expr ] StepBody .StepBody="->" Expr NEWLINE ∣ Block .ActorDecl="actor" NAME NEWLINE INDENT ActorMember { ActorMember } DEDENT .ActorMember=Field ∣ Handler ∣ FnDecl .Handler="on" Pattern [ "if" Expr ] StepBody .\begin{array}{rcl}\textsf{FnSig} & = & [\ \texttt{"comptime"}\ ]\ \texttt{"fn"}\ \texttt{NAME}\ [\ \texttt{Generics}\ ]\ \texttt{"("}\ [\ \texttt{Params}\ ]\ \texttt{")"}\ [\ \texttt{"->"}\ \texttt{Type}\ ] \\ & & [\ \texttt{"bound"}\ \texttt{INT}\ ]\ .\quad\textcolor{gray}{(6.7)} \\ \textsf{FnDecl} & = & \texttt{FnSig}\ (\ \texttt{Block}\ |\ \texttt{"="}\ \texttt{Expr}\ \texttt{NEWLINE}\ )\ . \\ \textsf{ExternDecl} & = & \texttt{"extern"}\ \texttt{STRING}\ \texttt{FnSig}\ \texttt{NEWLINE}\ .\quad\textcolor{gray}{(5.11)} \\ \textsf{Params} & = & \texttt{Param}\ \{\ \texttt{","}\ \texttt{Param}\ \}\ [\ \texttt{","}\ ]\ . \\ \textsf{Param} & = & [\ \texttt{"comptime"}\ ]\ [\ \texttt{NAME}\ ]\ \texttt{NAME}\ \texttt{":"}\ \texttt{Type}\ |\ \texttt{SelfParam}\ . \\ \textsf{SelfParam} & = & \texttt{"self"}\ |\ \texttt{"\&"}\ \texttt{"self"}\ |\ \texttt{"\&"}\ \texttt{"mut"}\ \texttt{"self"}\ . \\ \textsf{StepDecl} & = & \texttt{"step"}\ \texttt{NAME}\ \texttt{"on"}\ \texttt{Pattern}\ [\ \texttt{"if"}\ \texttt{Expr}\ ]\ \texttt{StepBody}\ . \\ \textsf{StepBody} & = & \texttt{"->"}\ \texttt{Expr}\ \texttt{NEWLINE}\ |\ \texttt{Block}\ . \\ \textsf{ActorDecl} & = & \texttt{"actor"}\ \texttt{NAME}\ \texttt{NEWLINE}\ \texttt{INDENT}\ \texttt{ActorMember}\ \{\ \texttt{ActorMember}\ \}\ \texttt{DEDENT}\ . \\ \textsf{ActorMember} & = & \texttt{Field}\ |\ \texttt{Handler}\ |\ \texttt{FnDecl}\ . \\ \textsf{Handler} & = & \texttt{"on"}\ \texttt{Pattern}\ [\ \texttt{"if"}\ \texttt{Expr}\ ]\ \texttt{StepBody}\ . \\\end{array}
Plain text of this block
FnSig     = [ "comptime" ] "fn" NAME [ Generics ] "(" [ Params ] ")" [ "->" Type ]
            [ "bound" INT ] .                                 (6.7)
FnDecl    = FnSig ( Block | "=" Expr NEWLINE ) .
ExternDecl = "extern" STRING FnSig NEWLINE .            (5.11)
Params    = Param { "," Param } [ "," ] .
Param     = [ "comptime" ] [ NAME ] NAME ":" Type | SelfParam .
SelfParam = "self" | "&" "self" | "&" "mut" "self" .
StepDecl  = "step" NAME "on" Pattern [ "if" Expr ] StepBody .
StepBody  = "->" Expr NEWLINE | Block .
ActorDecl = "actor" NAME NEWLINE INDENT ActorMember { ActorMember } DEDENT .
ActorMember = Field | Handler | FnDecl .
Handler   = "on" Pattern [ "if" Expr ] StepBody .

In Param, from src: u8 declares argument label from and parameter name src (Swift); src: u8 alone uses src as both.

3.6 Types

Listed from loosest to tightest binding.

Grammar Type, OptType, BorrowType, RegionType, BaseType, TypePath, TypeList
Type=OptType [ "!" OptType ] .error union T ! EOptType=BorrowType [ "?" ] .optionT?BorrowType="&" [ "mut" ] BorrowType ∣ RegionType .borrow&T, &mut TRegionType=BaseType [ "@" NAME ] .regionT @rBaseType=TypePath∣ "(" ")"unit∣ "(" Type "," [ Type { "," Type } [ "," ] ] ")"tuple∣ "(" Type ")"∣ "[" Type "]"slice∣ "[" Type ";" Expr "]"array, comptime length∣ "chan" BaseTypechannel∣ "iter" BaseTypeiterator (result of an iterator function only)∣ "fn" "(" [ TypeList ] ")" "->" BaseType . functionTypePath=Path [ "[" TypeList "]" ] .TypeList=Type { "," Type } [ "," ] .\begin{array}{rcl}\textsf{Type} & = & \texttt{OptType}\ [\ \texttt{"!"}\ \texttt{OptType}\ ]\ .\quad\textcolor{gray}{\text{error}\ \text{union}\ T\ !\ E} \\ \textsf{OptType} & = & \texttt{BorrowType}\ [\ \texttt{"?"}\ ]\ .\quad\textcolor{gray}{\text{option}}\quad\textcolor{gray}{T?} \\ \textsf{BorrowType} & = & \texttt{"\&"}\ [\ \texttt{"mut"}\ ]\ \texttt{BorrowType}\ |\ \texttt{RegionType}\ .\quad\textcolor{gray}{\text{borrow}}\quad\textcolor{gray}{\&T,\ \&\text{mut}\ T} \\ \textsf{RegionType} & = & \texttt{BaseType}\ [\ \texttt{"@"}\ \texttt{NAME}\ ]\ .\quad\textcolor{gray}{\text{region}}\quad\textcolor{gray}{T\ @r} \\ \textsf{BaseType} & = & \texttt{TypePath} \\ & & |\ \texttt{"("}\ \texttt{")"}\quad\textcolor{gray}{\text{unit}} \\ & & |\ \texttt{"("}\ \texttt{Type}\ \texttt{","}\ [\ \texttt{Type}\ \{\ \texttt{","}\ \texttt{Type}\ \}\ [\ \texttt{","}\ ]\ ]\ \texttt{")"}\quad\textcolor{gray}{\text{tuple}} \\ & & |\ \texttt{"("}\ \texttt{Type}\ \texttt{")"} \\ & & |\ \texttt{"["}\ \texttt{Type}\ \texttt{"]"}\quad\textcolor{gray}{\text{slice}} \\ & & |\ \texttt{"["}\ \texttt{Type}\ \texttt{";"}\ \texttt{Expr}\ \texttt{"]"}\quad\textcolor{gray}{\text{array},\ \text{comptime}\ \text{length}} \\ & & |\ \texttt{"chan"}\ \texttt{BaseType}\quad\textcolor{gray}{\text{channel}} \\ & & |\ \texttt{"iter"}\ \texttt{BaseType}\quad\textcolor{gray}{\text{iterator}\ (\text{result}\ \text{of}\ \text{an}\ \text{iterator}\ \text{function}\ \text{only})} \\ & & |\ \texttt{"fn"}\ \texttt{"("}\ [\ \texttt{TypeList}\ ]\ \texttt{")"}\ \texttt{"->"}\ \texttt{BaseType}\ .\ \texttt{function} \\ \textsf{TypePath} & = & \texttt{Path}\ [\ \texttt{"["}\ \texttt{TypeList}\ \texttt{"]"}\ ]\ . \\ \textsf{TypeList} & = & \texttt{Type}\ \{\ \texttt{","}\ \texttt{Type}\ \}\ [\ \texttt{","}\ ]\ . \\\end{array}
Plain text of this block
Type        = OptType [ "!" OptType ] .                  error union  T ! E
OptType     = BorrowType [ "?" ] .                       option       T?
BorrowType  = "&" [ "mut" ] BorrowType | RegionType .    borrow       &T, &mut T
RegionType  = BaseType [ "@" NAME ] .                    region       T @r
BaseType    = TypePath
            | "(" ")"                                    unit
            | "(" Type "," [ Type { "," Type } [ "," ] ] ")"   tuple
            | "(" Type ")"
            | "[" Type "]"                               slice
            | "[" Type ";" Expr "]"                      array, comptime length
            | "chan" BaseType                            channel
            | "iter" BaseType                            iterator (result of an iterator function only)
            | "fn" "(" [ TypeList ] ")" "->" BaseType .  function
TypePath    = Path [ "[" TypeList "]" ] .
TypeList    = Type { "," Type } [ "," ] .

3.7 Statements

Grammar Block, Stmt, SimpleStmt, AssignOp, LetStmt, VarStmt, IfStmt, WhileStmt, and 17 more
Block=NEWLINE INDENT Stmt { Stmt } DEDENT .Stmt=SimpleStmt ∣ LetStmt ∣ VarStmt ∣ IfStmt ∣ WhileStmt ∣ LoopStmt∣ ForStmt ∣ MatchStmt ∣ ReturnStmt ∣ BreakStmt ∣ ContinueStmt∣ EmitStmt ∣ FailStmt ∣ SpawnStmt ∣ SelectStmt ∣ ArenaStmt∣ DeviceStmt ∣ YieldStmt ∣ ComptimeStmt ∣ CheckDecl ∣ PassStmt .SimpleStmt=Expr [ AssignOp Expr ∣ "<-" Expr ] NEWLINE .AssignOp="=" ∣ "+=" ∣ "-=" ∣ "*=" ∣ "/=" ∣ "%=" ∣ "&=" ∣ "|=" ∣ "^=" ∣ "<<=" ∣ ">>=" .LetStmt="let" Pattern [ ":" Type ] "=" Expr NEWLINE .VarStmt="var" NAME [ ":" Type ] "=" Expr NEWLINE .IfStmt="if" Expr Block { "elif" Expr Block } [ "else" Block ] .WhileStmt="while" Expr [ Bound ] Block .LoopStmt="loop" [ Bound ] Block .Bound="bound" Expr .ForStmt="for" Pattern "in" Expr Block .MatchStmt="match" Expr NEWLINE INDENT Arm { Arm } DEDENT .Arm=Pattern [ "if" Expr ] ArmBody .ArmBody="->" InlineStmt ∣ Block .InlineStmt=SimpleStmt ∣ ReturnStmt ∣ BreakStmt ∣ ContinueStmt ∣ PassStmt ∣ EmitStmt ∣ FailStmt ∣ YieldStmt .ReturnStmt="return" [ Expr ] NEWLINE .BreakStmt="break" NEWLINE .ContinueStmt = "continue" NEWLINE .PassStmt="pass" NEWLINE .EmitStmt= "emit" Expr NEWLINE .FailStmt="fail" Expr NEWLINE . SpawnStmt= "spawn" Expr NEWLINE .YieldStmt="yield" Expr NEWLINE .SelectStmt="select" NEWLINE INDENT SelectArm { SelectArm } DEDENT .SelectArm="recv" Pattern "from" Expr ArmBody∣ "send" Expr "to" Expr ArmBody∣ "after" Expr ArmBody∣ "default" ArmBody .ArenaStmt="with" "arena" NAME [ Bound ] Block .(capacity, 5.7)DeviceStmt="with" "device" NAME [ Bound ] Block . (accelerator region, 5.13)ComptimeStmt="comptime" Block .\begin{array}{rcl}\textsf{Block} & = & \texttt{NEWLINE}\ \texttt{INDENT}\ \texttt{Stmt}\ \{\ \texttt{Stmt}\ \}\ \texttt{DEDENT}\ . \\ \textsf{Stmt} & = & \texttt{SimpleStmt}\ |\ \texttt{LetStmt}\ |\ \texttt{VarStmt}\ |\ \texttt{IfStmt}\ |\ \texttt{WhileStmt}\ |\ \texttt{LoopStmt} \\ & & |\ \texttt{ForStmt}\ |\ \texttt{MatchStmt}\ |\ \texttt{ReturnStmt}\ |\ \texttt{BreakStmt}\ |\ \texttt{ContinueStmt} \\ & & |\ \texttt{EmitStmt}\ |\ \texttt{FailStmt}\ |\ \texttt{SpawnStmt}\ |\ \texttt{SelectStmt}\ |\ \texttt{ArenaStmt} \\ & & |\ \texttt{DeviceStmt}\ |\ \texttt{YieldStmt}\ |\ \texttt{ComptimeStmt}\ |\ \texttt{CheckDecl}\ |\ \texttt{PassStmt}\ . \\ \textsf{SimpleStmt} & = & \texttt{Expr}\ [\ \texttt{AssignOp}\ \texttt{Expr}\ |\ \texttt{"<-"}\ \texttt{Expr}\ ]\ \texttt{NEWLINE}\ . \\ \textsf{AssignOp} & = & \texttt{"="}\ |\ \texttt{"+="}\ |\ \texttt{"-="}\ |\ \texttt{"*="}\ |\ \texttt{"/="}\ |\ \texttt{"\%="}\ |\ \texttt{"\&="}\ |\ \texttt{"|="}\ |\ \texttt{"\textasciicircum ="}\ |\ \texttt{"<<="}\ |\ \texttt{">>="}\ . \\ \textsf{LetStmt} & = & \texttt{"let"}\ \texttt{Pattern}\ [\ \texttt{":"}\ \texttt{Type}\ ]\ \texttt{"="}\ \texttt{Expr}\ \texttt{NEWLINE}\ . \\ \textsf{VarStmt} & = & \texttt{"var"}\ \texttt{NAME}\ [\ \texttt{":"}\ \texttt{Type}\ ]\ \texttt{"="}\ \texttt{Expr}\ \texttt{NEWLINE}\ . \\ \textsf{IfStmt} & = & \texttt{"if"}\ \texttt{Expr}\ \texttt{Block}\ \{\ \texttt{"elif"}\ \texttt{Expr}\ \texttt{Block}\ \}\ [\ \texttt{"else"}\ \texttt{Block}\ ]\ . \\ \textsf{WhileStmt} & = & \texttt{"while"}\ \texttt{Expr}\ [\ \texttt{Bound}\ ]\ \texttt{Block}\ . \\ \textsf{LoopStmt} & = & \texttt{"loop"}\ [\ \texttt{Bound}\ ]\ \texttt{Block}\ . \\ \textsf{Bound} & = & \texttt{"bound"}\ \texttt{Expr}\ . \\ \textsf{ForStmt} & = & \texttt{"for"}\ \texttt{Pattern}\ \texttt{"in"}\ \texttt{Expr}\ \texttt{Block}\ . \\ \textsf{MatchStmt} & = & \texttt{"match"}\ \texttt{Expr}\ \texttt{NEWLINE}\ \texttt{INDENT}\ \texttt{Arm}\ \{\ \texttt{Arm}\ \}\ \texttt{DEDENT}\ . \\ \textsf{Arm} & = & \texttt{Pattern}\ [\ \texttt{"if"}\ \texttt{Expr}\ ]\ \texttt{ArmBody}\ . \\ \textsf{ArmBody} & = & \texttt{"->"}\ \texttt{InlineStmt}\ |\ \texttt{Block}\ . \\ \textsf{InlineStmt} & = & \texttt{SimpleStmt}\ |\ \texttt{ReturnStmt}\ |\ \texttt{BreakStmt}\ |\ \texttt{ContinueStmt}\ |\ \texttt{PassStmt}\ |\ \texttt{EmitStmt}\ |\ \texttt{FailStmt}\ |\ \texttt{YieldStmt}\ . \\ \textsf{ReturnStmt} & = & \texttt{"return"}\ [\ \texttt{Expr}\ ]\ \texttt{NEWLINE}\ . \\ \textsf{BreakStmt} & = & \texttt{"break"}\ \texttt{NEWLINE}\ .\quad\textcolor{gray}{\text{ContinueStmt}\ =\ \texttt{"continue"}\ \text{NEWLINE}\ .} \\ \textsf{PassStmt} & = & \texttt{"pass"}\ \texttt{NEWLINE}\ .\quad\textcolor{gray}{\text{EmitStmt}}\quad\textcolor{gray}{=\ \texttt{"emit"}\ \text{Expr}\ \text{NEWLINE}\ .} \\ \textsf{FailStmt} & = & \texttt{"fail"}\ \texttt{Expr}\ \texttt{NEWLINE}\ .\ \texttt{SpawnStmt}\quad\textcolor{gray}{=\ \texttt{"spawn"}\ \text{Expr}\ \text{NEWLINE}\ .} \\ \textsf{YieldStmt} & = & \texttt{"yield"}\ \texttt{Expr}\ \texttt{NEWLINE}\ . \\ \textsf{SelectStmt} & = & \texttt{"select"}\ \texttt{NEWLINE}\ \texttt{INDENT}\ \texttt{SelectArm}\ \{\ \texttt{SelectArm}\ \}\ \texttt{DEDENT}\ . \\ \textsf{SelectArm} & = & \texttt{"recv"}\ \texttt{Pattern}\ \texttt{"from"}\ \texttt{Expr}\ \texttt{ArmBody} \\ & & |\ \texttt{"send"}\ \texttt{Expr}\ \texttt{"to"}\ \texttt{Expr}\ \texttt{ArmBody} \\ & & |\ \texttt{"after"}\ \texttt{Expr}\ \texttt{ArmBody} \\ & & |\ \texttt{"default"}\ \texttt{ArmBody}\ . \\ \textsf{ArenaStmt} & = & \texttt{"with"}\ \texttt{"arena"}\ \texttt{NAME}\ [\ \texttt{Bound}\ ]\ \texttt{Block}\ .\quad\textcolor{gray}{(\text{capacity},\ 5.7)} \\ \textsf{DeviceStmt} & = & \texttt{"with"}\ \texttt{"device"}\ \texttt{NAME}\ [\ \texttt{Bound}\ ]\ \texttt{Block}\ .\ (\texttt{accelerator}\ \texttt{region},\ 5.13) \\ \textsf{ComptimeStmt} & = & \texttt{"comptime"}\ \texttt{Block}\ . \\\end{array}
Plain text of this block
Block      = NEWLINE INDENT Stmt { Stmt } DEDENT .
Stmt       = SimpleStmt | LetStmt | VarStmt | IfStmt | WhileStmt | LoopStmt
           | ForStmt | MatchStmt | ReturnStmt | BreakStmt | ContinueStmt
           | EmitStmt | FailStmt | SpawnStmt | SelectStmt | ArenaStmt
           | DeviceStmt | YieldStmt | ComptimeStmt | CheckDecl | PassStmt .
SimpleStmt = Expr [ AssignOp Expr | "<-" Expr ] NEWLINE .
AssignOp   = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" .
LetStmt    = "let" Pattern [ ":" Type ] "=" Expr NEWLINE .
VarStmt    = "var" NAME [ ":" Type ] "=" Expr NEWLINE .
IfStmt     = "if" Expr Block { "elif" Expr Block } [ "else" Block ] .
WhileStmt  = "while" Expr [ Bound ] Block .
LoopStmt   = "loop" [ Bound ] Block .
Bound      = "bound" Expr .
ForStmt    = "for" Pattern "in" Expr Block .
MatchStmt  = "match" Expr NEWLINE INDENT Arm { Arm } DEDENT .
Arm        = Pattern [ "if" Expr ] ArmBody .
ArmBody    = "->" InlineStmt | Block .
InlineStmt = SimpleStmt | ReturnStmt | BreakStmt | ContinueStmt | PassStmt | EmitStmt | FailStmt | YieldStmt .
ReturnStmt = "return" [ Expr ] NEWLINE .
BreakStmt  = "break" NEWLINE .      ContinueStmt = "continue" NEWLINE .
PassStmt   = "pass" NEWLINE .       EmitStmt     = "emit" Expr NEWLINE .
FailStmt   = "fail" Expr NEWLINE .  SpawnStmt    = "spawn" Expr NEWLINE .
YieldStmt  = "yield" Expr NEWLINE .
SelectStmt = "select" NEWLINE INDENT SelectArm { SelectArm } DEDENT .
SelectArm  = "recv" Pattern "from" Expr ArmBody
           | "send" Expr "to" Expr ArmBody
           | "after" Expr ArmBody
           | "default" ArmBody .
ArenaStmt  = "with" "arena" NAME [ Bound ] Block .   (capacity, 5.7)
DeviceStmt = "with" "device" NAME [ Bound ] Block .  (accelerator region, 5.13)
ComptimeStmt = "comptime" Block .

The grammar accepts any expression left of =; rule W-PLACE (section 7) then requires it to be a place (a variable, field, index or tuple member path). This is how Python handles the same problem and keeps the grammar LALR(1).

3.8 Expressions

Precedence, loosest first. All binary levels are left-associative except comparison and range, which are non-associative (at most one operator).

LevelOperatorsProduction
1try e, try e else e, if c then a else b, fn(p) => eExpr
2a catch b, a catch |x| bCatchExpr
3orOrExpr
4andAndExpr
5not (prefix)NotExpr
6== != < <= > >= in not in (non-assoc)CmpExpr
7.. ..= (non-assoc)RangeExpr
8|BorExpr
9^BxorExpr
10&BandExpr
11<< >>ShiftExpr
12+ -AddExpr
13* / %MulExpr
14as TCastExpr
15prefix - ~ & &mut <- comptimeUnaryExpr
16call f(…), index a[i], slice a[i:j], member .x, .0Postfix

Unlike C, bitwise operators bind tighter than comparison, so x & 1 == 1 means (x & 1) == 1.

Grammar Expr, CatchExpr, OrExpr, AndExpr, NotExpr, CmpExpr, CmpOp, RangeExpr, and 13 more
Expr="try" CatchExpr [ "else" CatchExpr ]∣ "if" Expr "then" CatchExpr "else" CatchExpr∣ "fn" "(" [ Params ] ")" "=>" CatchExpr∣ CatchExpr .CatchExpr=OrExpr [ "catch" [ "|" NAME "|" ] OrExpr ] .OrExpr=AndExpr { "or" AndExpr } .AndExpr=NotExpr { "and" NotExpr } .NotExpr="not" NotExpr ∣ CmpExpr .CmpExpr=RangeExpr [ CmpOp RangeExpr ] .CmpOp="==" ∣ "!=" ∣ "<" ∣ "<=" ∣ ">" ∣ ">=" ∣ "in" ∣ "not" "in" .RangeExpr=BorExpr [ ( ".." ∣ "..=" ) BorExpr ] .BorExpr=BxorExpr { "|" BxorExpr } .BxorExpr=BandExpr { "^" BandExpr } .BandExpr=ShiftExpr { "&" ShiftExpr } .ShiftExpr=AddExpr { ( "<<" ∣ ">>" ) AddExpr } .AddExpr=MulExpr { ( "+" ∣ "-" ) MulExpr } .MulExpr=CastExpr { ( "*" ∣ "/" ∣ "%" ) CastExpr } .CastExpr=UnaryExpr [ "as" BaseType ] .UnaryExpr=( "-" ∣ "~" ∣ "&" [ "mut" ] ∣ "<-" ∣ "comptime" ) UnaryExpr ∣ Postfix .Postfix=Primary∣ Postfix "(" [ Args ] ")"∣ Postfix "[" Expr { "," Expr } "]"∣ Postfix "[" [ Expr ] ":" [ Expr ] "]"∣ Postfix "." ( NAME ∣ INT ) .Args=Arg { "," Arg } [ "," ] .Arg=[ NAME ":" ] Expr .Primary=NAME ∣ "self" ∣ INT ∣ FLOAT ∣ STRING ∣ "true" ∣ "false" ∣ "none"∣ "(" ")" ∣ "(" Expr ")" ∣ "(" Expr "," [ Expr { "," Expr } [ "," ] ] ")"∣ "[" "]" ∣ "[" Expr { "," Expr } [ "," ] "]" ∣ "[" Expr ";" Expr "]"∣ "[" Expr "for" Pattern "in" OrExpr [ "if" OrExpr ] "]"∣ "{" "}" ∣ "{" MapEntry { "," MapEntry } [ "," ] "}"∣ "chan" "[" Type "]" "(" [ Expr ] ")" .MapEntry=Expr ":" Expr .\begin{array}{rcl}\textsf{Expr} & = & \texttt{"try"}\ \texttt{CatchExpr}\ [\ \texttt{"else"}\ \texttt{CatchExpr}\ ] \\ & & |\ \texttt{"if"}\ \texttt{Expr}\ \texttt{"then"}\ \texttt{CatchExpr}\ \texttt{"else"}\ \texttt{CatchExpr} \\ & & |\ \texttt{"fn"}\ \texttt{"("}\ [\ \texttt{Params}\ ]\ \texttt{")"}\ \texttt{"=>"}\ \texttt{CatchExpr} \\ & & |\ \texttt{CatchExpr}\ . \\ \textsf{CatchExpr} & = & \texttt{OrExpr}\ [\ \texttt{"catch"}\ [\ \texttt{"|"}\ \texttt{NAME}\ \texttt{"|"}\ ]\ \texttt{OrExpr}\ ]\ . \\ \textsf{OrExpr} & = & \texttt{AndExpr}\ \{\ \texttt{"or"}\ \texttt{AndExpr}\ \}\ . \\ \textsf{AndExpr} & = & \texttt{NotExpr}\ \{\ \texttt{"and"}\ \texttt{NotExpr}\ \}\ . \\ \textsf{NotExpr} & = & \texttt{"not"}\ \texttt{NotExpr}\ |\ \texttt{CmpExpr}\ . \\ \textsf{CmpExpr} & = & \texttt{RangeExpr}\ [\ \texttt{CmpOp}\ \texttt{RangeExpr}\ ]\ . \\ \textsf{CmpOp} & = & \texttt{"=="}\ |\ \texttt{"!="}\ |\ \texttt{"<"}\ |\ \texttt{"<="}\ |\ \texttt{">"}\ |\ \texttt{">="}\ |\ \texttt{"in"}\ |\ \texttt{"not"}\ \texttt{"in"}\ . \\ \textsf{RangeExpr} & = & \texttt{BorExpr}\ [\ (\ \texttt{".."}\ |\ \texttt{"..="}\ )\ \texttt{BorExpr}\ ]\ . \\ \textsf{BorExpr} & = & \texttt{BxorExpr}\ \{\ \texttt{"|"}\ \texttt{BxorExpr}\ \}\ . \\ \textsf{BxorExpr} & = & \texttt{BandExpr}\ \{\ \texttt{"\textasciicircum "}\ \texttt{BandExpr}\ \}\ . \\ \textsf{BandExpr} & = & \texttt{ShiftExpr}\ \{\ \texttt{"\&"}\ \texttt{ShiftExpr}\ \}\ . \\ \textsf{ShiftExpr} & = & \texttt{AddExpr}\ \{\ (\ \texttt{"<<"}\ |\ \texttt{">>"}\ )\ \texttt{AddExpr}\ \}\ . \\ \textsf{AddExpr} & = & \texttt{MulExpr}\ \{\ (\ \texttt{"+"}\ |\ \texttt{"-"}\ )\ \texttt{MulExpr}\ \}\ . \\ \textsf{MulExpr} & = & \texttt{CastExpr}\ \{\ (\ \texttt{"*"}\ |\ \texttt{"/"}\ |\ \texttt{"\%"}\ )\ \texttt{CastExpr}\ \}\ . \\ \textsf{CastExpr} & = & \texttt{UnaryExpr}\ [\ \texttt{"as"}\ \texttt{BaseType}\ ]\ . \\ \textsf{UnaryExpr} & = & (\ \texttt{"-"}\ |\ \texttt{"\textasciitilde "}\ |\ \texttt{"\&"}\ [\ \texttt{"mut"}\ ]\ |\ \texttt{"<-"}\ |\ \texttt{"comptime"}\ )\ \texttt{UnaryExpr}\ |\ \texttt{Postfix}\ . \\ \textsf{Postfix} & = & \texttt{Primary} \\ & & |\ \texttt{Postfix}\ \texttt{"("}\ [\ \texttt{Args}\ ]\ \texttt{")"} \\ & & |\ \texttt{Postfix}\ \texttt{"["}\ \texttt{Expr}\ \{\ \texttt{","}\ \texttt{Expr}\ \}\ \texttt{"]"} \\ & & |\ \texttt{Postfix}\ \texttt{"["}\ [\ \texttt{Expr}\ ]\ \texttt{":"}\ [\ \texttt{Expr}\ ]\ \texttt{"]"} \\ & & |\ \texttt{Postfix}\ \texttt{"."}\ (\ \texttt{NAME}\ |\ \texttt{INT}\ )\ . \\ \textsf{Args} & = & \texttt{Arg}\ \{\ \texttt{","}\ \texttt{Arg}\ \}\ [\ \texttt{","}\ ]\ . \\ \textsf{Arg} & = & [\ \texttt{NAME}\ \texttt{":"}\ ]\ \texttt{Expr}\ . \\ \textsf{Primary} & = & \texttt{NAME}\ |\ \texttt{"self"}\ |\ \texttt{INT}\ |\ \texttt{FLOAT}\ |\ \texttt{STRING}\ |\ \texttt{"true"}\ |\ \texttt{"false"}\ |\ \texttt{"none"} \\ & & |\ \texttt{"("}\ \texttt{")"}\ |\ \texttt{"("}\ \texttt{Expr}\ \texttt{")"}\ |\ \texttt{"("}\ \texttt{Expr}\ \texttt{","}\ [\ \texttt{Expr}\ \{\ \texttt{","}\ \texttt{Expr}\ \}\ [\ \texttt{","}\ ]\ ]\ \texttt{")"} \\ & & |\ \texttt{"["}\ \texttt{"]"}\ |\ \texttt{"["}\ \texttt{Expr}\ \{\ \texttt{","}\ \texttt{Expr}\ \}\ [\ \texttt{","}\ ]\ \texttt{"]"}\ |\ \texttt{"["}\ \texttt{Expr}\ \texttt{";"}\ \texttt{Expr}\ \texttt{"]"} \\ & & |\ \texttt{"["}\ \texttt{Expr}\ \texttt{"for"}\ \texttt{Pattern}\ \texttt{"in"}\ \texttt{OrExpr}\ [\ \texttt{"if"}\ \texttt{OrExpr}\ ]\ \texttt{"]"} \\ & & |\ \texttt{"\{"}\ \texttt{"\}"}\ |\ \texttt{"\{"}\ \texttt{MapEntry}\ \{\ \texttt{","}\ \texttt{MapEntry}\ \}\ [\ \texttt{","}\ ]\ \texttt{"\}"} \\ & & |\ \texttt{"chan"}\ \texttt{"["}\ \texttt{Type}\ \texttt{"]"}\ \texttt{"("}\ [\ \texttt{Expr}\ ]\ \texttt{")"}\ . \\ \textsf{MapEntry} & = & \texttt{Expr}\ \texttt{":"}\ \texttt{Expr}\ . \\\end{array}
Plain text of this block
Expr      = "try" CatchExpr [ "else" CatchExpr ]
          | "if" Expr "then" CatchExpr "else" CatchExpr
          | "fn" "(" [ Params ] ")" "=>" CatchExpr
          | CatchExpr .
CatchExpr = OrExpr [ "catch" [ "|" NAME "|" ] OrExpr ] .
OrExpr    = AndExpr { "or" AndExpr } .
AndExpr   = NotExpr { "and" NotExpr } .
NotExpr   = "not" NotExpr | CmpExpr .
CmpExpr   = RangeExpr [ CmpOp RangeExpr ] .
CmpOp     = "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not" "in" .
RangeExpr = BorExpr [ ( ".." | "..=" ) BorExpr ] .
BorExpr   = BxorExpr { "|" BxorExpr } .
BxorExpr  = BandExpr { "^" BandExpr } .
BandExpr  = ShiftExpr { "&" ShiftExpr } .
ShiftExpr = AddExpr { ( "<<" | ">>" ) AddExpr } .
AddExpr   = MulExpr { ( "+" | "-" ) MulExpr } .
MulExpr   = CastExpr { ( "*" | "/" | "%" ) CastExpr } .
CastExpr  = UnaryExpr [ "as" BaseType ] .
UnaryExpr = ( "-" | "~" | "&" [ "mut" ] | "<-" | "comptime" ) UnaryExpr | Postfix .
Postfix   = Primary
          | Postfix "(" [ Args ] ")"
          | Postfix "[" Expr { "," Expr } "]"
          | Postfix "[" [ Expr ] ":" [ Expr ] "]"
          | Postfix "." ( NAME | INT ) .
Args      = Arg { "," Arg } [ "," ] .
Arg       = [ NAME ":" ] Expr .
Primary   = NAME | "self" | INT | FLOAT | STRING | "true" | "false" | "none"
          | "(" ")" | "(" Expr ")" | "(" Expr "," [ Expr { "," Expr } [ "," ] ] ")"
          | "[" "]" | "[" Expr { "," Expr } [ "," ] "]" | "[" Expr ";" Expr "]"
          | "[" Expr "for" Pattern "in" OrExpr [ "if" OrExpr ] "]"
          | "{" "}" | "{" MapEntry { "," MapEntry } [ "," ] "}"
          | "chan" "[" Type "]" "(" [ Expr ] ")" .
MapEntry  = Expr ":" Expr .

3.9 Patterns

Grammar Pattern, AtomPattern, PatArg, LitPattern
Pattern=AtomPattern { "|" AtomPattern } .AtomPattern="_" ∣ Path ∣ Path "(" [ PatArg { "," PatArg } [ "," ] ] ")"∣ LitPattern [ ( ".." ∣ "..=" ) LitPattern ]∣ "(" Pattern "," [ Pattern { "," Pattern } [ "," ] ] ")"∣ "(" Pattern ")" .PatArg=[ NAME ":" ] Pattern .LitPattern=INT ∣ "-" INT ∣ FLOAT ∣ STRING ∣ "true" ∣ "false" ∣ "none" .\begin{array}{rcl}\textsf{Pattern} & = & \texttt{AtomPattern}\ \{\ \texttt{"|"}\ \texttt{AtomPattern}\ \}\ . \\ \textsf{AtomPattern} & = & \texttt{"\_"}\ |\ \texttt{Path}\ |\ \texttt{Path}\ \texttt{"("}\ [\ \texttt{PatArg}\ \{\ \texttt{","}\ \texttt{PatArg}\ \}\ [\ \texttt{","}\ ]\ ]\ \texttt{")"} \\ & & |\ \texttt{LitPattern}\ [\ (\ \texttt{".."}\ |\ \texttt{"..="}\ )\ \texttt{LitPattern}\ ] \\ & & |\ \texttt{"("}\ \texttt{Pattern}\ \texttt{","}\ [\ \texttt{Pattern}\ \{\ \texttt{","}\ \texttt{Pattern}\ \}\ [\ \texttt{","}\ ]\ ]\ \texttt{")"} \\ & & |\ \texttt{"("}\ \texttt{Pattern}\ \texttt{")"}\ . \\ \textsf{PatArg} & = & [\ \texttt{NAME}\ \texttt{":"}\ ]\ \texttt{Pattern}\ . \\ \textsf{LitPattern} & = & \texttt{INT}\ |\ \texttt{"-"}\ \texttt{INT}\ |\ \texttt{FLOAT}\ |\ \texttt{STRING}\ |\ \texttt{"true"}\ |\ \texttt{"false"}\ |\ \texttt{"none"}\ . \\\end{array}
Plain text of this block
Pattern     = AtomPattern { "|" AtomPattern } .
AtomPattern = "_" | Path | Path "(" [ PatArg { "," PatArg } [ "," ] ] ")"
            | LitPattern [ ( ".." | "..=" ) LitPattern ]
            | "(" Pattern "," [ Pattern { "," Pattern } [ "," ] ] ")"
            | "(" Pattern ")" .
PatArg      = [ NAME ":" ] Pattern .
LitPattern  = INT | "-" INT | FLOAT | STRING | "true" | "false" | "none" .

3.10 Statement and expression boundaries

A Block always begins with NEWLINE INDENT, so a block can never be confused with an expression. A one-line form exists for the common cases: fn f(x: T) -> U = e, step S on E -> e, and Pattern -> stmt in match and select.

3.11 How apparent ambiguities are resolved

Each is resolved in the grammar itself, so there is no precedence declaration and no conflict to resolve at parse time.

  • R1 dangling else. else only follows a Block (statement if) or is mandatory (if … then … else … expression). A statement if ends at its DEDENT, so the next else at the same indentation belongs to it.
  • R2 try … else against if … then … else. The branches of an if expression and the operands of try are CatchExpr, which cannot contain a bare try or if. if c then try a else b is a syntax error; write if c then (try a else b) else d.
  • R3 comparison chains. 0 < a < 10 is a syntax error (non-associative). Write a in 0..10.
  • R4 assignment against equality. = is a statement form, never an expression; (x = 1) is a syntax error.
  • R5 generic call against index. f[T](x) parses as index(f, T) then a call; name resolution (4.3) turns an index of a generic function or type by type arguments into instantiation, as in Go.
  • R6 impl generics against slice types. impl [T] … would be ambiguous with the slice type [T], so impl parameters need forall: impl forall[T: Show] Show for List[T].
  • R7 labels. In argument and pattern lists NAME ":" is always a label. Map literals {k: v} are in a different bracket, so {a: 1} is a map whose key is the variable a (write {"a": 1} for a text key).
  • R8 variant patterns against bindings. A Path pattern is a unit variant if name resolution finds a variant of that name in scope, otherwise it binds a fresh variable (Rust's rule). W-PAT-1 refuses a binding that shadows a variant name, so a misspelled variant is never silently a binding.
  • R9 send. <- after an expression at statement level is a send; in prefix position it is a receive. The two never meet: a <- <- b is "send the value received from b to a".

3.12 Machine check

rce-spec-check (in spec/checker/, Rust only):

  1. reads every rule of this section from its code blocks (the annotation column beside a rule is prose and is skipped), expands the EBNF the way Lark did ([ X ] and { X } inlined as with and without, { X } as one left-recursive helper rule), builds the LALR(1) tables and fails on any shift/reduce or reduce/reduce conflict (verified: adding | AddExpr "+" AddExpr to AddExpr makes it fail with 3 conflicts); current result: 100 rules, 472 productions, 932 states, 0 conflicts;
  2. parses the 51 programs in examples/, with and without their final newline; all must parse;
  3. parses the 12 programs in examples/reject/ (tab indent, chained comparison, if expression without else, try in a then branch, inconsistent dedent, class, assignment inside an expression, empty kind, state with no fields, step without on, example without ->, unterminated string); all must be refused.

Each program is parsed three ways (the LALR(1) tables on the reference lexer's tokens, the Rust parser, and the tree-sitter port) and all three must agree. Until 2026-10-12 this check was spec/check.py on spec/rce.lark with Lark in strict mode; both are retired.

spec/tree-sitter/ is the same grammar for tree-sitter (grammar.js, with layout, bracket depth, reserved-keyword NAME and longest-match numbers and <- in src/scanner.c). The former tree-sitter/compare.py N SEED parsed every example and N fuzz programs, each program's syntax mutants and SOUP lexical-stress mutants (a random token jammed in or a space deleted) with Lark and tree-sitter and required that both refuse, or both accept with identical trees (rule names, nesting, kept tokens and their text). Results: 81 examples plus 10,000 programs (seed 7, SOUP=2): 69,323 inputs, 15,205 accepted by both with identical trees, 54,118 refused by both, 0 disagreements; 10,000 programs (seed 11, SOUP=10): 149,365 inputs, 35,837 identical trees, 113,528 refused by both, 0 disagreements. Draft 0.4 grammar (with extern and arena bound): 91 examples plus 2,000 programs (seed 7, SOUP=2): 13,983 inputs, 3,060 identical trees, 10,923 refused by both, 0 disagreements. Draft 0.5 grammar and generator (linear, iter, yield, device, no lalr): 127 examples plus 2,000 programs (seed 7, SOUP=2): 16,092 inputs, 3,185 identical trees, 12,907 refused by both, 0 disagreements.

Built from spec commit 49fa9af. Code cells run the reference checker rce-check, written in Rust and compiled to WebAssembly, inside your browser; nothing is sent to a server. Read-aloud uses the Kokoro-82M model (Apache-2.0), served from this site and run in your browser.