Note: the command-line version of Why3 is also supporting this input format, for files with suffix .py.
Logical annotations are inserted in special comments starting with //@ or /*@. In the following grammar, we only use the former kind, for simplicity, but both kinds are allowed.
file ::= decl*
decl ::= py-import | py-function | stmt | logic-declaration
py-import ::= "from" ident "import" ident { "," ident } NEWLINE
Directives import are ignored during the translation to
Why3. They are allowed anyway, such that a Python source code using
functions such as randint is accepted by a Python
interpreter (see below).
py-function ::= "def" ident "(" [ params ] ")" ":" NEWLINE INDENT { spec } { stmt } DEDENT
params ::= ident { "," ident }
spec ::= "requires" term NEWLINE
| "ensures" term NEWLINE
| "variant" term { "," term } NEWLINE
expr ::= "None" | "True" | "False" | integer-literal | string-literal
| identifier
| identifier "[" expr "]"
| "-" expr | "not" expr
| expr ( "+" | "-" | "*" | "//" | "%" | "==" | "!=" | "<" | "<=" | ">" | ">=" | "and" | "or" ) expr
| identifier "(" [ expr { "," expr } ] ")"
| "[" [ expr { "," expr } ] "]"
| "(" expr ")"
stmt ::= simple_stmt NEWLINE
| "if" expr ":" suite else_branch
| "while" expr ":" loop_body
| "for" ident "in" expr ":" loop_body
else_branch ::= /* nothing */
| "else:" suite
| "elif" expr ":" suite else_branch
suite ::= simple_stmt NEWLINE
| NEWLINE INDENT stmt { stmt } DEDENT
simple_stmt ::= expr
| "return" expr
| identifier "=" expr
| identifier "[" expr "]" "=" expr
| "break"
| "//@" "label" identifier
| "//@" ( "assert" | "assume" | "check" ) term
assignop ::= "=" | "+=" | "-=" | "*=" | "/="
loop_body ::= simple_stmt NEWLINE
| NEWLINE INDENT { loop_annot } stmt { stmt } DEDENT
loop_annot ::= "//@" "invariant" term NEWLINE
| "//@" "variant" term { "," term } NEWLINE
logic-declaration ::= "//@" "function" "int" identifier "(" params ")" NEWLINE
| "//@" "predicate" identifier "(" params ")" NEWLINE
Note that logic functions and predicates cannot be given definitions.
Yet, they can be axiomatized, using toplevel assume statements.
term ::= identifier
| integer-literal
| "None"
| "True"
| "False"
| "(" term ")"
| term "[" term "]"
| term "[" term "<-" term "]"
| "not" term
| "old" "(" term ")"
| "at" "(" term "," identifier ")"
| "-" term
| term ( "->" | "<->" | "or" | "and" ) term
| term ( "==" | "!=" | "<" | "<=" | ">" | ">=" ) term
| term ( "+" | "-" | "*" | "//" | "% ) term
| "if" term "then" term "else term
| "let" identifier "=" term "in" term
| ( "forall" | "exists" ) ident { "," ident } "." term
| identifier "(" [ term { "," term } ] ")"
Click on the gears button to launch the verification. Verification conditions (VCs) then appear in the right panel, in the Task List tab, and Alt-Ergo is run on each of them with a default time limit (that can be set in the Settings menu).
When a VC is not proved, there are several options: