Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Why3
why3
Commits
70a1f7df
Commit
70a1f7df
authored
Jan 29, 2017
by
Jean-Christophe Filliâtre
Browse files
python: logical annotations
parent
85fa13a1
Changes
6
Hide whitespace changes
Inline
Side-by-side
.gitignore
View file @
70a1f7df
...
...
@@ -217,6 +217,7 @@ pvsbin/
/plugins/python/py_parser.ml
/plugins/python/py_parser.mli
/plugins/python/test/
/plugins/python/py_parser.conflicts
# /drivers
/drivers/coq-realizations.aux
...
...
plugins/python/py_ast.ml
View file @
70a1f7df
...
...
@@ -54,6 +54,7 @@ and stmt_desc =
|
Sfor
of
ident
*
expr
*
stmt
|
Seval
of
expr
|
Sset
of
expr
*
expr
*
expr
(* e1[e2] = e3 *)
|
Sassert
of
Ptree
.
term
and
def
=
ident
*
ident
list
*
stmt
...
...
plugins/python/py_lexer.mll
View file @
70a1f7df
...
...
@@ -36,10 +36,20 @@
let
string_buffer
=
Buffer
.
create
1024
let
stack
=
ref
[
0
]
(* indentation stack *)
let
rec
unindent
n
=
match
!
stack
with
|
m
::
_
when
m
=
n
->
[]
|
m
::
st
when
m
>
n
->
stack
:=
st
;
END
::
unindent
n
|
_
->
raise
(
Lexing_error
"bad indentation"
)
let
update_stack
n
=
match
!
stack
with
|
m
::
_
when
m
<
n
->
stack
:=
n
::
!
stack
;
[
NEWLINE
;
BEGIN
]
|
_
->
NEWLINE
::
unindent
n
}
let
letter
=
[
'
a'
-
'
z'
'
A'
-
'
Z'
]
...
...
@@ -47,22 +57,17 @@ let digit = ['0'-'9']
let
ident
=
letter
(
letter
|
digit
|
'
_'
)
*
let
integer
=
[
'
0
'
-
'
9
'
]
+
let
space
=
'
'
|
'\t'
let
comment
=
"#"
[
^
'\n'
]
*
let
comment
=
"#"
[
^
'
#
'
'\n'
]
[
^
'\n'
]
*
rule
next_tokens
=
parse
|
'\n'
{
newline
lexbuf
;
let
n
=
indentation
lexbuf
in
match
!
stack
with
|
m
::
_
when
m
<
n
->
stack
:=
n
::
!
stack
;
[
NEWLINE
;
BEGIN
]
|
_
->
NEWLINE
::
unindent
n
}
|
'\n'
{
newline
lexbuf
;
update_stack
(
indentation
lexbuf
)
}
|
(
space
|
comment
)
+
{
next_tokens
lexbuf
}
|
ident
as
id
{
[
id_or_kwd
id
]
}
{
next_tokens
lexbuf
}
|
"##"
space
*
"invariant"
space
+
{
[
INVARIANT
]
}
|
"##"
space
*
"variant"
space
+
{
[
VARIANT
]
}
|
"##"
space
*
"assert"
space
+
{
[
ASSERT
]
}
|
ident
as
id
{
[
id_or_kwd
id
]
}
|
'
+
'
{
[
PLUS
]
}
|
'
-
'
{
[
MINUS
]
}
|
'
*
'
{
[
TIMES
]
}
...
...
@@ -81,14 +86,19 @@ rule next_tokens = parse
|
'
]
'
{
[
RSQ
]
}
|
'
,
'
{
[
COMMA
]
}
|
'
:
'
{
[
COLON
]
}
(* logic symbols *)
|
"->"
{
[
ARROW
]
}
|
"->"
{
[
LRARROW
]
}
|
integer
as
s
{
[
INTEGER
s
]
}
|
'
"' { [STRING (string lexbuf)] }
| eof { [EOF] }
| _ as c { raise (Lexing_error ("
illegal
character
:
" ^ String.make 1 c)) }
(* count the indentation, i.e. the number of space characters from bol *)
and indentation = parse
| (space | comment)* '
\n
'
(* skip empty lines *)
{ newline lexbuf; indentation lexbuf }
| space* as s
{ String.length s }
...
...
plugins/python/py_main.ml
View file @
70a1f7df
...
...
@@ -14,7 +14,7 @@ open Mlw_module
open
Ptree
open
Stdlib
let
debug
=
Debug
.
register_flag
"
mini-
python"
let
debug
=
Debug
.
register_flag
"python"
~
desc
:
"mini-python plugin debug flag"
let
mk_id
?
(
loc
=
Loc
.
dummy_position
)
name
=
...
...
@@ -22,6 +22,8 @@ let mk_id ?(loc=Loc.dummy_position) name =
let
mk_expr
?
(
loc
=
Loc
.
dummy_position
)
d
=
{
expr_desc
=
d
;
expr_loc
=
loc
}
let
mk_term
?
(
loc
=
Loc
.
dummy_position
)
d
=
{
term_desc
=
d
;
term_loc
=
loc
}
let
mk_unit
~
loc
=
mk_expr
~
loc
(
Etuple
[]
)
...
...
@@ -37,12 +39,24 @@ let empty_spec = {
}
type
env
=
{
vars
:
uni
t
Hstr
.
t
;
vars
:
iden
t
Hstr
.
t
;
}
let
infix
~
loc
s
=
Qident
(
mk_id
~
loc
(
"infix "
^
s
))
let
prefix
~
loc
s
=
Qident
(
mk_id
~
loc
(
"prefix "
^
s
))
(* dereference all variables from the environment *)
let
deref
env
t
=
let
deref
_
({
id_loc
=
loc
}
as
id
)
t
=
let
tid
=
mk_term
~
loc
(
Tident
(
Qident
id
))
in
let
tid
=
mk_term
~
loc
(
Tidapp
(
prefix
~
loc
"!"
,
[
tid
]))
in
mk_term
~
loc
:
t
.
term_loc
(
Tlet
(
id
,
tid
,
t
))
in
Hstr
.
fold
deref
env
.
vars
t
let
loop_annotation
env
a
=
{
loop_invariant
=
List
.
map
(
deref
env
)
a
.
loop_invariant
;
loop_variant
=
List
.
map
(
fun
(
t
,
o
)
->
deref
env
t
,
o
)
a
.
loop_variant
}
let
rec
expr
env
{
Py_ast
.
expr_loc
=
loc
;
Py_ast
.
expr_desc
=
d
}
=
match
d
with
|
Py_ast
.
Enone
->
mk_unit
~
loc
...
...
@@ -78,11 +92,11 @@ let rec expr env {Py_ast.expr_loc = loc; Py_ast.expr_desc = d } = match d with
mk_expr
~
loc
(
Eidapp
(
prefix
~
loc
"-"
,
[
expr
env
e
]))
|
Py_ast
.
Eunop
(
Py_ast
.
Unot
,
e
)
->
mk_expr
~
loc
(
Eidapp
(
Qident
(
mk_id
~
loc
"not"
)
,
[
expr
env
e
]))
|
Py_ast
.
Ecall
(
id
,
el
)
->
|
Py_ast
.
Ecall
(
_
id
,
_
el
)
->
assert
false
(*TODO*)
|
Py_ast
.
Elist
el
->
|
Py_ast
.
Elist
_
el
->
assert
false
|
Py_ast
.
Eget
(
e1
,
e2
)
->
|
Py_ast
.
Eget
(
_
e1
,
_
e2
)
->
assert
false
(*TODO*)
let
rec
stmt
env
({
Py_ast
.
stmt_loc
=
loc
;
Py_ast
.
stmt_desc
=
d
}
as
s
)
=
...
...
@@ -96,8 +110,8 @@ let rec stmt env ({Py_ast.stmt_loc = loc; Py_ast.stmt_desc = d } as s) =
|
Py_ast
.
Sif
(
e
,
s1
,
s2
)
->
mk_expr
~
loc
(
Eif
(
expr
env
e
,
stmt
env
s1
,
stmt
env
s2
))
|
Py_ast
.
Swhile
(
e
,
ann
,
s
)
->
mk_expr
~
loc
(
Ewhile
(
expr
env
e
,
ann
,
stmt
env
s
))
|
Py_ast
.
Sreturn
e
->
mk_expr
~
loc
(
Ewhile
(
expr
env
e
,
loop_annotation
env
ann
,
stmt
env
s
))
|
Py_ast
.
Sreturn
_
e
->
assert
false
(*TODO*)
|
Py_ast
.
Sassign
(
id
,
e
)
->
let
e
=
expr
env
e
in
...
...
@@ -106,10 +120,12 @@ let rec stmt env ({Py_ast.stmt_loc = loc; Py_ast.stmt_desc = d } as s) =
mk_expr
~
loc
(
Einfix
(
x
,
mk_id
~
loc
"infix :="
,
e
))
else
block
env
loc
[
s
]
|
Py_ast
.
Sfor
(
id
,
e
,
s
)
->
|
Py_ast
.
Sfor
(
_
id
,
_
e
,
_
s
)
->
assert
false
(*TODO*)
|
Py_ast
.
Sset
(
e1
,
e2
,
e3
)
->
|
Py_ast
.
Sset
(
_
e1
,
_
e2
,
_
e3
)
->
assert
false
(*TODO*)
|
Py_ast
.
Sassert
t
->
mk_expr
~
loc
(
Eassert
(
Aassert
,
deref
env
t
))
and
block
env
loc
=
function
|
[]
->
...
...
@@ -117,7 +133,7 @@ and block env loc = function
|
{
Py_ast
.
stmt_loc
=
loc
;
stmt_desc
=
Py_ast
.
Sassign
(
id
,
e
)
}
::
sl
when
not
(
Hstr
.
mem
env
.
vars
id
.
id_str
)
->
let
e
=
expr
env
e
in
(* check e *before* adding id to environment *)
Hstr
.
add
env
.
vars
id
.
id_str
()
;
Hstr
.
add
env
.
vars
id
.
id_str
id
;
let
e1
=
mk_expr
~
loc
(
Eidapp
(
Qident
(
mk_id
~
loc
"ref"
)
,
[
e
]))
in
mk_expr
~
loc
(
Elet
(
id
,
Gnone
,
e1
,
block
env
loc
sl
))
|
{
Py_ast
.
stmt_loc
=
loc
}
as
s
::
sl
->
...
...
plugins/python/py_parser.mly
View file @
70a1f7df
...
...
@@ -29,6 +29,10 @@
let
empty_annotation
=
{
loop_invariant
=
[]
;
loop_variant
=
[]
}
let
infix
s
=
"infix "
^
s
let
prefix
s
=
"prefix "
^
s
let
mixfix
s
=
"mixfix "
^
s
%
}
%
token
<
string
>
INTEGER
...
...
@@ -41,12 +45,14 @@
%
token
PLUS
MINUS
TIMES
DIV
MOD
/*
annotations
*/
%
token
INVARIANT
VARIANT
%
token
INVARIANT
VARIANT
ASSERT
%
token
ARROW
LRARROW
%
right
ARROW
LRARROW
%
left
OR
%
left
AND
%
nonassoc
NOT
%
nonassoc
CMP
%
left
CMP
%
left
PLUS
MINUS
%
left
TIMES
DIV
MOD
%
nonassoc
unary_minus
...
...
@@ -153,10 +159,10 @@ loop_annotation:
{
let
a
=
$
2
in
{
a
with
loop_variant
=
variant_union
$
1
a
.
loop_variant
}
}
invariant
:
|
INVARIANT
i
=
term
{
i
}
|
INVARIANT
i
=
term
NEWLINE
{
i
}
variant
:
|
VARIANT
l
=
comma_list1
(
term
)
{
List
.
map
(
fun
t
->
t
,
None
)
l
}
|
VARIANT
l
=
comma_list1
(
term
)
NEWLINE
{
List
.
map
(
fun
t
->
t
,
None
)
l
}
simple_stmt
:
located
(
simple_stmt_desc
)
{
$
1
};
...
...
@@ -169,6 +175,8 @@ simple_stmt_desc:
{
Sset
(
e1
,
e2
,
e3
)
}
|
PRINT
e
=
expr
{
Sprint
e
}
|
ASSERT
t
=
term
{
Sassert
t
}
|
e
=
expr
{
Seval
e
}
;
...
...
@@ -184,10 +192,48 @@ mk_term(X): d = X { mk_term d $startpos $endpos }
term
:
t
=
mk_term
(
term_
)
{
t
}
term_
:
|
term_arg_
{
match
$
1
with
(* break the infix relation chain *)
|
Tinfix
(
l
,
o
,
r
)
->
Tinnfix
(
l
,
o
,
r
)
|
d
->
d
}
|
NOT
term
{
Tunop
(
Tnot
,
$
2
)
}
|
l
=
term
;
o
=
bin_op
;
r
=
term
{
Tbinop
(
l
,
o
,
r
)
}
|
l
=
term
;
o
=
infix_op
;
r
=
term
{
Tinfix
(
l
,
o
,
r
)
}
|
l
=
term
;
o
=
div_mod_op
;
r
=
term
{
Tidapp
(
Qident
o
,
[
l
;
r
])
}
(* term_arg: mk_term(term_arg_) { $1 } *)
term_arg_
:
|
ident
{
Tident
(
Qident
$
1
)
}
|
INTEGER
{
Tconst
(
Number
.
ConstInt
((
Number
.
int_const_dec
$
1
)))
}
|
TRUE
{
Ttrue
}
|
FALSE
{
Tfalse
}
%
inline
bin_op
:
|
ARROW
{
Timplies
}
|
LRARROW
{
Tiff
}
|
OR
{
Tor
}
|
AND
{
Tand
}
%
inline
infix_op
:
|
PLUS
{
mk_id
(
infix
"+"
)
$
startpos
$
endpos
}
|
MINUS
{
mk_id
(
infix
"-"
)
$
startpos
$
endpos
}
|
TIMES
{
mk_id
(
infix
"*"
)
$
startpos
$
endpos
}
|
c
=
CMP
{
let
op
=
match
c
with
|
Beq
->
"="
|
Bneq
->
"<>"
|
Blt
->
"<"
|
Ble
->
"<="
|
Bgt
->
">"
|
Bge
->
">="
in
mk_id
(
infix
op
)
$
startpos
$
endpos
}
%
inline
div_mod_op
:
|
DIV
{
mk_id
"div"
$
startpos
$
endpos
}
|
MOD
{
mk_id
"mod"
$
startpos
$
endpos
}
comma_list1
(
X
)
:
|
separated_nonempty_list
(
COMMA
,
X
)
{
$
1
}
plugins/python/test.py
View file @
70a1f7df
...
...
@@ -2,8 +2,12 @@
a
=
0
b
=
1
while
b
<
100
:
## invariant b >= a >= 0
## invariant b >= 1
## variant 200 - b - a
print
(
a
)
b
=
a
+
b
## assert b >= 1
a
=
b
-
a
# Local Variables:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment