Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Grammar (Informal EBNF)

Informal sketch of the public surface. The authoritative grammar is cambrian-transpiler/src/cambrian.lalrpop. X? is optional, X* / X+ repeat, X,* is a comma-separated list, … elides detail.

Program        ::= TopLevel*

TopLevel       ::= ImportFile | UseDecl | PureFn | TypeAlias | RecordDecl
                 | EnumDecl | Entity | ExternEntity | EventDecl | ErrorDecl
                 | LibraryDecl | UsingDecl | TestDecl | PropertyDecl
                 | InvariantDecl

ImportFile     ::= "import" StringLit
UseDecl        ::= "use" Ident
PureFn         ::= "pure" "fn" Ident "(" Params ")" "->" Type "{" Block "}"
TypeAlias      ::= "type" Ident "=" Type                       // no ";"
Const          ::= "const" Ident ":" Type "=" Expr             // no ";"
RecordDecl     ::= "record" Ident "{" (Ident ":" Type),* "}"
EnumDecl       ::= "enum" Ident "{" (Ident ("(" Type,* ")")?),* "}"
EventDecl      ::= "event" Ident "(" ("indexed"? Ident ":" Type),* ")" ";"
ErrorDecl      ::= "error" Ident "(" Params ")" ";"
LibraryDecl    ::= "library" Ident "{" (PureFn | Const | TypeAlias)* "}"
UsingDecl      ::= "using" ("{" Ident,* "}" | Ident) "for" Type ";"

Entity         ::= "entity" Ident "{" EntityItem* "}"
EntityItem     ::= Const | Macro | RecordDecl | EnumDecl | TypeAlias
                 | EventDecl | ErrorDecl | RoutesBlock | Member
Macro          ::= "macro" Ident "(" Params ")" "->" Type "=" "{" Block "}"

ExternEntity   ::= ("@" "solidity_import" "(" StringLit ")")?
                   "extern" "entity" Ident "{" ExternRoute* "}"
ExternRoute    ::= ("view" | "accept")? "route" Ident "(" Params ")" ("->" Type)? ";"

Member         ::= Ident ":" Type ("=" Expr)? "{" Transform* "}"
                 | "identity" Ident ":" Type
Transform      ::= "in" Ident "(" Pattern,* ")" "=>" TransformBody
                 | "in" Ident "(" Pattern,* ")" "=>" (Ident ":" TransformBody)+   // per phase
TransformBody  ::= Expr | "{" Block "}"

RoutesBlock    ::= "routes" "{" Route* "}"
Route          ::= Attr* RouteHead "=>" "[" Body "]"
RouteHead      ::= Ident     "(" Params ")" From? ("->" Type)? Where?   // plain
                 | "accept"  Ident "(" Params ")" From? ("->" Type)? Where?
                 | "view"    Ident "(" Params ")" From? ("->" Type)? Where?
                 | "pure"    Ident "(" Params ")" ("->" Type)?
                 | "init"    Ident "(" Params ")" Where?
                 | "private" Ident "(" Params ")" Where?
Attr           ::= "#" "[" Ident ("(" (StringLit | IntLit) ")")? "]"      // e.g. #[factory_only]
From           ::= "from" FromAlt ("|" FromAlt)*
FromAlt        ::= Ident "(" Expr,* ")" ("with" "{" … "}")? ThrowSpec?  // entity form
                 | Ident ThrowSpec?                                     // member form
Where          ::= "where" Cond ("&&" Cond)*
                 | "where" "{" Cond,* "}"
Cond           ::= Expr ThrowSpec
ThrowSpec      ::= ":" "throw" (IntLit | Ident | Ident "(" Expr,* ")")

Body           ::= Action* | PhaseBlock*
PhaseBlock     ::= Ident Where? ":" "[" Action* "]"

Action         ::= "let" Pattern "=" LetValue ";"
                 | "var" Ident "=" Ident "(" Expr,* ")" "~>" Expr SendOpts? ";"
                 | "emit" Ident "(" Expr,* ")" ";"
                 | Ident "(" Expr,* ")" "~>" Expr SendOpts?             // typed send
                 | "~>" Expr SendOpts?                                  // value transfer
                 | "deploy" Ident ("(" Expr,* ")")? SendOpts?
                 | "return" "(" Expr,* ")"
                 | "throw" (IntLit | Ident | Ident "(" Expr,* ")")
                 | "call" Ident "(" Expr,* ")"
                 | Ident "::" Ident "(" Expr,* ")"                      // namespaced effect
                 | "if" Expr "=>" "[" Action* "]" ("else" "[" Action* "]")?
                 | "for" Pattern "in" Expr "=>" "[" Action* "]"
LetValue       ::= Expr | "if" … | "match" … | "{" Block "}"
SendOpts       ::= "with" "{" (Ident ":" Expr),* "}"

