The Dafny grammar has a traditional structure: a scanner tokenizes the textual input into a sequence of tokens; the parser consumes the tokens to produce an AST. The AST is then passed on for name and type resolution and further processing.
Dafny uses the Coco/R lexer and parser generator for its lexer and parser
(http://www.ssw.uni-linz.ac.at/Research/Projects/Coco)[@Linz:Coco].
See the Coco/R Reference
manual
for details.
The Dafny input file to Coco/R is the Dafny.atg
file in the source tree.
The grammar is an attributed extended BNF grammar. The attributed adjective indicates that the BNF productions are parameterized by boolean parameters that control variations of the production rules, such as whether a particular alternative is permitted or not. Using such attributes allows combining non-terminals with quite similar production rules, making a simpler, more compact and more readable grammer.
The grammar rules presented here replicate those in the source code, but omit semantic actions, error recovery markers, and conflict resolution syntax. Some uses of the attribute parameters are described informally.
The names of character sets and tokens start with a lower case letter; the names of grammar non-terminals start with an upper-case letter.
This section gives the definitions of Dafny tokens.
These definitions define some names as representing subsets of the set of characters. Here,
- double quotes enclose the set of characters constituting the class,
- single quotes enclose a single character (perhaps an escaped representation using
\
), - the binary
+
indicates set union, - binary
-
indicates set difference, and ANY
indicates the set of all (unicode) characters.
letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
digit = "0123456789"
posDigit = "123456789"
posDigitFrom2 = "23456789"
hexdigit = "0123456789ABCDEFabcdef"
special = "'_?"
cr = '\r'
lf = '\n'
tab = '\t'
space = ' '
nondigitIdChar = letter + special
idchar = nondigitIdChar + digit
nonidchar = ANY - idchar
charChar = ANY - '\'' - '\\' - cr - lf
stringChar = ANY - '"' - '\\' - cr - lf
verbatimStringChar = ANY - '"'
A nonidchar
is any character except those that can be used in an identifier.
Here the scanner generator will interpret ANY
as any unicode character.
However, nonidchar
is used only to mark the end of the !in
token;
in this context any character other than whitespace or printable ASCII
will trigger a subsequent scanning or parsing error.
These definitions use
- double-quotes to indicate a verbatim string (with no escaping of characters)
'"'
to indicate a literal double-quote character- vertical bar to indicate alternatives
- square brackets to indicate an optional part
- curly braces to indicate 0-or-more repetitions
- parentheses to indicate grouping
- a
-
sign to indicate set difference: any character sequence matched by the left operand except character sequences matched by the right operand - a sequence of any of the above to indicate concatenation without whitespace
reservedword =
"abstract" | "allocated" | "as" | "assert" | "assume" |
"bool" | "break" | "by" |
"calc" | "case" | "char" | "class" | "codatatype" |
"const" | "constructor" | "continue" |
"datatype" | "decreases" |
"else" | "ensures" | "exists" | "expect" | "export" | "extends" |
"false" | "for" | "forall" | "fresh" | "function" | "ghost" |
"if" | "imap" | "import" | "in" | "include" |
"int" | "invariant" | "is" | "iset" | "iterator" |
"label" | "lemma" | "map" | "match" | "method" |
"modifies" | "modify" | "module" | "multiset" |
"nameonly" | "nat" | "new" | "newtype" | "null" |
"object" | "object?" | "old" | "opaque" | "opened" | "ORDINAL"
"predicate" | "print" | "provides" |
"reads" | "real" | "refines" | "requires" | "return" |
"returns" | "reveal" | "reveals" |
"seq" | "set" | "static" | "string" |
"then" | "this" | "trait" | "true" | "twostate" | "type" |
"unchanged" | "var" | "while" | "witness" |
"yield" | "yields" |
arrayToken | bvToken
arrayToken = "array" [ posDigitFrom2 | posDigit digit { digit }]["?"]
bvToken = "bv" ( 0 | posDigit { digit } )
ident = nondigitIdChar { idchar } - charToken - reservedword
digits = digit {["_"] digit}
hexdigits = "0x" hexdigit {["_"] hexdigit}
decimaldigits = digit {["_"] digit} '.' digit {["_"] digit}
escapedChar =
( "\'" | "\"" | "\\" | "\0" | "\n" | "\r" | "\t"
| "\u" hexdigit hexdigit hexdigit hexdigit
| "\U{" hexdigit { hexdigit } "}"
)
charToken = "'" ( charChar | escapedChar ) "'"
stringToken =
'"' { stringChar | escapedChar } '"'
| "@" '"' { verbatimStringChar | '"' '"' } '"'
ellipsis = "..."
There are a few words that have a special meaning in certain contexts, but are not reserved words and can be used as identifiers outside of those contexts:
least
andgreatest
are recognized as adjectives to the keywordpredicate
(cf. Section 12.4).older
is a modifier for parameters of non-extreme predicates (cf. Section 6.4.6).
The \uXXXX
form of an escapedChar
is only used when the option --unicode-char=false
is set (which is the default for Dafny 3.x);
the \U{XXXXXX}
form of an escapedChar
is only used when the option --unicode-char=true
is set (which is the default for Dafny 4.x).
The grammar productions are presented in the following Extended BNF syntax:
- identifiers starting with a lower case letter denote terminal symbols (tokens) as defined in the previous subsection
- identifiers starting with an upper case letter denote nonterminal symbols
- strings (a sequence of characters enclosed by double quote characters) denote the sequence of enclosed characters
=
separates the sides of a production, e.g.A = a b c
|
separates alternatives, e.g.a b | c | d e
meansa b
orc
ord e
(
)
groups alternatives, e.g.(a | b) c
meansa c
orb c
[ ]
option, e.g.[a] b
meansa b
orb
{ }
iteration (0 or more times), e.g.{a} b
meansb
ora b
ora a b
or ...- We allow
|
inside[ ]
and{ }
. So[a | b]
is short for[(a | b)]
and{a | b}
is short for{(a | b)}
. //
in a line introduces a comment that extends to the end-of-the line, but does not terminate the production- The first production defines the name of the grammar, in this case
Dafny
.
In addition to the Coco rules, for the sake of readability we have adopted these additional conventions.
- We allow
-
to be used.a - b
means it matches if it matchesa
but notb
. - We omit the
.
that marks the end of a CoCo/R production. - we omit deprecated features.
To aid in explaining the grammar we have added some additional productions that are not present in the original grammar. We name these with a trailing underscore. Inlining these where they are referenced will reconstruct the original grammar.
Dafny = { IncludeDirective_ } { TopDecl(isTopLevel:true, isAbstract: false) } EOF
IncludeDirective_ = "include" stringToken
TopDecl(isTopLevel, isAbstract) =
{ DeclModifier }
( SubModuleDecl(isTopLevel)
| ClassDecl
| DatatypeDecl
| NewtypeDecl
| SynonymTypeDecl // includes abstract types
| IteratorDecl
| TraitDecl
| ClassMemberDecl(allowConstructors: false, isValueType: true, moduleLevelDecl: true)
)
DeclModifier = ( "abstract" | "ghost" | "static" | "opaque" )
SubModuleDecl(isTopLevel) = ( ModuleDefinition | ModuleImport | ModuleExport )
Module export declarations are not permitted if isTopLevel
is true.
ModuleDefinition(isTopLevel) =
"module" { Attribute } ModuleQualifiedName
[ "refines" ModuleQualifiedName ]
"{" { TopDecl(isTopLevel:false, isAbstract) } "}"
The isAbstract
argument is true if the preceding DeclModifiers
include "abstract".
ModuleImport =
"import"
[ "opened" ]
( QualifiedModuleExport
| ModuleName "=" QualifiedModuleExport
| ModuleName ":" QualifiedModuleExport
)
QualifiedModuleExport =
ModuleQualifiedName [ "`" ModuleExportSuffix ]
ModuleExportSuffix =
( ExportId
| "{" ExportId { "," ExportId } "}"
)
ModuleExport =
"export"
[ ExportId ]
[ "..." ]
{
"extends" ExportId { "," ExportId }
| "provides" ( ExportSignature { "," ExportSignature } | "*" )
| "reveals" ( ExportSignature { "," ExportSignature } | "*" )
}
ExportSignature = TypeNameOrCtorSuffix [ "." TypeNameOrCtorSuffix ]
Type = DomainType_ | ArrowType_
DomainType_ =
( BoolType_ | CharType_ | IntType_ | RealType_
| OrdinalType_ | BitVectorType_ | ObjectType_
| FiniteSetType_ | InfiniteSetType_
| MultisetType_
| FiniteMapType_ | InfiniteMapType_
| SequenceType_
| NatType_
| StringType_
| ArrayType_
| TupleType
| NamedType
)
NamedType = NameSegmentForTypeName { "." NameSegmentForTypeName }
NameSegmentForTypeName = Ident [ GenericInstantiation ]
BoolType_ = "bool"
IntType_ = "int"
RealType_ = "real"
BitVectorType_ = bvToken
OrdinalType_ = "ORDINAL"
CharType_ = "char"
GenericInstantiation = "<" Type { "," Type } ">"
GenericParameters(allowVariance) =
"<" [ Variance ] TypeVariableName { TypeParameterCharacteristics }
{ "," [ Variance ] TypeVariableName { TypeParameterCharacteristics } }
">"
// The optional Variance indicator is permitted only if allowVariance is true
Variance = ( "*" | "+" | "!" | "-" )
TypeParameterCharacteristics = "(" TPCharOption { "," TPCharOption } ")"
TPCharOption = ( "==" | "0" | "00" | "!" "new" )
FiniteSetType_ = "set" [ GenericInstantiation ]
InfiniteSetType_ = "iset" [ GenericInstantiation ]
MultisetType_ = "multiset" [ GenericInstantiation ]
SequenceType_ = "seq" [ GenericInstantiation ]
StringType_ = "string"
FiniteMapType_ = "map" [ GenericInstantiation ]
InfiniteMapType_ = "imap" [ GenericInstantiation ]
SynonymTypeDecl =
SynonymTypeDecl_ | OpaqueTypeDecl_ | SubsetTypeDecl_
SynonymTypeName = NoUSIdent
SynonymTypeDecl_ =
"type" { Attribute } SynonymTypeName
{ TypeParameterCharacteristics }
[ GenericParameters ]
"=" Type
OpaqueTypeDecl_ =
"type" { Attribute } SynonymTypeName
{ TypeParameterCharacteristics }
[ GenericParameters ]
[ TypeMembers ]
TypeMembers =
"{"
{
{ DeclModifier }
ClassMemberDecl(allowConstructors: false,
isValueType: true,
moduleLevelDecl: false,
isWithinAbstractModule: module.IsAbstract)
}
"}"
SubsetTypeDecl_ =
"type"
{ Attribute }
SynonymTypeName [ GenericParameters ]
"="
LocalIdentTypeOptional
"|"
Expression(allowLemma: false, allowLambda: true)
[ "ghost" "witness" Expression(allowLemma: false, allowLambda: true)
| "witness" Expression((allowLemma: false, allowLambda: true)
| "witness" "*"
]
NatType_ = "nat"
NewtypeDecl = "newtype" { Attribute } NewtypeName "="
[ ellipsis ]
( LocalIdentTypeOptional
"|"
Expression(allowLemma: false, allowLambda: true)
[ "ghost" "witness" Expression(allowLemma: false, allowLambda: true)
| "witness" Expression((allowLemma: false, allowLambda: true)
| "witness" "*"
]
| Type
)
[ TypeMembers ]
ClassDecl = "class" { Attribute } ClassName [ GenericParameters ]
["extends" Type {"," Type} | ellipsis ]
"{" { { DeclModifier }
ClassMemberDecl(modifiers,
allowConstructors: true,
isValueType: false,
moduleLevelDecl: false)
}
"}"
ClassMemberDecl(modifiers, allowConstructors, isValueType, moduleLevelDecl) =
( FieldDecl(isValueType) // allowed iff moduleLevelDecl is false
| ConstantFieldDecl(moduleLevelDecl)
| FunctionDecl(isWithinAbstractModule)
| MethodDecl(modifiers, allowConstructors)
)
TraitDecl =
"trait" { Attribute } ClassName [ GenericParameters ]
[ "extends" Type { "," Type } | ellipsis ]
"{"
{ { DeclModifier } ClassMemberDecl(allowConstructors: true,
isValueType: false,
moduleLevelDecl: false,
isWithinAbstractModule: false) }
"}"
ObjectType_ = "object" | "object?"
ArrayType_ = arrayToken [ GenericInstantiation ]
IteratorDecl = "iterator" { Attribute } IteratorName
( [ GenericParameters ]
Formals(allowGhostKeyword: true, allowNewKeyword: false,
allowOlderKeyword: false)
[ "yields" Formals(allowGhostKeyword: true, allowNewKeyword: false,
allowOlderKeyword: false) ]
| ellipsis
)
IteratorSpec
[ BlockStmt ]
ArrowType_ = ( DomainType_ "~>" Type
| DomainType_ "-->" Type
| DomainType_ "->" Type
)
DatatypeDecl =
( "datatype" | "codatatype" )
{ Attribute }
DatatypeName [ GenericParameters ]
"="
[ ellipsis ]
[ "|" ] DatatypeMemberDecl
{ "|" DatatypeMemberDecl }
[ TypeMembers ]
DatatypeMemberDecl =
{ Attribute } DatatypeMemberName [ FormalsOptionalIds ]
FieldDecl(isValueType) =
"var" { Attribute } FIdentType { "," FIdentType }
A FieldDecl
is not permitted if isValueType
is true.
ConstantFieldDecl(moduleLevelDecl) =
"const" { Attribute } CIdentType [ ellipsis ]
[ ":=" Expression(allowLemma: false, allowLambda:true) ]
If moduleLevelDecl
is true, then the static
modifier is not permitted
(the constant field is static implicitly).
MethodDecl(isGhost, allowConstructors, isWithinAbstractModule) =
MethodKeyword_ { Attribute } [ MethodFunctionName ]
( MethodSignature_(isGhost, isExtreme: true iff this is a least
or greatest lemma declaration)
| ellipsis
)
MethodSpec(isConstructor: true iff this is a constructor declaration)
[ BlockStmt ]
MethodKeyword_ = ( "method"
| "constructor"
| "lemma"
| "twostate" "lemma"
| "least" "lemma"
| "greatest" "lemma"
)
MethodSignature_(isGhost, isExtreme) =
[ GenericParameters ]
[ KType ] // permitted only if isExtreme == true
Formals(allowGhostKeyword: !isGhost, allowNewKeyword: isTwostateLemma,
allowOlderKeyword: false, allowDefault: true)
[ "returns" Formals(allowGhostKeyword: !isGhost, allowNewKeyword: false,
allowOlderKeyword: false, allowDefault: false) ]
KType = "[" ( "nat" | "ORDINAL" ) "]"
Formals(allowGhostKeyword, allowNewKeyword, allowOlderKeyword, allowDefault) =
"(" [ { Attribute } GIdentType(allowGhostKeyword, allowNewKeyword, allowOlderKeyword,
allowNameOnlyKeyword: true, allowDefault)
{ "," { Attribute } GIdentType(allowGhostKeyword, allowNewKeyword, allowOlderKeyword,
allowNameOnlyKeyword: true, allowDefault) }
]
")"
If isWithinAbstractModule
is false, then the method must have
a body for the program that contains the declaration to be compiled.
The KType
may be specified only for least and greatest lemmas.
FunctionDecl(isWithinAbstractModule) =
( [ "twostate" ] "function" [ "method" ] { Attribute }
MethodFunctionName
FunctionSignatureOrEllipsis_(allowGhostKeyword:
("method" present),
allowNewKeyword:
"twostate" present)
| "predicate" [ "method" ] { Attribute }
MethodFunctionName
PredicateSignatureOrEllipsis_(allowGhostKeyword:
("method" present),
allowNewKeyword:
"twostate" present,
allowOlderKeyword: true)
| ( "least" | "greatest" ) "predicate" { Attribute }
MethodFunctionName
PredicateSignatureOrEllipsis_(allowGhostKeyword: false,
allowNewKeyword: "twostate" present,
allowOlderKeyword: false))
)
FunctionSpec
[ FunctionBody ]
FunctionSignatureOrEllipsis_(allowGhostKeyword) =
FunctionSignature_(allowGhostKeyword) | ellipsis
FunctionSignature_(allowGhostKeyword, allowNewKeyword) =
[ GenericParameters ]
Formals(allowGhostKeyword, allowNewKeyword, allowOlderKeyword: true,
allowDefault: true)
":"
( Type
| "(" GIdentType(allowGhostKeyword: false,
allowNewKeyword: false,
allowOlderKeyword: false,
allowNameOnlyKeyword: false,
allowDefault: false)
")"
)
PredicateSignatureOrEllipsis_(allowGhostKeyword, allowNewKeyword,
allowOlderKeyword) =
PredicateSignature_(allowGhostKeyword, allowNewKeyword, allowOlderKeyword)
| ellipsis
PredicateSignature_(allowGhostKeyword, allowNewKeyword, allowOlderKeyword) =
[ GenericParameters ]
[ KType ]
Formals(allowGhostKeyword, allowNewKeyword, allowOlderKeyword,
allowDefault: true)
[
":"
( Type
| "(" Ident ":" "bool" ")"
)
]
FunctionBody = "{" Expression(allowLemma: true, allowLambda: true)
"}" [ "by" "method" BlockStmt ]
MethodSpec =
{ ModifiesClause(allowLambda: false)
| RequiresClause(allowLabel: true)
| EnsuresClause(allowLambda: false)
| DecreasesClause(allowWildcard: true, allowLambda: false)
}
FunctionSpec =
{ RequiresClause(allowLabel: true)
| ReadsClause(allowLemma: false, allowLambda: false, allowWild: true)
| EnsuresClause(allowLambda: false)
| DecreasesClause(allowWildcard: false, allowLambda: false)
}
LambdaSpec =
{ ReadsClause(allowLemma: true, allowLambda: false, allowWild: true)
| "requires" Expression(allowLemma: false, allowLambda: false)
}
IteratorSpec =
{ ReadsClause(allowLemma: false, allowLambda: false,
allowWild: false)
| ModifiesClause(allowLambda: false)
| [ "yield" ] RequiresClause(allowLabel: !isYield)
| [ "yield" ] EnsuresClause(allowLambda: false)
| DecreasesClause(allowWildcard: false, allowLambda: false)
}
LoopSpec =
{ InvariantClause_
| DecreasesClause(allowWildcard: true, allowLambda: true)
| ModifiesClause(allowLambda: true)
}
RequiresClause(allowLabel) =
"requires" { Attribute }
[ LabelName ":" ] // Label allowed only if allowLabel is true
Expression(allowLemma: false, allowLambda: false)
EnsuresClause(allowLambda) =
"ensures" { Attribute } Expression(allowLemma: false, allowLambda)
DecreasesClause(allowWildcard, allowLambda) =
"decreases" { Attribute } DecreasesList(allowWildcard, allowLambda)
DecreasesList(allowWildcard, allowLambda) =
PossiblyWildExpression(allowLambda, allowWildcard)
{ "," PossiblyWildExpression(allowLambda, allowWildcard) }
PossiblyWildExpression(allowLambda, allowWild) =
( "*" // if allowWild is false, using '*' provokes an error
| Expression(allowLemma: false, allowLambda)
)
ModifiesClause(allowLambda) =
"modifies" { Attribute }
FrameExpression(allowLemma: false, allowLambda)
{ "," FrameExpression(allowLemma: false, allowLambda) }
InvariantClause_ =
"invariant" { Attribute }
Expression(allowLemma: false, allowLambda: true)
ReadsClause(allowLemma, allowLambda, allowWild) =
"reads" { Attribute }
PossiblyWildFrameExpression(allowLemma, allowLambda, allowWild)
{ "," PossiblyWildFrameExpression(allowLemma, allowLambda, allowWild) }
FrameExpression(allowLemma, allowLambda) =
( Expression(allowLemma, allowLambda) [ FrameField ]
| FrameField
)
FrameField = "`" IdentOrDigits
PossiblyWildFrameExpression(allowLemma, allowLambda, allowWild) =
( "*" // error if !allowWild and '*'
| FrameExpression(allowLemma, allowLambda)
)
Stmt = { "label" LabelName ":" } NonLabeledStmt
NonLabeledStmt =
( AssertStmt | AssumeStmt | BlockStmt | BreakStmt
| CalcStmt | ExpectStmt | ForallStmt | IfStmt
| MatchStmt | ModifyStmt
| PrintStmt | ReturnStmt | RevealStmt
| UpdateStmt | UpdateFailureStmt
| VarDeclStatement | WhileStmt | ForLoopStmt | YieldStmt
)
BreakStmt =
( "break" LabelName ";"
| "continue" LabelName ";"
| { "break" } "break" ";"
| { "break" } "continue" ";"
)
BlockStmt = "{" { Stmt } "}"
ReturnStmt = "return" [ Rhs { "," Rhs } ] ";"
YieldStmt = "yield" [ Rhs { "," Rhs } ] ";"
UpdateStmt =
Lhs
( {Attribute} ";"
|
{ "," Lhs }
( ":=" Rhs { "," Rhs }
| ":|" [ "assume" ]
Expression(allowLemma: false, allowLambda: true)
)
";"
)
UpdateFailureStmt =
[ Lhs { "," Lhs } ]
":-"
[ "expect" | "assert" | "assume" ]
Expression(allowLemma: false, allowLambda: false)
{ "," Rhs }
";"
VarDeclStatement =
[ "ghost" ] "var" { Attribute }
(
LocalIdentTypeOptional
{ "," { Attribute } LocalIdentTypeOptional }
[ ":="
Rhs { "," Rhs }
| ":-"
[ "expect" | "assert" | "assume" ]
Expression(allowLemma: false, allowLambda: false)
{ "," Rhs }
| { Attribute }
":|"
[ "assume" ] Expression(allowLemma: false, allowLambda: true)
]
|
CasePatternLocal
( ":=" | { Attribute } ":|" )
Expression(allowLemma: false, allowLambda: true)
)
";"
CasePatternLocal =
( [ Ident ] "(" CasePatternLocal { "," CasePatternLocal } ")"
| LocalIdentTypeOptional
)
Guard = ( "*"
| "(" "*" ")"
| Expression(allowLemma: true, allowLambda: true)
)
BindingGuard(allowLambda) =
IdentTypeOptional { "," IdentTypeOptional }
{ Attribute }
":|"
Expression(allowLemma: true, allowLambda)
IfStmt = "if"
( AlternativeBlock(allowBindingGuards: true)
|
( BindingGuard(allowLambda: true)
| Guard
)
BlockStmt [ "else" ( IfStmt | BlockStmt ) ]
)
AlternativeBlock(allowBindingGuards) =
( { AlternativeBlockCase(allowBindingGuards) }
| "{" { AlternativeBlockCase(allowBindingGuards) } "}"
)
AlternativeBlockCase(allowBindingGuards) =
{ "case"
(
BindingGuard(allowLambda: false) //permitted iff allowBindingGuards == true
| Expression(allowLemma: true, allowLambda: false)
) "=>" { Stmt }
}
WhileStmt =
"while"
( LoopSpec
AlternativeBlock(allowBindingGuards: false)
| Guard
LoopSpec
( BlockStmt
| // no body
)
)
ForLoopStmt =
"for" IdentTypeOptional ":="
Expression(allowLemma: false, allowLambda: false)
( "to" | "downto" )
( "*" | Expression(allowLemma: false, allowLambda: false)
)
LoopSpec
( BlockStmt
| // no body
)
MatchStmt =
"match"
Expression(allowLemma: true, allowLambda: true)
( "{" { CaseStmt } "}"
| { CaseStmt }
)
CaseStmt = "case" ExtendedPattern "=>" { Stmt }
AssertStmt =
"assert"
{ Attribute }
[ LabelName ":" ]
Expression(allowLemma: false, allowLambda: true)
( ";"
| "by" BlockStmt
)
AssumeStmt =
"assume"
{ Attribute }
Expression(allowLemma: false, allowLambda: true)
";"
ExpectStmt =
"expect"
{ Attribute }
Expression(allowLemma: false, allowLambda: true)
[ "," Expression(allowLemma: false, allowLambda: true) ]
";"
PrintStmt =
"print"
Expression(allowLemma: false, allowLambda: true)
{ "," Expression(allowLemma: false, allowLambda: true) }
";"
RevealStmt =
"reveal"
Expression(allowLemma: false, allowLambda: true)
{ "," Expression(allowLemma: false, allowLambda: true) }
";"
ForallStmt =
"forall"
( "(" [ QuantifierDomain ] ")"
| [ QuantifierDomain ]
)
{ EnsuresClause(allowLambda: true) }
[ BlockStmt ]
ModifyStmt =
"modify"
{ Attribute }
FrameExpression(allowLemma: false, allowLambda: true)
{ "," FrameExpression(allowLemma: false, allowLambda: true) }
";"
CalcStmt = "calc" { Attribute } [ CalcOp ] "{" CalcBody_ "}"
CalcBody_ = { CalcLine_ [ CalcOp ] Hints_ }
CalcLine_ = Expression(allowLemma: false, allowLambda: true) ";"
Hints_ = { ( BlockStmt | CalcStmt ) }
CalcOp =
( "==" [ "#" "["
Expression(allowLemma: true, allowLambda: true) "]" ]
| "<" | ">"
| "!=" | "<=" | ">="
| "<==>" | "==>" | "<=="
)
OpaqueBlock = "opaque" OpaqueSpec BlockStmt
OpaqueSpec = {
| ModifiesClause(allowLambda: false)
| EnsuresClause(allowLambda: false)
}
Expression(allowLemma, allowLambda, allowBitwiseOps = true) =
EquivExpression(allowLemma, allowLambda, allowBitwiseOps)
[ ";" Expression(allowLemma, allowLambda, allowBitwiseOps) ]
The "allowLemma" argument says whether or not the expression
to be parsed is allowed to have the form S;E
where S
is a call to a lemma.
"allowLemma" should be passed in as "false" whenever the expression to
be parsed sits in a context that itself is terminated by a semi-colon.
The "allowLambda" says whether or not the expression to be parsed is
allowed to be a lambda expression. More precisely, an identifier or
parenthesized, comma-delimited list of identifiers is allowed to
continue as a lambda expression (that is, continue with a reads
, requires
,
or =>
) only if "allowLambda" is true. This affects function/method/iterator
specifications, if/while statements with guarded alternatives, and expressions
in the specification of a lambda expression itself.
EquivExpression(allowLemma, allowLambda, allowBitwiseOps) =
ImpliesExpliesExpression(allowLemma, allowLambda, allowBitwiseOps)
{ "<==>" ImpliesExpliesExpression(allowLemma, allowLambda, allowBitwiseOps) }
ImpliesExpliesExpression(allowLemma, allowLambda, allowBitwiseOps) =
LogicalExpression(allowLemma, allowLambda)
[ ( "==>" ImpliesExpression(allowLemma, allowLambda, allowBitwiseOps)
| "<==" LogicalExpression(allowLemma, allowLambda, allowBitwiseOps)
{ "<==" LogicalExpression(allowLemma, allowLambda, allowBitwiseOps) }
)
]
ImpliesExpression(allowLemma, allowLambda, allowBitwiseOps) =
LogicalExpression(allowLemma, allowLambda, allowBitwiseOps)
[ "==>" ImpliesExpression(allowLemma, allowLambda, allowBitwiseOps) ]
LogicalExpression(allowLemma, allowLambda, allowBitwiseOps) =
[ "&&" | "||" ]
RelationalExpression(allowLemma, allowLambda, allowBitwiseOps)
{ ( "&&" | "||" )
RelationalExpression(allowLemma, allowLambda, allowBitwiseOps)
}
RelationalExpression(allowLemma, allowLambda, allowBitwiseOps) =
ShiftTerm(allowLemma, allowLambda, allowBitwiseOps)
{ RelOp ShiftTerm(allowLemma, allowLambda, allowBitwiseOps) }
RelOp =
( "=="
[ "#" "[" Expression(allowLemma: true, allowLambda: true) "]" ]
| "!="
[ "#" "[" Expression(allowLemma: true, allowLambda: true) "]" ]
| "<" | ">" | "<=" | ">="
| "in"
| "!in"
| "!!"
)
ShiftTerm(allowLemma, allowLambda, allowBitwiseOps) =
Term(allowLemma, allowLambda, allowBitwiseOps)
{ ShiftOp Term(allowLemma, allowLambda, allowBitwiseOps) }
ShiftOp = ( "<<" | ">>" )
Term(allowLemma, allowLambda, allowBitwiseOps) =
Factor(allowLemma, allowLambda, allowBitwiseOps)
{ AddOp Factor(allowLemma, allowLambda, allowBitwiseOps) }
AddOp = ( "+" | "-" )
Factor(allowLemma, allowLambda, allowBitwiseOps) =
BitvectorFactor(allowLemma, allowLambda, allowBitwiseOps)
{ MulOp BitvectorFactor(allowLemma, allowLambda, allowBitwiseOps) }
MulOp = ( "*" | "/" | "%" )
BitvectorFactor(allowLemma, allowLambda, allowBitwiseOps) =
AsExpression(allowLemma, allowLambda, allowBitwiseOps)
{ BVOp AsExpression(allowLemma, allowLambda, allowBitwiseOps) }
BVOp = ( "|" | "&" | "^" )
If allowBitwiseOps
is false, it is an error to have a bitvector operation.
AsExpression(allowLemma, allowLambda, allowBitwiseOps) =
UnaryExpression(allowLemma, allowLambda, allowBitwiseOps)
{ ( "as" | "is" ) Type }
UnaryExpression(allowLemma, allowLambda, allowBitwiseOps) =
( "-" UnaryExpression(allowLemma, allowLambda, allowBitwiseOps)
| "!" UnaryExpression(allowLemma, allowLambda, allowBitwiseOps)
| PrimaryExpression(allowLemma, allowLambda, allowBitwiseOps)
)
PrimaryExpression(allowLemma, allowLambda, allowBitwiseOps) =
( NameSegment { Suffix }
| LambdaExpression(allowLemma, allowBitwiseOps)
| MapDisplayExpr { Suffix }
| SeqDisplayExpr { Suffix }
| SetDisplayExpr { Suffix }
| EndlessExpression(allowLemma, allowLambda, allowBitwiseOps)
| ConstAtomExpression { Suffix }
)
LambdaExpression(allowLemma, allowBitwiseOps) =
( WildIdent
| "(" [ IdentTypeOptional { "," IdentTypeOptional } ] ")"
)
LambdaSpec
"=>"
Expression(allowLemma, allowLambda: true, allowBitwiseOps)
(discussion) {
Lhs =
( NameSegment { Suffix }
| ConstAtomExpression Suffix { Suffix }
)
Rhs =
ArrayAllocation
| ObjectAllocation_
| Expression(allowLemma: false, allowLambda: true, allowBitwiseOps: true)
| HavocRhs_
)
{ Attribute }
ArrayAllocation_ =
"new" [ Type ] "[" [ Expressions ] "]"
[ "(" Expression(allowLemma: true, allowLambda: true) ")"
| "[" [ Expressions ] "]"
]
ObjectAllocation_ = "new" Type [ "." TypeNameOrCtorSuffix ]
[ "(" [ Bindings ] ")" ]
HavocRhs_ = "*"
ConstAtomExpression =
( LiteralExpression
| ThisExpression_
| FreshExpression_
| AllocatedExpression_
| UnchangedExpression_
| OldExpression_
| CardinalityExpression_
| ParensExpression
)
LiteralExpression =
( "false" | "true" | "null" | Nat | Dec |
charToken | stringToken )
Nat = ( digits | hexdigits )
Dec = decimaldigits
ThisExpression_ = "this"
OldExpression_ =
"old" [ "@" LabelName ]
"(" Expression(allowLemma: true, allowLambda: true) ")"
FreshExpression_ =
"fresh" [ "@" LabelName ]
"(" Expression(allowLemma: true, allowLambda: true) ")"
AllocatedExpression_ =
"allocated" "(" Expression(allowLemma: true, allowLambda: true) ")"
UnchangedExpression_ =
"unchanged" [ "@" LabelName ]
"(" FrameExpression(allowLemma: true, allowLambda: true)
{ "," FrameExpression(allowLemma: true, allowLambda: true) }
")"
CardinalityExpression_ =
"|" Expression(allowLemma: true, allowLambda: true) "|"
ParensExpression =
"(" [ TupleArgs ] ")"
TupleArgs =
[ "ghost" ]
ActualBinding(isGhost) // argument is true iff the ghost modifier is present
{ ","
[ "ghost" ]
ActualBinding(isGhost) // argument is true iff the ghost modifier is present
}
SeqDisplayExpr =
( "[" [ Expressions ] "]"
| "seq" [ GenericInstantiation ]
"(" Expression(allowLemma: true, allowLambda: true)
"," Expression(allowLemma: true, allowLambda: true)
")"
)
SetDisplayExpr =
( [ "iset" | "multiset" ] "{" [ Expressions ] "}"
| "multiset" "(" Expression(allowLemma: true,
allowLambda: true) ")"
)
MapDisplayExpr =
("map" | "imap" ) "[" [ MapLiteralExpressions ] "]"
MapLiteralExpressions =
Expression(allowLemma: true, allowLambda: true)
":="
Expression(allowLemma: true, allowLambda: true)
{ ","
Expression(allowLemma: true, allowLambda: true)
":="
Expression(allowLemma: true, allowLambda: true)
}
EndlessExpression(allowLemma, allowLambda, allowBitwiseOps) =
( IfExpression(allowLemma, allowLambda, allowBitwiseOps)
| MatchExpression(allowLemma, allowLambda, allowBitwiseOps)
| QuantifierExpression(allowLemma, allowLambda)
| SetComprehensionExpr(allowLemma, allowLambda, allowBitwiseOps)
| StmtInExpr
Expression(allowLemma, allowLambda, allowBitwiseOps)
| LetExpression(allowLemma, allowLambda, allowBitwiseOps)
| MapComprehensionExpr(allowLemma, allowLambda, allowBitwiseOps)
)
IfExpression(allowLemma, allowLambda, allowBitwiseOps) =
"if" ( BindingGuard(allowLambda: true)
| Expression(allowLemma: true, allowLambda: true, allowBitwiseOps: true)
)
"then" Expression(allowLemma: true, allowLambda: true, allowBitwiseOps: true)
"else" Expression(allowLemma, allowLambda, allowBitwiseOps)
MatchExpression(allowLemma, allowLambda, allowBitwiseOps) =
"match"
Expression(allowLemma, allowLambda, allowBitwiseOps)
( "{" { CaseExpression(allowLemma: true, allowLambda, allowBitwiseOps: true) } "}"
| { CaseExpression(allowLemma, allowLambda, allowBitwiseOps) }
)
CaseExpression(allowLemma, allowLambda, allowBitwiseOps) =
"case" { Attribute } ExtendedPattern "=>" Expression(allowLemma, allowLambda, allowBitwiseOps)
CasePattern =
( IdentTypeOptional
| [Ident] "(" [ CasePattern { "," CasePattern } ] ")"
)
SingleExtendedPattern =
( PossiblyNegatedLiteralExpression
| IdentTypeOptional
| [ Ident ] "(" [ SingleExtendedPattern { "," SingleExtendedPattern } ] ")"
)
ExtendedPattern =
( [ "|" ] SingleExtendedPattern { "|" SingleExtendedPattern } )
PossiblyNegatedLiteralExpression =
( "-" ( Nat | Dec )
| LiteralExpression
)
QuantifierExpression(allowLemma, allowLambda) =
( "forall" | "exists" ) QuantifierDomain "::"
Expression(allowLemma, allowLambda)
SetComprehensionExpr(allowLemma, allowLambda) =
[ "set" | "iset" ]
QuantifierDomain(allowLemma, allowLambda)
[ "::" Expression(allowLemma, allowLambda) ]
MapComprehensionExpr(allowLemma, allowLambda) =
( "map" | "imap" )
QuantifierDomain(allowLemma, allowLambda)
"::"
Expression(allowLemma, allowLambda)
[ ":=" Expression(allowLemma, allowLambda) ]
StmtInExpr = ( AssertStmt | AssumeStmt | ExpectStmt
| RevealStmt | CalcStmt
)
LetExpression(allowLemma, allowLambda) =
(
[ "ghost" ] "var" CasePattern { "," CasePattern }
( ":=" | ":-" | { Attribute } ":|" )
Expression(allowLemma: false, allowLambda: true)
{ "," Expression(allowLemma: false, allowLambda: true) }
|
":-"
Expression(allowLemma: false, allowLambda: true)
)
";"
Expression(allowLemma, allowLambda)
NameSegment = Ident [ GenericInstantiation | HashCall ]
HashCall = "#" [ GenericInstantiation ]
"[" Expression(allowLemma: true, allowLambda: true) "]"
"(" [ Bindings ] ")"
Suffix =
( AugmentedDotSuffix_
| DatatypeUpdateSuffix_
| SubsequenceSuffix_
| SlicesByLengthSuffix_
| SequenceUpdateSuffix_
| SelectionSuffix_
| ArgumentListSuffix_
)
AugmentedDotSuffix_ = "." DotSuffix
[ GenericInstantiation | HashCall ]
DatatypeUpdateSuffix_ =
"." "(" MemberBindingUpdate { "," MemberBindingUpdate } ")"
MemberBindingUpdate =
( ident | digits )
":=" Expression(allowLemma: true, allowLambda: true)
SubsequenceSuffix_ =
"[" [ Expression(allowLemma: true, allowLambda: true) ]
".." [ Expression(allowLemma: true, allowLambda: true) ]
"]"
SlicesByLengthSuffix_ =
"[" Expression(allowLemma: true, allowLambda: true) ":"
[
Expression(allowLemma: true, allowLambda: true)
{ ":" Expression(allowLemma: true, allowLambda: true) }
[ ":" ]
]
"]"
SequenceUpdateSuffix_ =
"[" Expression(allowLemma: true, allowLambda: true)
":=" Expression(allowLemma: true, allowLambda: true)
"]"
SelectionSuffix_ =
"[" Expression(allowLemma: true, allowLambda: true)
{ "," Expression(allowLemma: true, allowLambda: true) }
"]"
ArgumentListSuffix_ = "(" [ Expressions ] ")"
Expressions =
Expression(allowLemma: true, allowLambda: true)
{ "," Expression(allowLemma: true, allowLambda: true) }
ActualBindings =
ActualBinding
{ "," ActualBinding }
ActualBinding(isGhost = false) =
[ NoUSIdentOrDigits ":=" ]
Expression(allowLemma: true, allowLambda: true)
QuantifierDomain(allowLemma, allowLambda) =
QuantifierVarDecl(allowLemma, allowLambda)
{ "," QuantifierVarDecl(allowLemma, allowLambda) }
QuantifierVarDecl(allowLemma, allowLambda) =
IdentTypeOptional
[ "<-" Expression(allowLemma, allowLambda) ]
{ Attribute }
[ | Expression(allowLemma, allowLambda) ]
Ident = ident
DotSuffix = ( ident | digits | "requires" | "reads" )
NoUSIdent = ident - "_" { idchar }
WildIdent = NoUSIdent | "_"
IdentOrDigits = Ident | digits
NoUSIdentOrDigits = NoUSIdent | digits
ModuleName = NoUSIdent
ClassName = NoUSIdent // also traits
DatatypeName = NoUSIdent
DatatypeMemberName = NoUSIdentOrDigits
NewtypeName = NoUSIdent
SynonymTypeName = NoUSIdent
IteratorName = NoUSIdent
TypeVariableName = NoUSIdent
MethodFunctionName = NoUSIdentOrDigits
LabelName = NoUSIdentOrDigits
AttributeName = NoUSIdent
ExportId = NoUSIdentOrDigits
TypeNameOrCtorSuffix = NoUSIdentOrDigits
ModuleQualifiedName = ModuleName { "." ModuleName }
IdentType = WildIdent ":" Type
FIdentType = NoUSIdentOrDigits ":" Type
CIdentType = NoUSIdentOrDigits [ ":" Type ]
GIdentType(allowGhostKeyword, allowNewKeyword, allowOlderKeyword, allowNameOnlyKeyword, allowDefault) =
{ "ghost" | "new" | "nameonly" | "older" } IdentType
[ ":=" Expression(allowLemma: true, allowLambda: true) ]
LocalIdentTypeOptional = WildIdent [ ":" Type ]
IdentTypeOptional = WildIdent [ ":" Type ]
TypeIdentOptional =
{ Attribute }
{ "ghost" | "nameonly" } [ NoUSIdentOrDigits ":" ] Type
[ ":=" Expression(allowLemma: true, allowLambda: true) ]
FormalsOptionalIds = "(" [ TypeIdentOptional
{ "," TypeIdentOptional } ] ")"