2017-01-29 15:52:12 +01:00
|
|
|
(********************************************************************)
|
|
|
|
|
(* *)
|
|
|
|
|
(* The Why3 Verification Platform / The Why3 Development Team *)
|
2025-06-04 10:51:30 +02:00
|
|
|
(* Copyright 2010-2025 -- Inria - CNRS - Paris-Saclay University *)
|
2017-01-29 15:52:12 +01:00
|
|
|
(* *)
|
|
|
|
|
(* This software is distributed under the terms of the GNU Lesser *)
|
|
|
|
|
(* General Public License version 2.1, with the special exception *)
|
|
|
|
|
(* on linking described in file LICENSE. *)
|
|
|
|
|
(********************************************************************)
|
2017-01-29 13:02:04 +01:00
|
|
|
|
|
|
|
|
open Why3
|
2017-04-14 17:45:25 +02:00
|
|
|
open Pmodule
|
2017-01-31 20:52:16 +01:00
|
|
|
open Py_ast
|
2017-01-29 13:02:04 +01:00
|
|
|
open Ptree
|
2018-05-17 11:26:04 +02:00
|
|
|
open Wstdlib
|
2017-01-29 13:02:04 +01:00
|
|
|
|
2017-01-29 16:57:49 +01:00
|
|
|
let debug = Debug.register_flag "python"
|
2017-01-29 13:02:04 +01:00
|
|
|
~desc:"mini-python plugin debug flag"
|
2018-01-19 10:46:11 +01:00
|
|
|
|
|
|
|
|
(* NO! this will be executed at plugin load, thus
|
|
|
|
|
disabling the warning for ALL WHY3 USERS even if they don't
|
|
|
|
|
use the python front-end
|
2017-01-31 16:02:44 +01:00
|
|
|
let () = Debug.set_flag Dterm.debug_ignore_unused_var
|
2018-01-19 10:46:11 +01:00
|
|
|
*)
|
2017-01-29 13:02:04 +01:00
|
|
|
|
2017-02-01 13:48:49 +01:00
|
|
|
let mk_id ~loc name =
|
2018-06-01 21:03:01 +02:00
|
|
|
{ id_str = name; id_ats = []; id_loc = loc }
|
2017-01-29 15:52:12 +01:00
|
|
|
|
2022-09-07 14:44:02 +02:00
|
|
|
let mk_prime id =
|
|
|
|
|
{ id with id_str = id.id_str ^ "'" }
|
|
|
|
|
let mk_prime_n =
|
|
|
|
|
let n = ref 0 in
|
|
|
|
|
fun id -> incr n; { id with id_str = id.id_str ^ "'" ^ string_of_int !n }
|
|
|
|
|
|
2020-06-24 22:19:17 +02:00
|
|
|
let id_infix ~loc s = mk_id ~loc (Ident.op_infix s)
|
|
|
|
|
let infix ~loc s = Qident (id_infix ~loc s)
|
2018-07-07 16:13:29 +02:00
|
|
|
let prefix ~loc s = Qident (mk_id ~loc (Ident.op_prefix s))
|
2018-07-17 21:39:24 +02:00
|
|
|
let get_op ~loc = Qident (mk_id ~loc (Ident.op_get ""))
|
|
|
|
|
let set_op ~loc = Qident (mk_id ~loc (Ident.op_set ""))
|
2017-01-30 19:12:37 +01:00
|
|
|
|
2017-02-01 13:48:49 +01:00
|
|
|
let mk_expr ~loc d =
|
2017-01-29 15:52:12 +01:00
|
|
|
{ expr_desc = d; expr_loc = loc }
|
2017-02-01 13:48:49 +01:00
|
|
|
let mk_pat ~loc d =
|
2017-01-31 20:52:16 +01:00
|
|
|
{ pat_desc = d; pat_loc = loc }
|
2017-01-29 15:52:12 +01:00
|
|
|
let mk_unit ~loc =
|
|
|
|
|
mk_expr ~loc (Etuple [])
|
2017-01-30 19:12:37 +01:00
|
|
|
let mk_var ~loc id =
|
|
|
|
|
mk_expr ~loc (Eident (Qident id))
|
2022-09-07 14:44:02 +02:00
|
|
|
let mk_pure t =
|
|
|
|
|
mk_expr ~loc:t.term_loc (Epure t)
|
|
|
|
|
|
2017-01-30 19:12:37 +01:00
|
|
|
let mk_ref ~loc e =
|
2022-09-07 14:44:02 +02:00
|
|
|
mk_expr ~loc (Eapply (mk_expr ~loc Eref, e))
|
|
|
|
|
let mk_lref ~loc id =
|
|
|
|
|
mk_expr ~loc (Easref (Qident id))
|
|
|
|
|
|
2017-01-30 22:53:30 +01:00
|
|
|
let array_set ~loc a i v =
|
2018-07-07 16:13:29 +02:00
|
|
|
mk_expr ~loc (Eidapp (set_op ~loc, [a; i; v]))
|
2017-11-23 19:17:25 +01:00
|
|
|
let constant ~loc i =
|
2019-09-19 20:14:54 +02:00
|
|
|
mk_expr ~loc (Econst (Constant.int_const_of_int i))
|
2017-11-23 19:17:25 +01:00
|
|
|
let constant_s ~loc s =
|
2019-09-19 20:14:54 +02:00
|
|
|
let int_lit = Number.(int_literal ILitDec ~neg:false s) in
|
|
|
|
|
mk_expr ~loc (Econst (Constant.ConstInt int_lit))
|
2017-01-30 19:12:37 +01:00
|
|
|
let len ~loc =
|
|
|
|
|
Qident (mk_id ~loc "len")
|
2021-06-23 17:33:19 +02:00
|
|
|
|
2017-01-30 22:53:30 +01:00
|
|
|
let array_make ~loc n v =
|
2021-06-23 17:33:19 +02:00
|
|
|
mk_expr ~loc (Eidapp (Qdot (Qident (mk_id ~loc "Python"), mk_id ~loc "make"),
|
2017-01-30 22:53:30 +01:00
|
|
|
[n; v]))
|
2021-06-23 17:33:19 +02:00
|
|
|
let array_empty ~loc =
|
|
|
|
|
mk_expr ~loc (Eidapp (Qdot (Qident (mk_id ~loc "Python"), mk_id ~loc "empty"), [mk_unit ~loc]))
|
2019-07-06 14:54:56 +02:00
|
|
|
let set_ref id =
|
|
|
|
|
{ id with id_ats = ATstr Pmodule.ref_attr :: id.id_ats }
|
2017-01-29 15:52:12 +01:00
|
|
|
|
|
|
|
|
let empty_spec = {
|
|
|
|
|
sp_pre = [];
|
|
|
|
|
sp_post = [];
|
|
|
|
|
sp_xpost = [];
|
|
|
|
|
sp_reads = [];
|
|
|
|
|
sp_writes = [];
|
2017-12-13 18:47:53 +01:00
|
|
|
sp_alias = [];
|
2017-01-29 15:52:12 +01:00
|
|
|
sp_variant = [];
|
|
|
|
|
sp_checkrw = false;
|
|
|
|
|
sp_diverge = false;
|
2018-09-27 15:24:02 +02:00
|
|
|
sp_partial = false;
|
2017-01-29 15:52:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type env = {
|
2017-01-30 19:12:37 +01:00
|
|
|
vars: ident Mstr.t;
|
2017-01-29 15:52:12 +01:00
|
|
|
}
|
|
|
|
|
|
2017-01-30 19:12:37 +01:00
|
|
|
let empty_env =
|
2021-09-28 17:12:46 +02:00
|
|
|
{ vars = Mstr.empty }
|
2017-01-30 19:12:37 +01:00
|
|
|
|
2021-06-23 17:33:19 +02:00
|
|
|
let is_const (e: Py_ast.expr list) =
|
|
|
|
|
match List.nth e 2 with
|
|
|
|
|
| {Py_ast.expr_desc=Eint "1";_} -> 1
|
|
|
|
|
| {Py_ast.expr_desc=Eunop (Uneg, {Py_ast.expr_desc=Eint "1";_});_} -> -1
|
|
|
|
|
| _ -> 0
|
|
|
|
|
|
2017-01-30 19:12:37 +01:00
|
|
|
let add_var env id =
|
2021-09-28 17:12:46 +02:00
|
|
|
{ vars = Mstr.add id.id_str id env.vars }
|
2021-09-24 18:27:07 +02:00
|
|
|
let add_param env (id, _) =
|
|
|
|
|
add_var env id
|
2017-01-30 19:12:37 +01:00
|
|
|
|
2021-06-23 17:33:19 +02:00
|
|
|
let for_vars ~loc x =
|
|
|
|
|
let x = x.id_str in
|
|
|
|
|
mk_id ~loc (x ^ "'index"), mk_id ~loc (x ^ "'list")
|
2017-01-29 15:52:12 +01:00
|
|
|
|
2017-03-17 17:04:23 +01:00
|
|
|
let rec has_stmt p = function
|
|
|
|
|
| Dstmt s -> p s || begin match s.stmt_desc with
|
2022-09-07 14:44:02 +02:00
|
|
|
| Sbreak | Scontinue | Sreturn _ | Sassign _ | Slabel _ | Spass _
|
|
|
|
|
| Seval _ | Sset _ | Sblock _ | Sassert _ | Swhile _ | Scall_lemma _
|
|
|
|
|
-> false
|
2017-03-17 17:04:23 +01:00
|
|
|
| Sif (_, bl1, bl2) -> has_stmtl p bl1 || has_stmtl p bl2
|
|
|
|
|
| Sfor (_, _, _, bl) -> has_stmtl p bl end
|
|
|
|
|
| _ -> false
|
|
|
|
|
and has_stmtl p bl = List.exists (has_stmt p) bl
|
|
|
|
|
|
|
|
|
|
let rec expr_has_call id e = match e.Py_ast.expr_desc with
|
|
|
|
|
| Enone | Ebool _ | Eint _ | Estring _ | Py_ast.Eident _ -> false
|
|
|
|
|
| Emake (e1, e2) | Eget (e1, e2) | Ebinop (_, e1, e2) ->
|
|
|
|
|
expr_has_call id e1 || expr_has_call id e2
|
2022-09-07 14:44:02 +02:00
|
|
|
| Econd(c,e1,e2) -> expr_has_call id c || expr_has_call id e1 || expr_has_call id e2
|
2017-03-17 17:04:23 +01:00
|
|
|
| Eunop (_, e1) -> expr_has_call id e1
|
2021-06-23 17:33:19 +02:00
|
|
|
| Edot (e, f, el) -> id.id_str = f.id_str || List.exists (expr_has_call id) (e::el)
|
2017-03-17 17:04:23 +01:00
|
|
|
| Ecall (f, el) -> id.id_str = f.id_str || List.exists (expr_has_call id) el
|
|
|
|
|
| Elist el -> List.exists (expr_has_call id) el
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Etuple el -> List.exists (expr_has_call id) el
|
2017-03-17 17:04:23 +01:00
|
|
|
|
|
|
|
|
let rec stmt_has_call id s = match s.stmt_desc with
|
2022-09-07 14:44:02 +02:00
|
|
|
| Sbreak | Scontinue | Slabel _ | Sassert _ | Spass _ -> false
|
2017-03-17 17:04:23 +01:00
|
|
|
| Sreturn e | Sassign (_, e) | Seval e -> expr_has_call id e
|
2021-06-23 17:33:19 +02:00
|
|
|
| Sblock s -> block_has_call id s
|
2022-09-07 14:44:02 +02:00
|
|
|
| Scall_lemma (f, _) -> id.id_str = f.id_str
|
2017-03-17 17:04:23 +01:00
|
|
|
| Sset (e1, e2, e3) ->
|
|
|
|
|
expr_has_call id e1 || expr_has_call id e2 || expr_has_call id e3
|
|
|
|
|
| Sif (e, s1, s2) -> expr_has_call id e || block_has_call id s1 || block_has_call id s2
|
2017-04-14 17:45:25 +02:00
|
|
|
| Sfor (_, e, _, s) | Swhile (e, _, _, s) -> expr_has_call id e || block_has_call id s
|
2017-03-17 17:04:23 +01:00
|
|
|
and block_has_call id = has_stmtl (stmt_has_call id)
|
2017-01-31 16:02:44 +01:00
|
|
|
|
2022-09-07 14:44:02 +02:00
|
|
|
let rec is_list (e: Py_ast.expr) =
|
|
|
|
|
match e.Py_ast.expr_desc with
|
|
|
|
|
| Py_ast.Ecall (f, _) when f.id_str = "slice" -> true
|
|
|
|
|
| Py_ast.Ebinop (Py_ast.Badd, e, _) -> is_list e
|
2022-11-14 14:54:14 +01:00
|
|
|
| Py_ast.Edot (_, m, _) -> m.id_str = "copy"
|
|
|
|
|
| Py_ast.Elist _ | Py_ast.Emake _ -> true
|
2022-09-07 14:44:02 +02:00
|
|
|
| _ -> false
|
|
|
|
|
|
2017-01-29 15:52:12 +01:00
|
|
|
let rec expr env {Py_ast.expr_loc = loc; Py_ast.expr_desc = d } = match d with
|
|
|
|
|
| Py_ast.Enone ->
|
|
|
|
|
mk_unit ~loc
|
|
|
|
|
| Py_ast.Ebool b ->
|
|
|
|
|
mk_expr ~loc (if b then Etrue else Efalse)
|
|
|
|
|
| Py_ast.Eint s ->
|
2017-11-23 19:17:25 +01:00
|
|
|
constant_s ~loc s
|
2017-01-29 15:52:12 +01:00
|
|
|
| Py_ast.Estring _s ->
|
2017-01-31 14:35:51 +01:00
|
|
|
mk_unit ~loc (*FIXME*)
|
2017-01-29 15:52:12 +01:00
|
|
|
| Py_ast.Eident id ->
|
2017-01-30 19:12:37 +01:00
|
|
|
if not (Mstr.mem id.id_str env.vars) then
|
2017-01-29 15:52:12 +01:00
|
|
|
Loc.errorm ~loc "unbound variable %s" id.id_str;
|
2019-07-06 14:54:56 +02:00
|
|
|
mk_expr ~loc (Eident (Qident id))
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Econd (c, e1, e2) ->
|
|
|
|
|
let c = expr env c and e1 = expr env e1 and e2 = expr env e2 in
|
|
|
|
|
mk_expr ~loc (Eif(c,e1,e2))
|
2017-01-29 15:52:12 +01:00
|
|
|
| Py_ast.Ebinop (op, e1, e2) ->
|
2022-09-07 14:44:02 +02:00
|
|
|
let isl = is_list e1 in
|
2017-01-29 15:52:12 +01:00
|
|
|
let e1 = expr env e1 in
|
|
|
|
|
let e2 = expr env e2 in
|
|
|
|
|
mk_expr ~loc (match op with
|
2017-04-14 17:45:25 +02:00
|
|
|
| Py_ast.Band -> Eand (e1, e2)
|
|
|
|
|
| Py_ast.Bor -> Eor (e1, e2)
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Badd when isl ->
|
|
|
|
|
let id = mk_id ~loc "add_list" in
|
|
|
|
|
Eidapp (Qident id, [e1; e2])
|
2020-06-24 22:19:17 +02:00
|
|
|
| Py_ast.Badd -> Eidapp (infix ~loc "+", [e1; e2])
|
|
|
|
|
| Py_ast.Bsub -> Eidapp (infix ~loc "-", [e1; e2])
|
|
|
|
|
| Py_ast.Bmul -> Eidapp (infix ~loc "*", [e1; e2])
|
2017-04-25 17:02:29 +02:00
|
|
|
| Py_ast.Bdiv -> Eidapp (infix ~loc "//", [e1; e2])
|
2020-06-24 22:19:17 +02:00
|
|
|
| Py_ast.Bmod -> Eidapp (infix ~loc "%", [e1; e2])
|
|
|
|
|
| Py_ast.Beq -> Einnfix (e1, id_infix ~loc "=", e2)
|
|
|
|
|
| Py_ast.Bneq -> Einnfix (e1, id_infix ~loc "<>", e2)
|
|
|
|
|
| Py_ast.Blt -> Einnfix (e1, id_infix ~loc "<", e2)
|
|
|
|
|
| Py_ast.Ble -> Einnfix (e1, id_infix ~loc "<=", e2)
|
|
|
|
|
| Py_ast.Bgt -> Einnfix (e1, id_infix ~loc ">", e2)
|
|
|
|
|
| Py_ast.Bge -> Einnfix (e1, id_infix ~loc ">=", e2)
|
2017-01-29 15:52:12 +01:00
|
|
|
)
|
|
|
|
|
| Py_ast.Eunop (Py_ast.Uneg, e) ->
|
|
|
|
|
mk_expr ~loc (Eidapp (prefix ~loc "-", [expr env e]))
|
|
|
|
|
| Py_ast.Eunop (Py_ast.Unot, e) ->
|
2020-06-24 22:19:17 +02:00
|
|
|
mk_expr ~loc (Enot (expr env e))
|
2021-06-23 17:33:19 +02:00
|
|
|
|
|
|
|
|
| Py_ast.Edot (e, f, el) ->
|
|
|
|
|
let el = List.map (expr env) (e::el) in
|
|
|
|
|
let id = Qdot (Qident (mk_id ~loc "Python"), f) in
|
|
|
|
|
mk_expr ~loc (Eidapp (id, el))
|
|
|
|
|
|
|
|
|
|
| Py_ast.Ecall ({id_str="slice"} as id, [e1;e2;e3]) ->
|
|
|
|
|
|
|
|
|
|
let zero = expr env ({Py_ast.expr_loc = loc; Py_ast.expr_desc = Eint "0"}) in
|
|
|
|
|
let e1' = mk_id ~loc "e1'" in
|
|
|
|
|
let e1_var = mk_var ~loc e1' in
|
|
|
|
|
|
|
|
|
|
let len = mk_expr ~loc (Eidapp (Qident (mk_id ~loc "len"), [e1_var])) in
|
|
|
|
|
|
|
|
|
|
let e2, e3 = match e2, e3 with
|
|
|
|
|
| {Py_ast.expr_desc=Py_ast.Enone}, {Py_ast.expr_desc=Py_ast.Enone} -> zero, len
|
|
|
|
|
| _ , {Py_ast.expr_desc=Py_ast.Enone} -> expr env e2, len
|
|
|
|
|
| {Py_ast.expr_desc=Py_ast.Enone}, _ -> zero, expr env e3
|
|
|
|
|
| _ , _ -> expr env e2, expr env e3
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let id = Qdot (Qident (mk_id ~loc "Python"), id) in
|
|
|
|
|
|
|
|
|
|
mk_expr ~loc (Elet (e1', false, Expr.RKnone, expr env e1,
|
|
|
|
|
mk_expr ~loc (Eidapp (id, [e1_var;e2;e3]))
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
| Py_ast.Ecall ({id_str="range"} as id, els) when List.length els < 4 ->
|
|
|
|
|
let zero = {Py_ast.expr_loc = loc; Py_ast.expr_desc = Eint "0"} in
|
|
|
|
|
let from_to_step, id = match els with
|
|
|
|
|
| [e] -> [zero; e], id
|
|
|
|
|
| [e1;e2] -> [e1; e2], id
|
|
|
|
|
| [e1;e2;e3] -> [e1; e2; e3], mk_id ~loc "range3"
|
|
|
|
|
| _ -> assert false
|
|
|
|
|
in
|
|
|
|
|
let el = List.map (expr env) from_to_step in
|
|
|
|
|
mk_expr ~loc (Eidapp (Qident id, el))
|
|
|
|
|
|
2017-01-31 18:53:35 +01:00
|
|
|
| Py_ast.Ecall ({id_str="print"}, el) ->
|
|
|
|
|
let eval res e =
|
2017-04-14 17:45:25 +02:00
|
|
|
mk_expr ~loc (Elet (mk_id ~loc "_", false, Expr.RKnone, expr env e, res)) in
|
2017-01-31 18:53:35 +01:00
|
|
|
List.fold_left eval (mk_unit ~loc) el
|
2017-01-30 07:57:19 +01:00
|
|
|
| Py_ast.Ecall (id, el) ->
|
2019-07-06 12:09:08 +02:00
|
|
|
let el = if el = [] then [mk_unit ~loc] else List.map (expr env) el in
|
|
|
|
|
mk_expr ~loc (Eidapp (Qident id, el))
|
2017-01-30 22:53:30 +01:00
|
|
|
| Py_ast.Emake (e1, e2) -> (* [e1]*e2 *)
|
|
|
|
|
array_make ~loc (expr env e2) (expr env e1)
|
|
|
|
|
| Py_ast.Elist [] ->
|
2021-06-23 17:33:19 +02:00
|
|
|
array_empty ~loc
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Elist (e :: el) ->
|
|
|
|
|
let n = 1 + List.length el in
|
2017-11-07 10:27:15 +01:00
|
|
|
let n = constant ~loc n in
|
2022-09-07 14:44:02 +02:00
|
|
|
let e = expr env e in
|
2017-01-30 22:53:30 +01:00
|
|
|
let id = mk_id ~loc "new array" in
|
2022-09-07 14:44:02 +02:00
|
|
|
mk_expr ~loc (Elet (id, false, Expr.RKnone, array_make ~loc n e,
|
|
|
|
|
let i = ref 0 in
|
2017-01-30 22:53:30 +01:00
|
|
|
let init seq e =
|
2017-11-07 10:27:15 +01:00
|
|
|
incr i; let i = constant ~loc !i in
|
2017-01-30 22:53:30 +01:00
|
|
|
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))
|
2017-01-30 07:57:19 +01:00
|
|
|
| Py_ast.Eget (e1, e2) ->
|
2018-07-07 16:13:29 +02:00
|
|
|
mk_expr ~loc (Eidapp (get_op ~loc, [expr env e1; expr env e2]))
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Etuple el -> mk_expr ~loc (Etuple (List.map (expr env) el))
|
2017-01-29 15:52:12 +01:00
|
|
|
|
2017-03-17 17:04:23 +01:00
|
|
|
let no_params ~loc = [loc, None, false, Some (PTtuple [])]
|
|
|
|
|
|
2021-06-23 17:33:19 +02:00
|
|
|
let mk_for_params exps loc env =
|
|
|
|
|
|
|
|
|
|
let mk_op1 op ub = mk_expr ~loc (Eidapp (infix ~loc op, [expr env ub; constant ~loc 1])) in
|
|
|
|
|
let mk_minus1 ub = mk_op1 "-" ub in
|
|
|
|
|
let mk_plus1 ub = mk_op1 "+" ub in
|
|
|
|
|
|
|
|
|
|
match exps with
|
|
|
|
|
| [e1] ->
|
|
|
|
|
let zero = {Py_ast.expr_loc = loc; Py_ast.expr_desc = Eint "0"} in
|
|
|
|
|
expr env zero, mk_minus1 e1, Expr.To
|
|
|
|
|
| [e1;e2] ->
|
|
|
|
|
expr env e1, mk_minus1 e2, Expr.To
|
|
|
|
|
| [e1;e2;_] ->
|
|
|
|
|
begin match is_const exps with
|
|
|
|
|
| 1 -> expr env e1, mk_minus1 e2, Expr.To
|
|
|
|
|
| -1 -> expr env e1, mk_plus1 e2, Expr.DownTo
|
|
|
|
|
| _ -> assert false
|
|
|
|
|
end
|
|
|
|
|
| _ -> assert false
|
|
|
|
|
|
2022-09-07 14:44:02 +02:00
|
|
|
let rec new_vars env (e: Py_ast.expr) =
|
|
|
|
|
match e.Py_ast.expr_desc with
|
|
|
|
|
| Py_ast.Eident id ->
|
|
|
|
|
if Mstr.mem id.id_str env.vars then [] else [id]
|
|
|
|
|
| Py_ast.Etuple el ->
|
|
|
|
|
List.sort_uniq compare (List.concat (List.map (new_vars env) el))
|
|
|
|
|
| _ -> []
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
|
(r1,..)..(rn,..) := e1,...em
|
|
|
|
|
==> match e1,...em with (r'1,..)..(r'n,..) ->
|
|
|
|
|
r1 := r'1; .. let ri := r'i in ...
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
let rec build_pat1 (e1: Py_ast.expr) =
|
|
|
|
|
let loc = e1.Py_ast.expr_loc in
|
|
|
|
|
match e1.Py_ast.expr_desc with
|
|
|
|
|
| Py_ast.Etuple el1 ->
|
|
|
|
|
mk_pat ~loc (Ptuple (List.map build_pat1 el1))
|
|
|
|
|
| Py_ast.Eident id ->
|
|
|
|
|
mk_pat ~loc:id.id_loc (Pvar (mk_prime id))
|
|
|
|
|
| _ ->
|
|
|
|
|
let id = mk_id ~loc "_" in
|
|
|
|
|
mk_pat ~loc (Pvar (mk_prime_n id))
|
|
|
|
|
|
|
|
|
|
let rec build_pat2 (e1: Py_ast.expr) (e2: expr) =
|
|
|
|
|
let loc = e1.Py_ast.expr_loc in
|
|
|
|
|
match e1.Py_ast.expr_desc, e2.expr_desc with
|
|
|
|
|
| Py_ast.Etuple el1, Etuple el2 ->
|
|
|
|
|
if List.length el1 = List.length el2 then
|
|
|
|
|
mk_pat ~loc (Ptuple (List.map2 build_pat2 el1 el2))
|
|
|
|
|
else
|
|
|
|
|
Loc.errorm ~loc "illegal assignment"
|
|
|
|
|
| Py_ast.Etuple el1, _ ->
|
|
|
|
|
mk_pat ~loc (Ptuple (List.map build_pat1 el1))
|
|
|
|
|
| Py_ast.Eident id, _ ->
|
|
|
|
|
mk_pat ~loc:id.id_loc (Pvar (mk_prime id))
|
|
|
|
|
| _ ->
|
|
|
|
|
let id = mk_id ~loc "_" in
|
|
|
|
|
mk_pat ~loc:id.id_loc (Pvar (mk_prime_n id))
|
|
|
|
|
|
|
|
|
|
let rec flatten_updates (e: Py_ast.expr) (p: pattern) =
|
|
|
|
|
match e.Py_ast.expr_desc, p.pat_desc with
|
|
|
|
|
| Py_ast.Etuple le, Ptuple lp -> List.concat (List.map2 flatten_updates le lp)
|
|
|
|
|
| _, Pvar _ -> [e, p]
|
|
|
|
|
| _ -> failwith "flatten_updates"
|
|
|
|
|
|
|
|
|
|
let rec gen_updates env lp cnt =
|
|
|
|
|
match lp with
|
|
|
|
|
| [] -> cnt
|
|
|
|
|
| ({ Py_ast.expr_desc = Py_ast.Eident id },
|
|
|
|
|
{ pat_desc = Pvar id'; pat_loc = loc }) :: lp'
|
|
|
|
|
when Mstr.mem id.id_str env.vars ->
|
|
|
|
|
let a = mk_expr ~loc (Eassign [mk_lref ~loc id, None, mk_var ~loc id']) in
|
|
|
|
|
mk_expr ~loc (Esequence (a, gen_updates env lp' cnt))
|
|
|
|
|
| ({ Py_ast.expr_desc = Py_ast.Eident id},
|
|
|
|
|
{ pat_desc = Pvar id'; pat_loc = loc }) :: lp' ->
|
|
|
|
|
mk_expr ~loc
|
|
|
|
|
(Elet (set_ref id, false, Expr.RKnone, mk_ref ~loc (mk_var ~loc id'),
|
|
|
|
|
gen_updates env lp' cnt))
|
|
|
|
|
| ({ Py_ast.expr_desc = Eget (e1,e2) },
|
|
|
|
|
{ pat_desc = Pvar id'; pat_loc = loc }) :: lp' ->
|
|
|
|
|
let a =
|
|
|
|
|
array_set ~loc:e1.Py_ast.expr_loc (expr env e1) (expr env e2) (mk_var ~loc id') in
|
|
|
|
|
mk_expr ~loc (Esequence (a, gen_updates env lp' cnt))
|
|
|
|
|
| (e,_) :: _ ->
|
|
|
|
|
Loc.errorm ~loc:e.Py_ast.expr_loc "invalid lhs in assignment"
|
|
|
|
|
|
|
|
|
|
let rec stmt env {Py_ast.stmt_loc = loc; Py_ast.stmt_desc = d } =
|
2017-01-29 15:52:12 +01:00
|
|
|
match d with
|
2021-06-23 17:33:19 +02:00
|
|
|
| Py_ast.Sblock s ->
|
2022-09-07 14:44:02 +02:00
|
|
|
block env ~loc s
|
2017-01-29 15:52:12 +01:00
|
|
|
| Py_ast.Seval e ->
|
2021-06-23 17:33:19 +02:00
|
|
|
let id = mk_id ~loc "_'" in
|
|
|
|
|
mk_expr ~loc (Elet (id, false, Expr.RKnone, expr env e, mk_unit ~loc))
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Scall_lemma (f, lt) ->
|
|
|
|
|
let id = mk_id ~loc "_'" in
|
|
|
|
|
let call = Eidapp (Qident f, List.map mk_pure lt) in
|
|
|
|
|
mk_expr ~loc
|
|
|
|
|
(Elet (id, false, Expr.RKnone, mk_expr ~loc call, mk_unit ~loc))
|
2017-01-29 15:52:12 +01:00
|
|
|
| Py_ast.Sif (e, s1, s2) ->
|
2017-01-30 09:08:52 +01:00
|
|
|
mk_expr ~loc (Eif (expr env e, block env ~loc s1, block env ~loc s2))
|
2017-01-31 20:52:16 +01:00
|
|
|
| Py_ast.Sreturn e ->
|
2024-10-25 10:15:47 +02:00
|
|
|
mk_expr ~loc (Eraise (Qident (mk_id ~loc Ptree_helpers.return_id), Some (expr env e)))
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Sassign (lhs, e) ->
|
|
|
|
|
(*
|
|
|
|
|
r1,...rn = e1,...en ==>
|
|
|
|
|
match e1,... en with r1',... rn' -> r1:=r1'; ... rn := rn'
|
|
|
|
|
*)
|
|
|
|
|
let e = expr env e in
|
|
|
|
|
let p = build_pat2 lhs e in
|
|
|
|
|
let lp = flatten_updates lhs p in
|
|
|
|
|
let u = gen_updates env lp (mk_unit ~loc) in
|
|
|
|
|
mk_expr ~loc (Ematch (e, [p, u], []))
|
|
|
|
|
|
2017-01-30 09:52:35 +01:00
|
|
|
| Py_ast.Sset (e1, e2, e3) ->
|
2017-01-30 22:53:30 +01:00
|
|
|
array_set ~loc (expr env e1) (expr env e2) (expr env e3)
|
2017-01-30 13:50:18 +01:00
|
|
|
| Py_ast.Sassert (k, t) ->
|
2019-07-06 14:54:56 +02:00
|
|
|
mk_expr ~loc (Eassert (k, t))
|
2017-04-14 17:45:25 +02:00
|
|
|
| Py_ast.Swhile (e, inv, var, s) ->
|
2024-10-25 10:15:47 +02:00
|
|
|
let id_b = mk_id ~loc Ptree_helpers.break_id in
|
|
|
|
|
let id_c = mk_id ~loc Ptree_helpers.continue_id in
|
2021-06-23 17:33:19 +02:00
|
|
|
let body = block env ~loc s in
|
|
|
|
|
let body = mk_expr ~loc (Eoptexn (id_c, Ity.MaskVisible, body)) in
|
|
|
|
|
let loop = mk_expr ~loc (Ewhile (expr env e, inv, var, body)) in
|
|
|
|
|
mk_expr ~loc (Eoptexn (id_b, Ity.MaskVisible, loop))
|
2017-01-31 16:02:44 +01:00
|
|
|
| Py_ast.Sbreak ->
|
2024-10-25 10:15:47 +02:00
|
|
|
mk_expr ~loc (Eraise (Qident (mk_id ~loc Ptree_helpers.break_id), None))
|
2021-06-23 17:33:19 +02:00
|
|
|
| Py_ast.Scontinue ->
|
2024-10-25 10:15:47 +02:00
|
|
|
mk_expr ~loc (Eraise (Qident (mk_id ~loc Ptree_helpers.continue_id), None))
|
2017-01-31 22:23:15 +01:00
|
|
|
| Py_ast.Slabel _ ->
|
|
|
|
|
mk_unit ~loc (* ignore lonely marks *)
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Spass (ty, sp) ->
|
|
|
|
|
mk_expr ~loc
|
|
|
|
|
(Eany ([], Expr.RKnone, ty, mk_pat ~loc Pwild, Ity.MaskVisible, sp))
|
|
|
|
|
(* make a special case for
|
|
|
|
|
for id in range(e1, [e2, e3]) *)
|
2021-06-23 17:33:19 +02:00
|
|
|
| Py_ast.Sfor (id, {Py_ast.expr_desc=Ecall ({id_str="range"}, exps)},
|
|
|
|
|
inv, body)
|
2022-09-07 14:44:02 +02:00
|
|
|
when (List.length exps = 3 && (let c = is_const exps in c = -1 || c = 1)) ->
|
2021-06-23 17:33:19 +02:00
|
|
|
let lb, ub, direction = mk_for_params exps loc env in
|
|
|
|
|
let body = block ~loc (add_var env id) body in
|
2022-09-07 14:44:02 +02:00
|
|
|
let body =
|
2024-10-25 10:15:47 +02:00
|
|
|
mk_expr ~loc (Eoptexn (mk_id ~loc Ptree_helpers.continue_id, Ity.MaskVisible, body)) in
|
2021-06-23 17:33:19 +02:00
|
|
|
let body = mk_expr ~loc (Elet (set_ref id, false, Expr.RKnone,
|
|
|
|
|
mk_ref ~loc (mk_var ~loc id), body)) in
|
|
|
|
|
let loop = mk_expr ~loc (Efor (id, lb, direction, ub, inv, body)) in
|
2024-10-25 10:15:47 +02:00
|
|
|
mk_expr ~loc (Eoptexn (mk_id ~loc Ptree_helpers.break_id, Ity.MaskVisible, loop))
|
2021-06-23 17:33:19 +02:00
|
|
|
|
|
|
|
|
| Py_ast.Sfor (id, {Py_ast.expr_desc=Ecall ({id_str="range"}, exps)},
|
|
|
|
|
inv, body)
|
2022-09-07 14:44:02 +02:00
|
|
|
when (List.length exps < 3) ->
|
2021-06-23 17:33:19 +02:00
|
|
|
let lb, ub, direction = mk_for_params exps loc env in
|
|
|
|
|
let body = block ~loc (add_var env id) body in
|
2022-09-07 14:44:02 +02:00
|
|
|
let body =
|
2024-10-25 10:15:47 +02:00
|
|
|
mk_expr ~loc (Eoptexn (mk_id ~loc Ptree_helpers.continue_id, Ity.MaskVisible, body)) in
|
2021-06-23 17:33:19 +02:00
|
|
|
let body = mk_expr ~loc (Elet (set_ref id, false, Expr.RKnone,
|
|
|
|
|
mk_ref ~loc (mk_var ~loc id), body)) in
|
|
|
|
|
let loop = mk_expr ~loc (Efor (id, lb, direction, ub, inv, body)) in
|
2024-10-25 10:15:47 +02:00
|
|
|
mk_expr ~loc (Eoptexn (mk_id ~loc Ptree_helpers.break_id, Ity.MaskVisible, loop))
|
2017-02-02 21:52:15 +01:00
|
|
|
(* otherwise, translate
|
|
|
|
|
for id in e:
|
|
|
|
|
#@ invariant inv
|
|
|
|
|
body
|
|
|
|
|
to
|
2017-01-30 19:12:37 +01:00
|
|
|
let l = e in
|
2021-06-23 17:33:19 +02:00
|
|
|
for i'index = 0 to len(l)-1 do
|
|
|
|
|
invariant { I }
|
|
|
|
|
let id = ref l[i'index] in
|
2017-02-02 21:52:15 +01:00
|
|
|
body
|
2017-01-30 19:12:37 +01:00
|
|
|
done
|
|
|
|
|
*)
|
2017-02-02 21:52:15 +01:00
|
|
|
| Py_ast.Sfor (id, e, inv, body) ->
|
2017-01-30 19:12:37 +01:00
|
|
|
let e = expr env e in
|
2021-06-23 17:33:19 +02:00
|
|
|
let i, l = for_vars ~loc id in
|
2017-11-07 10:27:15 +01:00
|
|
|
let lb = constant ~loc 0 in
|
2017-01-30 19:12:37 +01:00
|
|
|
let lenl = mk_expr ~loc (Eidapp (len ~loc, [mk_var ~loc l])) in
|
2017-11-07 10:27:15 +01:00
|
|
|
let ub = mk_expr ~loc (Eidapp (infix ~loc "-", [lenl; constant ~loc 1])) in
|
2021-06-23 17:33:19 +02:00
|
|
|
let li = mk_expr ~loc (Eidapp (get_op ~loc, [mk_var ~loc l; mk_var ~loc i])) in
|
|
|
|
|
let body = block ~loc (add_var env id) body in
|
2024-10-25 10:15:47 +02:00
|
|
|
let body = mk_expr ~loc (Eoptexn (mk_id ~loc Ptree_helpers.continue_id, Ity.MaskVisible, body)) in
|
2021-06-23 17:33:19 +02:00
|
|
|
let body = mk_expr ~loc (Elet (set_ref id, false, Expr.RKnone,
|
|
|
|
|
mk_ref ~loc li, body)) in
|
|
|
|
|
let loop = mk_expr ~loc (Efor (i, lb, Expr.To, ub, inv, body)) in
|
|
|
|
|
let loop = mk_expr ~loc (Elet (l, false, Expr.RKnone, e, loop)) in
|
2024-10-25 10:15:47 +02:00
|
|
|
mk_expr ~loc (Eoptexn (mk_id ~loc Ptree_helpers.break_id, Ity.MaskVisible, loop))
|
2017-01-29 15:52:12 +01:00
|
|
|
|
2017-02-01 13:48:49 +01:00
|
|
|
and block env ~loc = function
|
2017-01-29 15:52:12 +01:00
|
|
|
| [] ->
|
|
|
|
|
mk_unit ~loc
|
2017-03-17 17:04:23 +01:00
|
|
|
| Dstmt { stmt_loc = loc; stmt_desc = Slabel id } :: sl ->
|
2018-06-01 21:03:01 +02:00
|
|
|
mk_expr ~loc (Elabel (id, block env ~loc sl))
|
2022-09-07 14:44:02 +02:00
|
|
|
| Dstmt { Py_ast.stmt_loc=loc; stmt_desc = Py_ast.Sassign (lhs, e) } :: sl ->
|
|
|
|
|
let ids = new_vars env lhs in
|
|
|
|
|
let env' = List.fold_left add_var env ids in
|
|
|
|
|
let e = expr env e in
|
|
|
|
|
let p = build_pat2 lhs e in
|
|
|
|
|
let lp = flatten_updates lhs p in
|
|
|
|
|
let u = gen_updates env lp (block env' ~loc sl) in
|
|
|
|
|
mk_expr ~loc (Ematch (e, [p, u], []))
|
2017-03-17 17:04:23 +01:00
|
|
|
| Dstmt ({ Py_ast.stmt_loc = loc } as s) :: sl ->
|
2017-01-30 09:08:52 +01:00
|
|
|
let s = stmt env s in
|
2017-01-31 20:52:16 +01:00
|
|
|
if sl = [] then s else mk_expr ~loc (Esequence (s, block env ~loc sl))
|
2022-09-07 14:44:02 +02:00
|
|
|
| Ddef (id, idl, ty, sp, bl, fct) :: sl ->
|
2017-04-24 15:43:45 +02:00
|
|
|
(* f(x1,...,xn): body ==>
|
|
|
|
|
let f x1 ... xn =
|
|
|
|
|
let x1 = ref x1 in ... let xn = ref xn in
|
|
|
|
|
try body with Return x -> x *)
|
2022-09-08 10:13:53 +02:00
|
|
|
let param (id, ty) = id.id_loc, Some id, false, ty in
|
2017-04-24 15:43:45 +02:00
|
|
|
let params = if idl = [] then no_params ~loc else List.map param idl in
|
2019-09-18 17:24:19 +02:00
|
|
|
let p = mk_pat ~loc Pwild in
|
2022-09-07 14:44:02 +02:00
|
|
|
let is_rec = block_has_call id bl in
|
|
|
|
|
let s = block env ~loc sl in
|
2022-09-08 10:13:53 +02:00
|
|
|
(match bl with
|
|
|
|
|
| [Py_ast.Dstmt {stmt_desc=Py_ast.Sreturn e}] when fct ->
|
|
|
|
|
let env' = List.fold_left add_param empty_env idl in
|
|
|
|
|
let e = expr env' e in
|
|
|
|
|
let d =
|
|
|
|
|
if is_rec then
|
|
|
|
|
Drec ([id,false,Expr.RKfunc,params,ty,p,Ity.MaskVisible,sp,e])
|
|
|
|
|
else
|
|
|
|
|
let e = Efun (params, ty, p, Ity.MaskVisible, sp, e) in
|
|
|
|
|
Dlet (id, false, Expr.RKfunc, mk_expr ~loc e) in
|
|
|
|
|
Typing.add_decl id.id_loc d;
|
|
|
|
|
s
|
|
|
|
|
| _ ->
|
|
|
|
|
let env' = List.fold_left add_param env idl in
|
|
|
|
|
let body = block env' ~loc:id.id_loc bl in
|
|
|
|
|
let body =
|
|
|
|
|
let loc = id.id_loc in
|
2024-10-25 10:15:47 +02:00
|
|
|
let id = mk_id ~loc Ptree_helpers.return_id in
|
2022-09-08 10:13:53 +02:00
|
|
|
{ body with expr_desc = Eoptexn (id, Ity.MaskVisible, body) } in
|
|
|
|
|
let local bl (id, _) =
|
|
|
|
|
let loc = id.id_loc in
|
|
|
|
|
let ref = mk_ref ~loc (mk_var ~loc id) in
|
|
|
|
|
mk_expr ~loc (Elet (set_ref id, false, Expr.RKnone, ref, bl)) in
|
|
|
|
|
let body = List.fold_left local body idl in
|
|
|
|
|
let kind = if fct then Expr.RKlocal else Expr.RKnone in
|
|
|
|
|
let e =
|
|
|
|
|
if is_rec then
|
|
|
|
|
Erec ([id, false, kind, params, ty, p, Ity.MaskVisible, sp, body], s)
|
|
|
|
|
else
|
|
|
|
|
let e = Efun (params, ty, p, Ity.MaskVisible, sp, body) in
|
|
|
|
|
Elet (id, false, kind, mk_expr ~loc e, s)
|
|
|
|
|
in
|
|
|
|
|
mk_expr ~loc e)
|
2019-06-18 17:10:56 +02:00
|
|
|
| (Py_ast.Dimport _ | Py_ast.Dlogic _) :: sl ->
|
2022-09-08 10:13:53 +02:00
|
|
|
block env ~loc sl
|
|
|
|
|
| Py_ast.Dconst (id, e) :: sl ->
|
|
|
|
|
let e = expr env e in
|
|
|
|
|
let d = Dlet (id, false, Expr.RKfunc, e) in
|
|
|
|
|
Typing.add_decl id.id_loc d;
|
|
|
|
|
let e = Elet (id, false, Expr.RKnone, e,
|
|
|
|
|
block ~loc (add_var env id) sl) in
|
|
|
|
|
mk_expr ~loc e
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Dprop (pk, id, t) :: sl ->
|
2022-09-08 10:13:53 +02:00
|
|
|
Typing.add_decl id.id_loc (Dprop (pk, id, t));
|
|
|
|
|
block env ~loc sl
|
2017-02-02 21:52:15 +01:00
|
|
|
|
2021-09-24 16:12:45 +02:00
|
|
|
let logic_param (id, ty) =
|
2021-09-28 14:36:47 +02:00
|
|
|
id.id_loc, Some id, false, ty
|
2017-03-17 17:04:23 +01:00
|
|
|
|
2017-04-24 15:43:45 +02:00
|
|
|
let logic = function
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Dlogic (id, idl, ty, None, def) ->
|
2017-03-17 17:04:23 +01:00
|
|
|
let d = { ld_loc = id.id_loc;
|
|
|
|
|
ld_ident = id;
|
|
|
|
|
ld_params = List.map logic_param idl;
|
2021-09-28 14:36:47 +02:00
|
|
|
ld_type = ty;
|
2021-09-30 10:43:02 +02:00
|
|
|
ld_def = def } in
|
2017-04-24 15:43:45 +02:00
|
|
|
Typing.add_decl id.id_loc (Dlogic [d])
|
2022-09-07 14:44:02 +02:00
|
|
|
| Py_ast.Dlogic (id, idl, Some ty, Some var, Some def) ->
|
|
|
|
|
let loc = id.id_loc in
|
|
|
|
|
let p = mk_pat ~loc (Pvar id) in
|
|
|
|
|
let s = { Ptree_helpers.empty_spec with sp_variant = [var,None] } in
|
|
|
|
|
let e = mk_expr ~loc (Epure def) in
|
|
|
|
|
let pl = List.map (fun (id,ty) -> loc,Some id,false,Some ty) idl in
|
|
|
|
|
let dr =
|
|
|
|
|
Drec ([id, true, Expr.RKfunc, pl, Some ty, p, Ity.MaskVisible, s, e]) in
|
|
|
|
|
Typing.add_decl id.id_loc dr
|
|
|
|
|
| Py_ast.Dlogic (id, idl, None, _, def) ->
|
|
|
|
|
let d = { ld_loc = id.id_loc;
|
|
|
|
|
ld_ident = id;
|
|
|
|
|
ld_params = List.map logic_param idl;
|
|
|
|
|
ld_type = None;
|
|
|
|
|
ld_def = def } in
|
|
|
|
|
Typing.add_decl id.id_loc (Dlogic [d])
|
2017-03-17 17:04:23 +01:00
|
|
|
| _ -> ()
|
|
|
|
|
|
2017-04-24 15:43:45 +02:00
|
|
|
let translate ~loc dl =
|
|
|
|
|
List.iter logic dl;
|
|
|
|
|
let bl = block empty_env ~loc dl in
|
2019-09-18 17:24:19 +02:00
|
|
|
let p = mk_pat ~loc Pwild in
|
|
|
|
|
let fd = Efun (no_params ~loc, None, p, Ity.MaskVisible, empty_spec, bl) in
|
2017-04-24 15:43:45 +02:00
|
|
|
let main = Dlet (mk_id ~loc "main", false, Expr.RKnone, mk_expr ~loc fd) in
|
|
|
|
|
Typing.add_decl loc main
|
2017-01-29 15:52:12 +01:00
|
|
|
|
2017-01-29 13:02:04 +01:00
|
|
|
let read_channel env path file c =
|
2019-04-12 09:34:59 +02:00
|
|
|
let f : Py_ast.file = Py_lexer.parse file c in
|
2017-01-29 13:02:04 +01:00
|
|
|
Debug.dprintf debug "%s parsed successfully.@." file;
|
2022-09-22 14:47:16 +02:00
|
|
|
let loc = Loc.user_position file 0 0 0 0 in
|
2017-01-29 13:02:04 +01:00
|
|
|
let file = Filename.basename file in
|
|
|
|
|
let file = Filename.chop_extension file in
|
2017-04-05 14:22:24 +02:00
|
|
|
let name = Strings.capitalize file in
|
2017-01-29 13:02:04 +01:00
|
|
|
Debug.dprintf debug "building module %s.@." name;
|
2017-04-24 15:43:45 +02:00
|
|
|
Typing.open_file env path;
|
|
|
|
|
Typing.open_module (mk_id ~loc name);
|
2017-01-29 15:52:12 +01:00
|
|
|
let use_import (f, m) =
|
2017-04-24 15:43:45 +02:00
|
|
|
let m = mk_id ~loc m in
|
2019-07-26 13:26:59 +02:00
|
|
|
let qid = Qdot (Qident (mk_id ~loc f), m) in
|
|
|
|
|
let decl = Ptree.Duseimport(loc,false,[(qid,None)]) in
|
|
|
|
|
Typing.add_decl loc decl in
|
2017-01-30 07:57:19 +01:00
|
|
|
List.iter use_import
|
2017-01-30 19:12:37 +01:00
|
|
|
["int", "Int"; "ref", "Refint"; "python", "Python"];
|
2017-04-24 15:43:45 +02:00
|
|
|
translate ~loc f;
|
|
|
|
|
Typing.close_module loc;
|
|
|
|
|
let mm = Typing.close_file () in
|
2017-01-29 13:02:04 +01:00
|
|
|
if path = [] && Debug.test_flag debug then begin
|
2025-04-28 11:24:55 +02:00
|
|
|
let add_m _ m modm = Ident.Mid.add (Pmodule.mod_name m) m modm in
|
2017-04-24 15:43:45 +02:00
|
|
|
let print_m _ m = Pmodule.print_module Format.err_formatter m in
|
|
|
|
|
Ident.Mid.iter print_m (Mstr.fold add_m mm Ident.Mid.empty)
|
2017-01-29 13:02:04 +01:00
|
|
|
end;
|
2017-04-24 15:43:45 +02:00
|
|
|
mm
|
2017-01-29 13:02:04 +01:00
|
|
|
|
|
|
|
|
let () =
|
|
|
|
|
Env.register_format mlw_language "python" ["py"] read_channel
|
|
|
|
|
~desc:"mini-Python format"
|
2019-10-04 15:51:14 +02:00
|
|
|
|
|
|
|
|
(* Python pretty-printer, to print tasks with a little bit
|
|
|
|
|
of Python syntax *)
|
2019-09-24 17:23:21 +02:00
|
|
|
|
2019-09-25 17:39:52 +02:00
|
|
|
open Term
|
2019-09-26 15:23:34 +02:00
|
|
|
open Format
|
|
|
|
|
open Pretty
|
|
|
|
|
|
|
|
|
|
(* python print_binop *)
|
|
|
|
|
let print_binop ~asym fmt = function
|
2021-09-10 14:11:14 +02:00
|
|
|
| Tand when asym -> pp_print_string fmt "&&"
|
|
|
|
|
| Tor when asym -> pp_print_string fmt "||"
|
|
|
|
|
| Tand -> pp_print_string fmt "and"
|
|
|
|
|
| Tor -> pp_print_string fmt "or"
|
|
|
|
|
| Timplies -> pp_print_string fmt "->"
|
|
|
|
|
| Tiff -> pp_print_string fmt "<->"
|
2019-09-25 17:39:52 +02:00
|
|
|
|
2019-09-23 15:58:34 +02:00
|
|
|
(* Register the transformations functions *)
|
|
|
|
|
let rec python_ext_printer print_any fmt a =
|
|
|
|
|
match a with
|
2019-09-26 15:23:34 +02:00
|
|
|
| Pp_term (t, pri) ->
|
2019-09-25 17:39:52 +02:00
|
|
|
begin match t.t_node with
|
|
|
|
|
| Tapp (ls, [t1; t2]) when ls_equal ls ps_equ ->
|
2019-09-25 17:23:49 +02:00
|
|
|
(* == *)
|
2019-09-26 15:23:34 +02:00
|
|
|
fprintf fmt (protect_on (pri > 0) "@[%a == %a@]")
|
|
|
|
|
(python_ext_printer print_any) (Pp_term (t1, 0))
|
|
|
|
|
(python_ext_printer print_any) (Pp_term (t2, 0))
|
2019-09-25 17:39:52 +02:00
|
|
|
| Tnot {t_node = Tapp (ls, [t1; t2]) } when ls_equal ls ps_equ ->
|
|
|
|
|
(* != *)
|
2019-09-26 15:23:34 +02:00
|
|
|
fprintf fmt (protect_on (pri > 0) "@[%a != %a@]")
|
|
|
|
|
(python_ext_printer print_any) (Pp_term (t1, 0))
|
|
|
|
|
(python_ext_printer print_any) (Pp_term (t2, 0))
|
|
|
|
|
| Tbinop (b, f1, f2) ->
|
|
|
|
|
(* and, or *)
|
|
|
|
|
let asym = Ident.Sattr.mem asym_split f1.t_attrs in
|
|
|
|
|
let p = prio_binop b in
|
|
|
|
|
fprintf fmt (protect_on (pri > p) "@[%a %a@ %a@]")
|
|
|
|
|
(python_ext_printer print_any) (Pp_term (f1, (p + 1)))
|
|
|
|
|
(print_binop ~asym) b
|
|
|
|
|
(python_ext_printer print_any) (Pp_term (f2, p))
|
2019-09-23 15:58:34 +02:00
|
|
|
| _ -> print_any fmt a
|
|
|
|
|
end
|
|
|
|
|
| _ -> print_any fmt a
|
|
|
|
|
|
ada_terms: Add task printer, transformation with args parser for Ada
This is inspired from the python printer/parser, the changes are:
- and, or, and then, or else are now supported instead of /\, \/, &&, ||
- different (LTGT) is now '/=' instead of '<>'
- allowing A'Last, A'First using "name" attributes
- allowing the notation "for all i in A .. B => stuff"
- allowing syntax for arrays as A(I) using new attributes "syntax" (also
the reason why we need to pass a name table to the parser)
- some constants are printed as "(cst:type)" (This is not real Ada syntax
and should probably be replaced by "type'(cst)"
This also adds a test at tests/ada_terms/print_test.adb
This adds new cases in any_pp: note that all these cases are needed as we
cannot use the legacyprinter for calls to, for instance, print_ls.
This would have the disadvantage that, when printed twice (reload), idents
gets reprinted which would change their disambiguation number (break at
every reload).
Also, pass the task to the printer in order to be able to detect which
lsymbols are used in record fields definitions.
Parser edition with respect to the Why3 parser:
- Removing qualification (not usable in transformation anyway)
- QUOTE disallowed in ident: still allowing it for type variable
- the ada parser uses a naming table during the parsing phase. The naming
table does not influence the parsing but is used to generate different
trees depending on the names recognized. It is useful to distinct a
function from an array in application as the syntax is the same.
Note that the naming_table is passed with a reference: we may want to
improve this in the future (no other known solution to the author of this
message).
New attributes appears:
- [@syntax:array:] followed by name of the getter function to be used:
this is used to know which function should be used as getter for this type
during the parsing.
- [@syntax:getter:] followed by its own name: this is used to know during
the printing if the function should be removed from the display to
simplify the notation. The name is checked in case attributes of a
specific ident are derived or copied to another one.
Add README with some changes in to be changed syntax
2019-11-25 11:57:11 +01:00
|
|
|
let () = Itp_server.add_registered_lang "python" (fun _ -> python_ext_printer)
|
2019-09-23 15:58:34 +02:00
|
|
|
|
2019-09-24 16:29:39 +02:00
|
|
|
let () = Args_wrapper.set_argument_parsing_functions "python"
|
2019-09-23 15:58:34 +02:00
|
|
|
~parse_term:(fun _ lb -> Py_lexer.parse_term lb)
|
|
|
|
|
~parse_term_list:(fun _ lb -> Py_lexer.parse_term_list lb)
|
|
|
|
|
~parse_list_ident:(fun lb -> Py_lexer.parse_list_ident lb)
|
|
|
|
|
(* TODO for qualids, add a similar funciton *)
|
|
|
|
|
~parse_qualid:(fun lb -> Lexer.parse_qualid lb)
|
|
|
|
|
~parse_list_qualid:(fun lb -> Lexer.parse_list_qualid lb)
|