Block          ::= LetStmt* BlockTail
LetStmt        ::= "let" Pattern "=" (Expr | RecordLit | "if" … | "match" … | "{" Block "}") ";"
BlockTail      ::= Expr | RecordLit | "{" Block "}"
                 | "if" Expr "{" Block "}" ("else" "{" Block "}")?
                 | "match" Expr "{" (MatchPat "=>" (Expr | "{" Block "}")),* "}"
                 | "for" Pattern "in" Expr "{" Block "}"
RecordLit      ::= Ident "{" (Ident ":" Expr),* "}"
MatchPat       ::= Ident "::" Ident ("(" Pattern,* ")")? | "some" "(" Pattern ")"
                 | "none" | "_" | IntLit | "true" | "false" | Ident
Pattern        ::= Ident | "_" | "(" Pattern,* ")" | "some" "(" Pattern ")" | "none"

Expr           ::= Closure | Expr ".." Expr | BinaryExpr    // see Operator Precedence
Closure        ::= "|" Pattern,* "|" (Expr | RecordLit | "{" Block "}" | "if" …)
Primary        ::= IntLit | HexLit | BinLit | StringLit | BytesLit | "true" | "false"
                 | "array" "(" Expr,* ")" | "{" "}" | "(" Expr ("," Expr)+ ")"
                 | "^" Ident | "@" Ident "(" Expr,* ")"
                 | "msg::" Ident | "sys::" Ident | "trace::" Ident ("(" Ident ")")?
                 | "some" "(" Expr ")" | "none"
                 | Ident "::" Ident "::" Ident "(" Expr,* ")"   // std::math::min(…)
                 | Ident "::" Ident ("(" Expr,* ")")?            // Enum::Variant, evm::…
                 | "address_of" Ident "(" Expr,* ")"
                 | Ident "(" Expr,* ")" | Ident | "(" Expr ")"

TestDecl       ::= Attr* "test" StringLit "for" Ident ("skip" "from")?
                   ("with" "{" (Ident ":" Expr),* "}")? "{" TestStep* "}"
TestStep       ::= "call" (Ident ".")? Ident "(" Expr,* ")"
                 | Ident "{" (Ident ":" Expr),* "}"             // msg { sender: … }
                 | "let" Ident (":" Type)? "=" Expr
                 | "deploy" Ident "=" Ident "(" Expr,* ")" ("with" "{" … "}")?
                 | "expect" "state" "{" (FieldPath ":" Expr),* "}"
                 | "expect" "return" ("==")? Expr
                 | "expect" "return" ("." FieldPath | "[" … "]") ("==" | RelOp) Expr
                 | "expect" "throw" IntLit
                 | "expect" "emit" Ident "(" Expr,* ")"
                 | "expect" Expr                                // boolean predicate
                 | "assume" Expr | "bound" Ident "in" Expr (".." | "..=") Expr

PropertyDecl   ::= Attr* "property" StringLit ("(" Params ")")? "for" Ident
                   With? Ctx? "{" (TestStep | Instance)* "}"
Instance       ::= Attr* ("test" | "fuzz") StringLit? "{" Binding,* "}" With? Ctx?
Binding        ::= Ident ":" Expr | Ident "in" Expr (".." | "..=") Expr
With           ::= "with" "{" (Ident ":" (Expr | "*") | "*"),* "}"
Ctx            ::= "ctx" "{" (("msg::" | "sys::") Ident ":" (Expr | "*")),* "}"

InvariantDecl  ::= Attr* "invariant" StringLit Attr* "for" InvTarget Attr* "{" InvItem* "}"
InvTarget      ::= Ident | "{" (Ident ":" Ident),* "}"          // single / multi-entity
InvItem        ::= "init" Ident? "{" … "}" | "with" "{" … "}"      // Ident = instance
                 | "deploy" "{" Expr,* "}"
                 | "senders" "{" Expr,* "}" | Ctx
                 | "action" Ident ("." Ident)? "(" Params ")" "{" TestStep* "}"
                 | "check" Expr
                 | "track" "{" ("let" Ident "=" Expr ";"?)* "}"
                 | "derived" Ident "(" Params ")" "->" Type "{" TestStep* "return" Expr "}"
                 | "exclude" ("senders" | "selectors") "{" … "}"

Invariant action bodies additionally accept skip if Expr and advanceTime(Expr) (with #[with_time]).

Comments are // … only. Literals: decimal 1_000, hex 0xff, binary 0b1010, strings "…", bytes b"…". Strings and bytes decode the escapes \n, \r, \t, \0, \\ and \xHH; any other character, including non-ASCII text, is taken literally. A string can’t contain a " character (\" is not accepted).

See also Keywords and Operator Precedence.