Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
why3
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
119
Issues
119
List
Boards
Labels
Service Desk
Milestones
Merge Requests
16
Merge Requests
16
Operations
Operations
Incidents
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Why3
why3
Commits
b65d100c
Commit
b65d100c
authored
Jan 30, 2017
by
Jean-Christophe Filliâtre
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
python: building lists
parent
dadb2908
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
121 additions
and
29 deletions
+121
-29
modules/python.mlw
modules/python.mlw
+11
-11
plugins/python/py_ast.ml
plugins/python/py_ast.ml
+4
-3
plugins/python/py_lexer.mll
plugins/python/py_lexer.mll
+12
-5
plugins/python/py_main.ml
plugins/python/py_main.ml
+42
-5
plugins/python/py_parser.mly
plugins/python/py_parser.mly
+40
-4
plugins/python/test.py
plugins/python/test.py
+12
-1
No files found.
modules/python.mlw
View file @
b65d100c
...
...
@@ -3,35 +3,35 @@ module Python
use import int.Int
use import ref.Ref
use array.Array
as A
use array.Array
(* Python's lists are actually resizable arrays, but we simplify here *)
type list 'a = A.array 'a
type list 'a = A
rray
.array 'a
function ([]) (l: list 'a) (i: int) : 'a =
A.get l i
A
rray
.get l i
function len (l: list 'a) : int =
A.length l
A
rray
.length l
let len (l: list 'a) : int
ensures { result = len(l) }
= A.length l
= A
rray
.length l
let ([]) (l: list 'a) (i: int) : 'a
requires { 0 <= i < A.length l }
requires { 0 <= i < A
rray
.length l }
ensures { result = l[i] }
= A.([]) l i
= A
rray
.([]) l i
let ([]<-) (l: list 'a) (i: int) (v: 'a) : unit
requires { 0 <= i < A.length l }
requires { 0 <= i < A
rray
.length l }
writes { l }
ensures { l = A.([<-]) (old l) i v }
= A.([]<-) l i v
ensures { l = A
rray
.([<-]) (old l) i v }
= A
rray
.([]<-) l i v
val range (l u: int) : list int
requires { l <= u }
ensures { A.length result = u - l }
ensures { A
rray
.length result = u - l }
ensures { forall i. l <= i < u -> result[i] = i }
(* Python's division and modulus according are neither Euclidean division,
...
...
plugins/python/py_ast.ml
View file @
b65d100c
...
...
@@ -36,8 +36,9 @@ and expr_desc =
|
Ebinop
of
binop
*
expr
*
expr
|
Eunop
of
unop
*
expr
|
Ecall
of
ident
*
expr
list
|
Elist
of
expr
list
|
Eget
of
expr
*
expr
(* e1[e2] *)
|
Elist
of
expr
list
(* [e1, e2, ..., en] *)
|
Emake
of
expr
*
expr
(* [e1] * e2 *)
|
Eget
of
expr
*
expr
(* e1[e2] *)
and
stmt
=
{
stmt_desc
:
stmt_desc
;
...
...
@@ -57,7 +58,7 @@ and stmt_desc =
and
block
=
stmt
list
and
def
=
ident
*
ident
list
*
block
and
def
=
ident
*
ident
list
*
Ptree
.
spec
*
block
and
file
=
def
list
*
block
...
...
plugins/python/py_lexer.mll
View file @
b65d100c
...
...
@@ -33,6 +33,16 @@
];
fun
s
->
try
Hashtbl
.
find
h
s
with
Not_found
->
IDENT
s
let
annotation
=
let
h
=
Hashtbl
.
create
32
in
List
.
iter
(
fun
(
s
,
tok
)
->
Hashtbl
.
add
h
s
tok
)
[
"invariant"
,
INVARIANT
;
"variant"
,
VARIANT
;
"assert"
,
ASSERT
;
"assume"
,
ASSUME
;
"check"
,
CHECK
;
"requires"
,
REQUIRES
;
"ensures"
,
ENSURES
;
];
fun
s
->
try
Hashtbl
.
find
h
s
with
Not_found
->
raise
(
Lexing_error
(
"no such annotation '"
^
s
^
"'"
))
let
newline
lexbuf
=
let
pos
=
lexbuf
.
lex_curr_p
in
lexbuf
.
lex_curr_p
<-
...
...
@@ -68,11 +78,8 @@ rule next_tokens = parse
|
'\n'
{
newline
lexbuf
;
update_stack
(
indentation
lexbuf
)
}
|
(
space
|
comment
)
+
{
next_tokens
lexbuf
}
|
"#@"
space
*
"invariant"
space
+
{
[
INVARIANT
]
}
|
"#@"
space
*
"variant"
space
+
{
[
VARIANT
]
}
|
"#@"
space
*
"assert"
space
+
{
[
ASSERT
]
}
|
"#@"
space
*
"assume"
space
+
{
[
ASSUME
]
}
|
"#@"
space
*
"check"
space
+
{
[
CHECK
]
}
|
"#@"
space
*
(
ident
as
id
)
{
[
annotation
id
]
}
|
"#@"
{
raise
(
Lexing_error
"expecting an annotation"
)
}
|
ident
as
id
{
[
id_or_kwd
id
]
}
...
...
plugins/python/py_main.ml
View file @
b65d100c
...
...
@@ -36,10 +36,15 @@ let mk_ref ~loc e =
mk_expr
~
loc
(
Eidapp
(
Qident
(
mk_id
~
loc
"ref"
)
,
[
e
]))
let
deref_id
~
loc
id
=
mk_expr
~
loc
(
Eidapp
(
prefix
~
loc
"!"
,
[
mk_expr
~
loc
(
Eident
(
Qident
id
))]))
let
array_set
~
loc
a
i
v
=
mk_expr
~
loc
(
Eidapp
(
mixfix
~
loc
"[]<-"
,
[
a
;
i
;
v
]))
let
constant
~
loc
s
=
mk_expr
~
loc
(
Econst
(
Number
.
ConstInt
(
Number
.
int_const_dec
s
)))
let
len
~
loc
=
Qident
(
mk_id
~
loc
"len"
)
let
array_make
~
loc
n
v
=
mk_expr
~
loc
(
Eidapp
(
Qdot
(
Qident
(
mk_id
~
loc
"Array"
)
,
mk_id
~
loc
"make"
)
,
[
n
;
v
]))
let
empty_spec
=
{
sp_pre
=
[]
;
...
...
@@ -122,8 +127,21 @@ let rec expr env {Py_ast.expr_loc = loc; Py_ast.expr_desc = d } = match d with
mk_expr
~
loc
(
Eidapp
(
Qident
(
mk_id
~
loc
"not"
)
,
[
expr
env
e
]))
|
Py_ast
.
Ecall
(
id
,
el
)
->
mk_expr
~
loc
(
Eidapp
(
Qident
id
,
List
.
map
(
expr
env
)
el
))
|
Py_ast
.
Elist
_el
->
assert
false
(*TODO*)
|
Py_ast
.
Emake
(
e1
,
e2
)
->
(* [e1]*e2 *)
array_make
~
loc
(
expr
env
e2
)
(
expr
env
e1
)
|
Py_ast
.
Elist
[]
->
array_make
~
loc
(
constant
~
loc
"0"
)
(
constant
~
loc
"0"
)
|
Py_ast
.
Elist
el
->
let
n
=
List
.
length
el
in
let
n
=
constant
~
loc
(
string_of_int
n
)
in
let
id
=
mk_id
~
loc
"new array"
in
mk_expr
~
loc
(
Elet
(
id
,
Gnone
,
array_make
~
loc
n
(
constant
~
loc
"0"
)
,
let
i
=
ref
(
-
1
)
in
let
init
seq
e
=
incr
i
;
let
i
=
constant
~
loc
(
string_of_int
!
i
)
in
let
assign
=
array_set
~
loc
(
mk_var
~
loc
id
)
i
(
expr
env
e
)
in
mk_expr
~
loc
(
Esequence
(
assign
,
seq
))
in
List
.
fold_left
init
(
mk_var
~
loc
id
)
el
))
|
Py_ast
.
Eget
(
e1
,
e2
)
->
mk_expr
~
loc
(
Eidapp
(
mixfix
~
loc
"[]"
,
[
expr
env
e1
;
expr
env
e2
]))
...
...
@@ -145,8 +163,7 @@ let rec stmt env ({Py_ast.stmt_loc = loc; Py_ast.stmt_desc = d } as s) =
else
block
env
~
loc
[
s
]
|
Py_ast
.
Sset
(
e1
,
e2
,
e3
)
->
mk_expr
~
loc
(
Eidapp
(
mixfix
~
loc
"[]<-"
,
[
expr
env
e1
;
expr
env
e2
;
expr
env
e3
]))
array_set
~
loc
(
expr
env
e1
)
(
expr
env
e2
)
(
expr
env
e3
)
|
Py_ast
.
Sassert
(
k
,
t
)
->
mk_expr
~
loc
(
Eassert
(
k
,
deref
env
t
))
|
Py_ast
.
Swhile
(
e
,
ann
,
s
)
->
...
...
@@ -192,7 +209,27 @@ and block env ?(loc=Loc.dummy_position) = function
let
sl
=
block
env
~
loc
sl
in
mk_expr
~
loc
(
Esequence
(
s
,
sl
))
let
translate
inc
(
_dl
,
s
)
=
let
post
env
(
loc
,
l
)
=
loc
,
List
.
map
(
fun
(
pat
,
t
)
->
pat
,
deref
env
t
)
l
let
spec
env
sp
=
assert
(
sp
.
sp_xpost
=
[]
&&
sp
.
sp_reads
=
[]
&&
sp
.
sp_writes
=
[]
&&
sp
.
sp_variant
=
[]
);
{
sp
with
sp_pre
=
List
.
map
(
deref
env
)
sp
.
sp_pre
;
sp_post
=
List
.
map
(
post
env
)
sp
.
sp_post
}
let
def
inc
(
id
,
idl
,
sp
,
bl
)
=
let
env
=
empty_env
in
let
env
=
List
.
fold_left
add_var
env
idl
in
let
param
id
=
id
.
id_loc
,
Some
id
,
false
,
None
in
let
params
=
List
.
map
param
idl
in
let
fd
=
(
params
,
None
,
block
env
bl
,
spec
env
sp
)
in
let
d
=
Dfun
(
id
,
Gnone
,
fd
)
in
inc
.
new_pdecl
id
.
id_loc
d
let
translate
inc
(
dl
,
s
)
=
List
.
iter
(
def
inc
)
dl
;
let
params
=
[
Loc
.
dummy_position
,
None
,
false
,
Some
(
PTtuple
[]
)]
in
let
env
=
empty_env
in
let
fd
=
(
params
,
None
,
block
env
s
,
empty_spec
)
in
...
...
plugins/python/py_parser.mly
View file @
b65d100c
...
...
@@ -20,6 +20,7 @@
let
floc
s
e
=
Loc
.
extract
(
s
,
e
)
let
mk_id
id
s
e
=
{
id_str
=
id
;
id_lab
=
[]
;
id_loc
=
floc
s
e
}
let
mk_pat
d
s
e
=
{
pat_desc
=
d
;
pat_loc
=
floc
s
e
}
let
mk_term
d
s
e
=
{
term_desc
=
d
;
term_loc
=
floc
s
e
}
let
mk_expr
loc
d
=
{
expr_desc
=
d
;
expr_loc
=
loc
}
let
mk_stmt
loc
d
=
{
stmt_desc
=
d
;
stmt_loc
=
loc
}
...
...
@@ -39,6 +40,23 @@
let
get_op
s
e
=
Qident
(
mk_id
(
mixfix
"[]"
)
s
e
)
let
empty_spec
=
{
sp_pre
=
[]
;
sp_post
=
[]
;
sp_xpost
=
[]
;
sp_reads
=
[]
;
sp_writes
=
[]
;
sp_variant
=
[]
;
sp_checkrw
=
false
;
sp_diverge
=
false
;
}
let
spec_union
s1
s2
=
{
sp_pre
=
s1
.
sp_pre
@
s2
.
sp_pre
;
sp_post
=
s1
.
sp_post
@
s2
.
sp_post
;
sp_xpost
=
s1
.
sp_xpost
@
s2
.
sp_xpost
;
sp_reads
=
s1
.
sp_reads
@
s2
.
sp_reads
;
sp_writes
=
s1
.
sp_writes
@
s2
.
sp_writes
;
sp_variant
=
variant_union
s1
.
sp_variant
s2
.
sp_variant
;
sp_checkrw
=
s1
.
sp_checkrw
||
s2
.
sp_checkrw
;
sp_diverge
=
s1
.
sp_diverge
||
s2
.
sp_diverge
;
}
%
}
%
token
<
string
>
INTEGER
...
...
@@ -50,7 +68,7 @@
%
token
LEFTPAR
RIGHTPAR
LEFTSQ
RIGHTSQ
COMMA
EQUAL
COLON
BEGIN
END
NEWLINE
%
token
PLUS
MINUS
TIMES
DIV
MOD
(* annotations *)
%
token
INVARIANT
VARIANT
ASSUME
ASSERT
CHECK
%
token
INVARIANT
VARIANT
ASSUME
ASSERT
CHECK
REQUIRES
ENSURES
%
token
ARROW
LRARROW
FORALL
EXISTS
DOT
THEN
LET
(* precedences *)
...
...
@@ -80,10 +98,25 @@ file:
def
:
|
DEF
f
=
ident
LEFTPAR
x
=
separated_list
(
COMMA
,
ident
)
RIGHTPAR
COLON
s
=
suite
{
f
,
x
,
s
}
COLON
NEWLINE
BEGIN
s
=
spec
l
=
nonempty_list
(
stmt
)
END
{
f
,
x
,
s
,
l
}
;
spec
:
|
(* epsilon *)
{
empty_spec
}
|
single_spec
spec
{
spec_union
$
1
$
2
}
single_spec
:
|
REQUIRES
t
=
term
NEWLINE
{
{
empty_spec
with
sp_pre
=
[
t
]
}
}
|
ENSURES
e
=
ensures
NEWLINE
{
{
empty_spec
with
sp_post
=
[
floc
$
startpos
(
e
)
$
endpos
(
e
)
,
e
]
}
}
ensures
:
|
term
{
let
id
=
mk_id
"result"
$
startpos
$
endpos
in
[
mk_pat
(
Pvar
id
)
$
startpos
$
endpos
,
$
1
]
}
expr
:
|
d
=
expr_desc
{
mk_expr
(
floc
$
startpos
$
endpos
)
d
}
...
...
@@ -110,6 +143,10 @@ expr_desc:
{
Eunop
(
Unot
,
e1
)
}
|
e1
=
expr
o
=
binop
e2
=
expr
{
Ebinop
(
o
,
e1
,
e2
)
}
|
e1
=
expr
TIMES
e2
=
expr
{
match
e1
.
expr_desc
with
|
Elist
[
e1
]
->
Emake
(
e1
,
e2
)
|
_
->
Ebinop
(
Bmul
,
e1
,
e2
)
}
|
f
=
ident
LEFTPAR
e
=
separated_list
(
COMMA
,
expr
)
RIGHTPAR
{
Ecall
(
f
,
e
)
}
|
LEFTSQ
l
=
separated_list
(
COMMA
,
expr
)
RIGHTSQ
...
...
@@ -121,7 +158,6 @@ expr_desc:
%
inline
binop
:
|
PLUS
{
Badd
}
|
MINUS
{
Bsub
}
|
TIMES
{
Bmul
}
|
DIV
{
Bdiv
}
|
MOD
{
Bmod
}
|
c
=
CMP
{
c
}
...
...
plugins/python/test.py
View file @
b65d100c
# def swap(a, i, j):
# #@ requires 0 <= i < len(a) and 0 <= j < len(a)
# t = a[i]
# a[i] = a[j]
# a[j] = t
a
=
0
b
=
1
while
b
<
100
:
...
...
@@ -24,12 +30,17 @@ while i < 10:
i
=
i
+
1
sum
=
0
for
x
in
l
:
for
x
in
[
42
]
*
3
:
#@ invariant sum >= 0
print
(
x
)
#@ assert x >= 0
sum
=
sum
+
x
foo
=
[
1
,
2
,
3
]
#@ assert len(foo)==3
#@ assert foo[1]==2
# Python's division is neither Euclidean division, nor computer division
#@ assert 4 // 3 == 1 and 4 % 3 == 1
#@ assert -4 // 3 == -2 and -4 % 3 == 2
...
...
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