Commit bfc3c223 authored by Jean-Christophe Filliâtre's avatar Jean-Christophe Filliâtre

merge of the branch 'modules'

parents f4a70768 8e5ef36a
......@@ -10,6 +10,7 @@ why.conf
*.cmo
*.cmi
*.cmxs
*.annot
\#*\#
# /
......
......@@ -283,8 +283,8 @@ install_no_local::
PGMGENERATED = src/programs/pgm_parser.mli src/programs/pgm_parser.ml \
src/programs/pgm_lexer.ml
PGM_FILES = pgm_ttree pgm_ptree pgm_parser pgm_lexer pgm_effect \
pgm_env pgm_typing pgm_wp pgm_main
PGM_FILES = pgm_ttree pgm_ptree pgm_parser pgm_lexer \
pgm_types pgm_module pgm_wp pgm_env pgm_typing pgm_main
PGMMODULES = $(addprefix src/programs/, $(PGM_FILES))
......@@ -729,9 +729,12 @@ test: bin/why.byte plugins.byte $(TOOLS)
@for i in output_coq/*.v; do printf "coq $$i\\n" && coqc $$i ; done
testl: bin/whyml.byte
ocamlrun -bt bin/whyml.byte --debug-all tests/test-pgm-jcf.mlw
ocamlrun -bt bin/whyml.byte tests/test-pgm-jcf.mlw
ocamlrun -bt bin/whyml.byte -P alt-ergo tests/test-pgm-jcf.mlw
testl-debug: bin/whyml.byte
ocamlrun -bt bin/whyml.byte --debug-all tests/test-pgm-jcf.mlw
testl-ide: bin/whyide.opt
bin/whyide.opt tests/test-pgm-jcf.mlw
......
whybench.opt
whybench.byte
......@@ -84,7 +84,7 @@ let alt_ergo : Whyconf.config_prover =
exit 0
(* builds the environment from the [loadpath] *)
let env : Env.env = Env.create_env (Lexer.retrieve (Whyconf.loadpath main))
let env : Env.env = Lexer.create_env (Whyconf.loadpath main)
(* loading the Alt-Ergo driver *)
let alt_ergo_driver : Driver.driver = Driver.load_driver env alt_ergo.Whyconf.driver
......
......@@ -29,8 +29,8 @@
;; Note: comment font-lock is guaranteed by suitable syntax entries
;; '("(\\*\\([^*)]\\([^*]\\|\\*[^)]\\)*\\)?\\*)" . font-lock-comment-face)
'("{\\([^}]*\\)}" . font-lock-type-face)
`(,(why-regexp-opt '("use" "clone" "namespace" "import" "export" "inductive" "external" "logic" "parameter" "exception" "axiom" "lemma" "goal" "type")) . font-lock-builtin-face)
`(,(why-regexp-opt '("and" "any" "match" "let" "rec" "in" "if" "then" "else" "begin" "end" "while" "invariant" "variant" "for" "to" "downto" "do" "done" "label" "assert" "absurd" "assume" "check" "ghost" "try" "with" "theory" "uses")) . font-lock-keyword-face)
`(,(why-regexp-opt '("use" "clone" "namespace" "import" "export" "inductive" "external" "logic" "parameter" "exception" "axiom" "lemma" "goal" "type" "mutable" "model")) . font-lock-builtin-face)
`(,(why-regexp-opt '("and" "any" "match" "let" "rec" "in" "if" "then" "else" "begin" "end" "while" "invariant" "variant" "for" "to" "downto" "do" "done" "label" "assert" "absurd" "assume" "check" "ghost" "try" "with" "theory" "uses" "module")) . font-lock-keyword-face)
; `(,(why-regexp-opt '("unit" "bool" "int" "float" "prop" "array")) . font-lock-type-face)
)
"Minimal highlighting for Why mode")
......
bench.annot
whybench.annot
......@@ -51,7 +51,7 @@ let read_tools absf wc map (name,section) =
let timelimit = get_int ~default:(timelimit wc_main) section "timelimit" in
let memlimit = get_int ~default:(memlimit wc_main) section "memlimit" in
(* env *)
let env = Env.create_env (Lexer.retrieve loadpath) in
let env = Lexer.create_env loadpath in
(* transformations *)
let transforms = get_stringl ~default:[] section "transform" in
let lookup acc t = Trans.compose (Trans.lookup_transform t env) acc in
......
......@@ -303,7 +303,7 @@ let () =
in
opt_task := List.fold_left add_meta !opt_task !opt_metas;
let env = Env.create_env (Lexer.retrieve !opt_loadpath) in
let env = Lexer.create_env !opt_loadpath in
let map_prover s =
let prover = try Mstr.find s (get_provers config) with
| Not_found -> eprintf "Prover %s not found.@." s; exit 1
......
......@@ -46,7 +46,7 @@ let cprovers = Whyconf.get_provers config
let timelimit = timelimit main
let env = Env.create_env (Lexer.retrieve (loadpath main))
let env = Lexer.create_env (loadpath main)
let provers = Hashtbl.create 17
......
......@@ -22,7 +22,10 @@ open Theory
(** Environment *)
type retrieve_channel = string list -> string * in_channel
type env = {
env_ret_chan : retrieve_channel;
env_retrieve : retrieve_theory;
env_memo : (string list, theory Mnm.t) Hashtbl.t;
env_tag : Hashweak.tag;
......@@ -35,7 +38,8 @@ let create_memo () =
Hashtbl.add ht [] Mnm.empty;
ht
let create_env = let c = ref (-1) in fun retrieve -> {
let create_env = let c = ref (-1) in fun ret_chan retrieve -> {
env_ret_chan = ret_chan;
env_retrieve = retrieve;
env_memo = create_memo ();
env_tag = (incr c; Hashweak.create_tag !c) }
......@@ -70,6 +74,8 @@ let find_theory env sl s =
else try Mnm.find s (find_library env sl)
with Not_found -> raise (TheoryNotFound (sl, s))
let find_channel env = env.env_ret_chan
let env_tag env = env.env_tag
module Wenv = Hashweak.Make(struct type t = env let tag = env_tag end)
......
......@@ -27,9 +27,13 @@ val env_tag : env -> Hashweak.tag
module Wenv : Hashweak.S with type key = env
type retrieve_theory = env -> string list -> theory Mnm.t
type retrieve_channel = string list -> string * in_channel
(** retrieves a channel from a given path; a filename is also returned,
for printing purposes only *)
val create_env : retrieve_theory -> env
type retrieve_theory = env -> string list -> theory Mnm.t
val create_env : retrieve_channel -> retrieve_theory -> env
exception TheoryNotFound of string list * string
......@@ -37,6 +41,8 @@ val find_theory : env -> string list -> string -> theory
(** [find_theory e p n] finds the theory named [p.n] in environment [e]
@raise TheoryNotFound if theory not present in env [e] *)
val find_channel : env -> string list -> string * in_channel
(** Parsers *)
type read_channel = env -> string -> in_channel -> theory Mnm.t
......
......@@ -111,10 +111,10 @@ let load_config config =
let provers = get_provers config in
*)
(*
let env = Env.create_env (Lexer.retrieve main.loadpath) in
let env = Lexer.create_env main.loadpath in
*)
(* temporary sets env to empty *)
let env = Env.create_env (Lexer.retrieve []) in
let env = Lexer.create_env [] in
{ window_height = ide.ide_window_height;
window_width = ide.ide_window_width;
tree_width = ide.ide_tree_width;
......
......@@ -166,7 +166,7 @@ let source_text fname =
let gconfig =
let c = Gconfig.config in
let loadpath = (Whyconf.loadpath (get_main ())) @ List.rev !includes in
c.env <- Env.create_env (Lexer.retrieve loadpath);
c.env <- Lexer.create_env loadpath;
let provers = Whyconf.get_provers c.Gconfig.config in
c.provers <-
Util.Mstr.fold (Gconfig.get_prover_data c.env) provers Util.Mstr.empty;
......
......@@ -444,7 +444,7 @@ let do_input env drv = function
let () =
try
let env = Env.create_env (Lexer.retrieve !opt_loadpath) in
let env = Lexer.create_env !opt_loadpath in
let drv = Util.option_map (load_driver env) !opt_driver in
Queue.iter (do_input env drv) opt_queue
with e when not (Debug.test_flag Debug.stack_trace) ->
......
......@@ -50,6 +50,8 @@ and type_var = {
type_var_loc : loc option;
}
let tvsymbol_of_type_var tv = tv.tvsymbol
let rec print_dty fmt = function
| Tyvar { type_val = Some t } ->
print_dty fmt t
......@@ -58,10 +60,9 @@ let rec print_dty fmt = function
| Tyapp (s, []) ->
fprintf fmt "%s" s.ts_name.id_string
| Tyapp (s, [t]) ->
fprintf fmt "%a %s" print_dty t s.ts_name.id_string
fprintf fmt "%s %a" s.ts_name.id_string print_dty t
| Tyapp (s, l) ->
fprintf fmt "(%a) %s"
(print_list comma print_dty) l s.ts_name.id_string
fprintf fmt "%s %a" s.ts_name.id_string (print_list comma print_dty) l
let create_ty_decl_var =
let t = ref 0 in
......
......@@ -95,3 +95,6 @@ val specialize_term : loc:Ptree.loc -> type_var Htv.t -> term -> dterm
val specialize_fmla : loc:Ptree.loc -> type_var Htv.t -> fmla -> dfmla
(** exported for programs *)
val tvsymbol_of_type_var : type_var -> tvsymbol
......@@ -21,7 +21,7 @@ open Theory
(** parsing entry points *)
val retrieve : string list -> Env.retrieve_theory
val create_env : string list -> Env.env
(** creates a new typing environment for a given loadpath *)
val parse_list0_decl :
......
......@@ -271,21 +271,32 @@ and string = parse
Loc.set_file file lb;
parse_logic_file env lb
let retrieve lp env sl =
let f = List.fold_left Filename.concat "" sl ^ ".why" in
(* searches file [f] in loadpath [lp] *)
let locate_file lp f =
let fl = List.map (fun dir -> Filename.concat dir f) lp in
let file = match List.filter Sys.file_exists fl with
match List.filter Sys.file_exists fl with
| [] -> raise Not_found
| [file] -> file
| file1 :: file2 :: _ -> raise (AmbiguousPath (file1, file2))
let create_env lp =
let ret_chan sl =
let f = List.fold_left Filename.concat "" sl in
let file = locate_file lp f in
file, open_in file
in
let retrieve env sl =
let f = List.fold_left Filename.concat "" sl ^ ".why" in
let file = locate_file lp f in
let c = open_in file in
try
let tl = read_channel env file c in
close_in c;
tl
with
| e -> close_in c; raise e
in
let c = open_in file in
try
let tl = read_channel env file c in
close_in c;
tl
with
| e -> close_in c; raise e
Env.create_env ret_chan retrieve
let () = Env.register_format "why" ["why"] read_channel
}
......
......@@ -146,6 +146,9 @@ let mem_var x denv = Mstr.mem x denv.dvars
let find_var x denv = Mstr.find x denv.dvars
let add_var x ty denv = { denv with dvars = Mstr.add x ty denv.dvars }
let print_denv fmt denv =
Mstr.iter (fun x ty -> fprintf fmt "%s:%a,@ " x print_dty ty) denv.dvars
(* parsed types -> intermediate types *)
let rec qloc = function
......
......@@ -71,6 +71,10 @@ val dfmla : ?localize:bool -> denv -> Ptree.lexpr -> Denv.dfmla
val dpat : denv -> Ptree.pattern -> denv * Denv.dpattern
val dpat_list : denv -> Denv.dty -> Ptree.pattern -> denv * Denv.dpattern
val print_denv : Format.formatter -> denv -> unit
val split_qualid : Ptree.qualid -> string list * string
val string_list_of_qualid : string list -> Ptree.qualid -> string list
val qloc : Ptree.qualid -> Loc.position
val ts_tuple : int -> Ty.tysymbol
......
o refs -> mutable types
o loadpath: how to retrieve program files? (cannot use "env")
o what about pervasives old, at, label, exn, unit = (), lt_nat
......@@ -18,383 +18,41 @@
(**************************************************************************)
open Why
open Util
open Ident
open Theory
open Term
open Ty
module E = Pgm_effect
open Pgm_module
(* types *)
type effect = E.t
type reference = Pgm_effect.reference
type pre = Term.fmla
type post_fmla = Term.vsymbol (* result *) * Term.fmla
type exn_post_fmla = Term.vsymbol (* result *) option * Term.fmla
type post = post_fmla * (Term.lsymbol * exn_post_fmla) list
type type_v =
| Tpure of Ty.ty
| Tarrow of binder list * type_c
and type_c =
{ c_result_type : type_v;
c_effect : effect;
c_pre : pre;
c_post : post; }
and binder = Term.vsymbol * type_v
(* environments *)
type env = {
uc : theory_uc;
(***
globals : type_v Mls.t;
locals : type_v Mvs.t;
***)
globals : (lsymbol * type_v) Mstr.t;
exceptions : lsymbol Mstr.t;
ts_arrow: tysymbol;
ts_bool : tysymbol;
ts_label: tysymbol;
ts_ref: tysymbol;
ts_exn: tysymbol;
ts_unit : tysymbol;
ls_at : lsymbol;
ls_bang : lsymbol;
ls_old : lsymbol;
ls_True : lsymbol;
ls_False: lsymbol;
ls_andb : lsymbol;
ls_orb : lsymbol;
ls_notb : lsymbol;
ls_unit : lsymbol;
ls_lt : lsymbol;
ls_gt : lsymbol;
ls_le : lsymbol;
ls_ge : lsymbol;
ls_add : lsymbol;
type t = {
env : Env.env;
retrieve : retrieve_module;
memo : (string list, Pgm_module.t Mnm.t) Hashtbl.t;
}
and retrieve_module = t -> string -> in_channel -> Pgm_module.t Mnm.t
(* prelude *)
let find_ts uc = ns_find_ts (get_namespace uc)
let find_ls uc = ns_find_ls (get_namespace uc)
(* predefined lsymbols are memoized wrt the lsymbol for type "ref" *)
let memo_ls f =
let h = Hts.create 17 in
fun uc ->
let ts_ref = find_ts uc ["ref"] in
try Hts.find h ts_ref
with Not_found -> let s = f uc ts_ref in Hts.add h ts_ref s; s
(* logic ref ('a) : 'a ref *)
let ls_ref = memo_ls
(fun _uc ts_ref ->
let a = ty_var (create_tvsymbol (id_fresh "a")) in
create_lsymbol (id_fresh "ref") [a] (Some (ty_app ts_ref [a])))
(* logic (:=)('a ref, 'a) : unit *)
let ls_assign = memo_ls
(fun uc ts_ref ->
let ty_unit = ty_app (find_ts uc ["unit"]) [] in
let a = ty_var (create_tvsymbol (id_fresh "a")) in
create_lsymbol (id_fresh "infix :=") [ty_app ts_ref [a]; a] (Some ty_unit))
let ls_Exit = memo_ls
(fun uc _ ->
let ty_exn = ty_app (find_ts uc ["exn"]) [] in
create_lsymbol (id_fresh "%Exit") [] (Some ty_exn))
let v_result ty = create_vsymbol (id_fresh "result") ty
let get_env penv = penv.env
let exn_v_result ls = match ls.ls_args with
| [] -> None
| [ty] -> Some (v_result ty)
| _ -> assert false
let add_type_v_ref uc m =
let ts_ref = find_ts uc ["ref"] in
let a = ty_var (create_tvsymbol (id_fresh "a")) in
let x = create_vsymbol (id_fresh "x") a in
let ty = ty_app ts_ref [a] in
let result = v_result ty in
let q = f_equ (t_app (find_ls uc ["prefix !"]) [t_var result] a) (t_var x) in
let c = { c_result_type = Tpure ty;
c_effect = Pgm_effect.empty;
c_pre = f_true;
c_post = (result, q), []; } in
let v = Tarrow ([x, Tpure a], c) in
Mstr.add "ref" (ls_ref uc, v) m
let add_type_v_assign uc m =
let ts_ref = find_ts uc ["ref"] in
let a = ty_var (create_tvsymbol (id_fresh "a")) in
let a_ref = ty_app ts_ref [a] in
let x = create_vsymbol (id_fresh "x") a_ref in
let y = create_vsymbol (id_fresh "y") a in
let ty = ty_app (find_ts uc ["unit"]) [] in
let result = v_result ty in
let q = f_equ (t_app (find_ls uc ["prefix !"]) [t_var x] a) (t_var y) in
let c = { c_result_type = Tpure ty;
c_effect = E.add_write (E.Rlocal x) E.empty;
c_pre = f_true;
c_post = (result, q), []; } in
let v = Tarrow ([x, Tpure a_ref; y, Tpure a], c) in
Mstr.add "infix :=" (ls_assign uc, v) m
let empty_env uc = {
uc = uc;
globals = add_type_v_ref uc (add_type_v_assign uc Mstr.empty);
exceptions = Mstr.add "%Exit" (ls_Exit uc) Mstr.empty;
(* types *)
ts_arrow = find_ts uc ["arrow"];
ts_bool = find_ts uc ["bool"];
ts_label = find_ts uc ["label"];
ts_ref = find_ts uc ["ref"];
ts_exn = find_ts uc ["exn"];
ts_unit = find_ts uc ["tuple0"];
(* functions *)
ls_at = find_ls uc ["at"];
ls_bang = find_ls uc ["prefix !"];
ls_old = find_ls uc ["old"];
ls_True = find_ls uc ["True"];
ls_False = find_ls uc ["False"];
ls_andb = find_ls uc ["andb"];
ls_orb = find_ls uc ["orb"];
ls_notb = find_ls uc ["notb"];
ls_unit = find_ls uc ["Tuple0"];
ls_lt = find_ls uc ["infix <"];
ls_gt = find_ls uc ["infix >"];
ls_le = find_ls uc ["infix <="];
ls_ge = find_ls uc ["infix >="];
ls_add = find_ls uc ["infix +"];
let create env retrieve = {
env = env;
retrieve = retrieve;
memo = Hashtbl.create 17;
}
let make_arrow_type env tyl ty =
let arrow ty1 ty2 = Ty.ty_app env.ts_arrow [ty1; ty2] in
List.fold_right arrow tyl ty
let rec uncurry_type = function
| Tpure ty ->
[], ty
| Tarrow (bl, c) ->
let tyl1 = List.map (fun (v,_) -> v.vs_ty) bl in
let tyl2, ty = uncurry_type c.c_result_type in
tyl1 @ tyl2, ty (* TODO: improve? *)
let purify env v =
let tyl, ty = uncurry_type v in
make_arrow_type env tyl ty
(* parsing LOGIC strings using functions from src/parser/
requires proper relocation *)
let reloc loc lb =
lb.Lexing.lex_curr_p <- loc;
lb.Lexing.lex_abs_pos <- loc.Lexing.pos_cnum + 1
let parse_string f loc s =
let lb = Lexing.from_string s in
reloc loc lb;
f lb
let logic_lexpr ((pos, _), s) =
parse_string Lexer.parse_lexpr pos s
let logic_decls ((loc, _), s) e env =
let parse = Lexer.parse_list0_decl e Mnm.empty env.uc in
{ env with uc = parse_string parse loc s }
(* addition *)
let add_global id tyv env =
let tyl, ty = uncurry_type tyv in
let s = create_lsymbol id tyl (Some ty) in
s, { env with globals = Mstr.add s.ls_name.id_string (s, tyv) env.globals }
let add_decl d env =
{ env with uc = Typing.with_tuples add_decl env.uc d }
let add_exception id ty env =
let tyl = match ty with None -> [] | Some ty -> [ty] in
let s = create_lsymbol id tyl (Some (ty_app env.ts_exn [])) in
s, { env with exceptions = Mstr.add s.ls_name.id_string s env.exceptions }
(* misc. functions *)
let post_map f ((v, q), ql) =
(v, f q), List.map (fun (e,(v,q)) -> e, (v, f q)) ql
let type_c_of_type_v env = function
| Tarrow ([], c) ->
c
| v ->
let ty = purify env v in
{ c_result_type = v;
c_effect = Pgm_effect.empty;
c_pre = f_true;
c_post = (v_result ty, f_true), []; }
let rec subst_var ts s vs =
let ty' = ty_inst ts vs.vs_ty in
if ty_equal ty' vs.vs_ty then
s, vs
else
let vs' = create_vsymbol (id_clone vs.vs_name) ty' in
Mvs.add vs (t_var vs') s, vs'
and subst_post ts s ((v, q), ql) =
let vq = let s, v = subst_var ts s v in v, f_ty_subst ts s q in
let handler (e, (v, q)) = match v with
| None -> e, (v, f_ty_subst ts s q)
| Some v -> let s, v = subst_var ts s v in e, (Some v, f_ty_subst ts s q)
in
vq, List.map handler ql
let rec subst_type_c ef ts s c =
{ c_result_type = subst_type_v ef ts s c.c_result_type;
c_effect = E.subst ef c.c_effect;
c_pre = f_ty_subst ts s c.c_pre;
c_post = subst_post ts s c.c_post; }
and subst_type_v ef ts s = function
| Tpure ty ->
Tpure (ty_inst ts ty)
| Tarrow (bl, c) ->
let s, bl = Util.map_fold_left (binder ef ts) s bl in
Tarrow (bl, subst_type_c ef ts s c)
and binder ef ts s (vs, v) =
let v = subst_type_v ef ts s v in
let s, vs = subst_var ts s vs in
s, (vs, v)
let tpure ty = Tpure ty
let tarrow bl c = match bl with
| [] ->
invalid_arg "tarrow"
| _ ->
let rename (e, s) (vs, v) =
let vs' = create_vsymbol (id_clone vs.vs_name) vs.vs_ty in
let v' = subst_type_v e Mtv.empty s v in
let e' = Mvs.add vs (E.Rlocal vs') e in
let s' = Mvs.add vs (t_var vs') s in
(e', s'), (vs', v')
in
let (e, s), bl' = Util.map_fold_left rename (Mvs.empty, Mvs.empty) bl in
Tarrow (bl', subst_type_c e Mtv.empty s c)
let subst1 vs1 t2 = Mvs.add vs1 t2 Mvs.empty
let apply_type_v env v vs = match v with
| Tarrow ((x, tyx) :: bl, c) ->
let ts = ty_match Mtv.empty (purify env tyx) vs.vs_ty in
let c = type_c_of_type_v env (Tarrow (bl, c)) in
subst_type_c Mvs.empty ts (subst1 x (t_var vs)) c
| Tarrow ([], _) | Tpure _ ->
assert false
let apply_type_v_ref env v r = match r, v with
| E.Rlocal vs as r, Tarrow ((x, tyx) :: bl, c) ->
let ts = ty_match Mtv.empty (purify env tyx) vs.vs_ty in
let c = type_c_of_type_v env (Tarrow (bl, c)) in
let ef = Mvs.add x r Mvs.empty in
subst_type_c ef ts (subst1 x (t_var vs)) c
| E.Rglobal ls as r, Tarrow ((x, tyx) :: bl, c) ->
let ty = match ls.ls_value with None -> assert false | Some ty -> ty in
let ts = ty_match Mtv.empty (purify env tyx) ty in
let c = type_c_of_type_v env (Tarrow (bl, c)) in
let ef = Mvs.add x r Mvs.empty in
subst_type_c ef ts (subst1 x (t_app ls [] ty)) c
| _ ->
assert false
let occur_formula r f = match r with
| E.Rlocal vs -> f_occurs_single vs f
| E.Rglobal ls -> f_s_any (fun _ -> false) (ls_equal ls) f
let rec occur_type_v r = function
| Tpure _ ->
false
| Tarrow (bl, c) ->
occur_arrow r bl c
and occur_arrow r bl c = match bl with
| [] ->
occur_type_c r c
| (vs, v) :: bl ->
occur_type_v r v ||
not (E.ref_equal r (E.Rlocal vs)) && occur_arrow r bl c
and occur_type_c r c =
occur_type_v r c.c_result_type ||
occur_formula r c.c_pre ||
E.occur r c.c_effect ||
occur_post r c.c_post
and occur_post r ((_, q), ql) =
occur_formula r q ||
List.exists (fun (_, (_, qe)) -> occur_formula r qe) ql
let rec eq_type_v v1 v2 = match v1, v2 with
| Tpure ty1, Tpure ty2 ->
ty_equal ty1 ty2
| Tarrow _, Tarrow _ ->
false (* TODO? *)
| _ ->
assert false
let t_True env =
t_app env.ls_True [] (ty_app env.ts_bool [])
let type_v_unit env =
Tpure (ty_app env.ts_unit [])
(* pretty-printers *)
open Pp