summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJon French2018-12-28 15:12:00 +0000
committerJon French2018-12-28 15:12:00 +0000
commitb59fba68e535f39b6285ec7f4f693107b6e34148 (patch)
tree3135513ac4b23f96b41f3d521990f1ce91206c99 /src
parent9f6a95882e1d3d057bcb83d098ba1b63925a4d1f (diff)
parent2c887e7d01331d3165120695594eac7a2650ec03 (diff)
Merge branch 'sail2' into rmem_interpreter
Diffstat (limited to 'src')
-rw-r--r--src/_tags5
-rw-r--r--src/anf.ml53
-rw-r--r--src/anf.mli2
-rw-r--r--src/ast_util.ml688
-rw-r--r--src/ast_util.mli96
-rw-r--r--src/bytecode_interpreter.ml162
-rw-r--r--src/bytecode_util.ml173
-rw-r--r--src/c_backend.ml892
-rw-r--r--src/c_backend.mli14
-rw-r--r--src/cgen_backend.ml77
-rw-r--r--src/constant_fold.ml7
-rw-r--r--src/constraint.ml254
-rw-r--r--src/constraint.mli34
-rw-r--r--src/extra_pervasives.ml2
-rw-r--r--src/gen_lib/sail2_string.lem4
-rw-r--r--src/initial_check.ml1545
-rw-r--r--src/initial_check.mli7
-rw-r--r--src/interpreter.ml16
-rw-r--r--src/isail.ml173
-rw-r--r--src/latex.ml426
-rw-r--r--src/lem_interp/sail2_instr_kinds.lem7
-rw-r--r--src/lexer.mll16
-rw-r--r--src/monomorphise.ml383
-rw-r--r--src/nl_flow.ml118
-rw-r--r--src/nl_flow.mli60
-rw-r--r--src/ocaml_backend.ml80
-rw-r--r--src/parse_ast.ml125
-rw-r--r--src/parser.mly248
-rw-r--r--src/pattern_completeness.ml6
-rw-r--r--src/pretty_print_common.ml128
-rw-r--r--src/pretty_print_coq.ml664
-rw-r--r--src/pretty_print_lem.ml182
-rw-r--r--src/pretty_print_sail.ml238
-rw-r--r--src/process_file.ml54
-rw-r--r--src/process_file.mli1
-rw-r--r--src/profile.ml91
-rw-r--r--src/reporting.ml (renamed from src/reporting_basic.ml)70
-rw-r--r--src/reporting.mli (renamed from src/reporting_basic.mli)5
-rw-r--r--src/return_analysis.ml182
-rw-r--r--src/rewriter.ml73
-rw-r--r--src/rewriter.mli28
-rw-r--r--src/rewrites.ml556
-rw-r--r--src/sail.ml58
-rw-r--r--src/sail_lib.ml56
-rw-r--r--src/scattered.ml141
-rw-r--r--src/spec_analysis.ml93
-rw-r--r--src/specialize.ml99
-rw-r--r--src/specialize.mli4
-rw-r--r--src/state.ml46
-rw-r--r--src/type_check.ml2092
-rw-r--r--src/type_check.mli74
-rw-r--r--src/type_error.ml213
-rw-r--r--src/util.ml19
-rw-r--r--src/util.mli12
-rw-r--r--src/value.ml53
55 files changed, 6409 insertions, 4496 deletions
diff --git a/src/_tags b/src/_tags
index 6b2bf716..cdc8fbb5 100644
--- a/src/_tags
+++ b/src/_tags
@@ -1,11 +1,12 @@
true: -traverse, debug, use_menhir
<**/*.ml>: bin_annot, annot
-<sail.{byte,native}>: package(zarith), package(linksem), package(lem), package(base64), use_pprint
-<isail.{byte,native}>: package(zarith), package(linenoise), package(linksem), package(lem), package(base64), use_pprint
+<sail.{byte,native}>: package(zarith), package(linksem), package(lem), package(omd), package(base64), use_pprint
+<isail.{byte,native}>: package(zarith), package(linenoise), package(linksem), package(lem), package(omd), package(base64), use_pprint
<isail.ml>: package(linenoise)
<elf_loader.ml>: package(linksem)
+<latex.ml>: package(omd)
<**/*.m{l,li}>: package(lem), package(base64)
<gen_lib>: include
diff --git a/src/anf.ml b/src/anf.ml
index 0f98caff..915ab738 100644
--- a/src/anf.ml
+++ b/src/anf.ml
@@ -57,9 +57,6 @@ open PPrint
module Big_int = Nat_big_num
-let anf_error ?loc:(l=Parse_ast.Unknown) message =
- raise (Reporting_basic.err_general l ("\nANF translation: " ^ message))
-
(**************************************************************************)
(* 1. Conversion to A-normal form (ANF) *)
(**************************************************************************)
@@ -130,7 +127,7 @@ and 'a aval =
| AV_list of ('a aval) list * 'a
| AV_vector of ('a aval) list * 'a
| AV_record of ('a aval) Bindings.t * 'a
- | AV_C_fragment of fragment * 'a
+ | AV_C_fragment of fragment * 'a * ctyp
(* Renaming variables in ANF expressions *)
@@ -186,7 +183,7 @@ let rec aval_rename from_id to_id = function
| AV_list (avals, typ) -> AV_list (List.map (aval_rename from_id to_id) avals, typ)
| AV_vector (avals, typ) -> AV_vector (List.map (aval_rename from_id to_id) avals, typ)
| AV_record (avals, typ) -> AV_record (Bindings.map (aval_rename from_id to_id) avals, typ)
- | AV_C_fragment (fragment, typ) -> AV_C_fragment (frag_rename from_id to_id fragment, typ)
+ | AV_C_fragment (fragment, typ, ctyp) -> AV_C_fragment (frag_rename from_id to_id fragment, typ, ctyp)
let rec aexp_rename from_id to_id (AE_aux (aexp, env, l)) =
let recur = aexp_rename from_id to_id in
@@ -426,7 +423,8 @@ and pp_aval = function
| AV_id (id, lvar) -> pp_lvar lvar (pp_id id)
| AV_tuple avals -> parens (separate_map (comma ^^ space) pp_aval avals)
| AV_ref (id, lvar) -> string "ref" ^^ space ^^ pp_lvar lvar (pp_id id)
- | AV_C_fragment (frag, typ) -> pp_annot typ (string (string_of_fragment frag |> Util.cyan |> Util.clear))
+ | AV_C_fragment (frag, typ, ctyp) ->
+ pp_annot typ (string ("(" ^ string_of_ctyp ctyp ^ ")" ^ string_of_fragment frag |> Util.cyan |> Util.clear))
| AV_vector (avals, typ) ->
pp_annot typ (string "[" ^^ separate_map (comma ^^ space) pp_aval avals ^^ string "]")
| AV_list (avals, typ) ->
@@ -453,23 +451,26 @@ let rec split_block l = function
| exp :: exps ->
let exps, last = split_block l exps in
exp :: exps, last
- | [] -> anf_error ~loc:l "empty block"
+ | [] ->
+ raise (Reporting.err_unreachable l __POS__ "empty block found when converting to ANF")
let rec anf_pat ?global:(global=false) (P_aux (p_aux, annot) as pat) =
let mk_apat aux = AP_aux (aux, env_of_annot annot, fst annot) in
match p_aux with
- | P_id id when global -> mk_apat (AP_global (id, pat_typ_of pat))
- | P_id id -> mk_apat (AP_id (id, pat_typ_of pat))
- | P_wild -> mk_apat (AP_wild (pat_typ_of pat))
+ | P_id id when global -> mk_apat (AP_global (id, typ_of_pat pat))
+ | P_id id -> mk_apat (AP_id (id, typ_of_pat pat))
+ | P_wild -> mk_apat (AP_wild (typ_of_pat pat))
| P_tup pats -> mk_apat (AP_tup (List.map (fun pat -> anf_pat ~global:global pat) pats))
- | P_app (id, [subpat]) -> mk_apat (AP_app (id, anf_pat ~global:global subpat, pat_typ_of pat))
- | P_app (id, pats) -> mk_apat (AP_app (id, mk_apat (AP_tup (List.map (fun pat -> anf_pat ~global:global pat) pats)), pat_typ_of pat))
+ | P_app (id, [subpat]) -> mk_apat (AP_app (id, anf_pat ~global:global subpat, typ_of_pat pat))
+ | P_app (id, pats) -> mk_apat (AP_app (id, mk_apat (AP_tup (List.map (fun pat -> anf_pat ~global:global pat) pats)), typ_of_pat pat))
| P_typ (_, pat) -> anf_pat ~global:global pat
| P_var (pat, _) -> anf_pat ~global:global pat
| P_cons (hd_pat, tl_pat) -> mk_apat (AP_cons (anf_pat ~global:global hd_pat, anf_pat ~global:global tl_pat))
- | P_list pats -> List.fold_right (fun pat apat -> mk_apat (AP_cons (anf_pat ~global:global pat, apat))) pats (mk_apat (AP_nil (pat_typ_of pat)))
- | P_lit (L_aux (L_unit, _)) -> mk_apat (AP_wild (pat_typ_of pat))
- | _ -> anf_error ~loc:(fst annot) ("Could not convert pattern to ANF: " ^ string_of_pat pat)
+ | P_list pats -> List.fold_right (fun pat apat -> mk_apat (AP_cons (anf_pat ~global:global pat, apat))) pats (mk_apat (AP_nil (typ_of_pat pat)))
+ | P_lit (L_aux (L_unit, _)) -> mk_apat (AP_wild (typ_of_pat pat))
+ | _ ->
+ raise (Reporting.err_unreachable (fst annot) __POS__
+ ("Could not convert pattern to ANF: " ^ string_of_pat pat))
let rec apat_globals (AP_aux (aux, _, _)) =
match aux with
@@ -510,7 +511,7 @@ let rec anf (E_aux (e_aux, ((l, _) as exp_annot)) as exp) =
| E_lit lit -> mk_aexp (ae_lit lit (typ_of exp))
| E_block [] ->
- Util.warn (Reporting_basic.loc_to_string l
+ Util.warn (Reporting.loc_to_string l
^ "\n\nTranslating empty block (possibly assigning to an uninitialized variable at the end of a block?)");
mk_aexp (ae_lit (L_aux (L_unit, l)) (typ_of exp))
| E_block exps ->
@@ -529,7 +530,8 @@ let rec anf (E_aux (e_aux, ((l, _) as exp_annot)) as exp) =
mk_aexp (AE_assign (id, lvar_typ (Env.lookup_id id (env_of exp)), aexp))
| E_assign (lexp, _) ->
- failwith ("Encountered complex l-expression " ^ string_of_lexp lexp ^ " when converting to ANF")
+ raise (Reporting.err_unreachable l __POS__
+ ("Encountered complex l-expression " ^ string_of_lexp lexp ^ " when converting to ANF"))
| E_loop (loop_typ, cond, exp) ->
let acond = anf cond in
@@ -567,7 +569,7 @@ let rec anf (E_aux (e_aux, ((l, _) as exp_annot)) as exp) =
let aval, wrap = to_aval (anf field_exp) in
wrap (mk_aexp (AE_field (aval, id, typ_of exp)))
- | E_record_update (exp, FES_aux (FES_Fexps (fexps, _), _)) ->
+ | E_record_update (exp, fexps) ->
let anf_fexp (FE_aux (FE_Fexp (id, exp), _)) =
let aval, wrap = to_aval (anf exp) in
(id, aval), wrap
@@ -665,7 +667,8 @@ let rec anf (E_aux (e_aux, ((l, _) as exp_annot)) as exp) =
mk_aexp (AE_let (Mutable, id, lvar_typ lvar, anf binding, anf body, typ_of exp))
| E_var (lexp, _, _) ->
- failwith ("Encountered complex l-expression " ^ string_of_lexp lexp ^ " when converting to ANF")
+ raise (Reporting.err_unreachable l __POS__
+ ("Encountered complex l-expression " ^ string_of_lexp lexp ^ " when converting to ANF"))
| E_let (LB_aux (LB_val (pat, binding), _), body) ->
anf (E_aux (E_case (binding, [Pat_aux (Pat_exp (pat, body), (Parse_ast.Unknown, empty_tannot))]), exp_annot))
@@ -676,7 +679,7 @@ let rec anf (E_aux (e_aux, ((l, _) as exp_annot)) as exp) =
let wrap = List.fold_left (fun f g x -> f (g x)) (fun x -> x) (List.map snd avals) in
wrap (mk_aexp (AE_val (AV_tuple (List.map fst avals))))
- | E_record (FES_aux (FES_Fexps (fexps, _), _)) ->
+ | E_record fexps ->
let anf_fexp (FE_aux (FE_Fexp (id, exp), _)) =
let aval, wrap = to_aval (anf exp) in
(id, aval), wrap
@@ -690,19 +693,19 @@ let rec anf (E_aux (e_aux, ((l, _) as exp_annot)) as exp) =
| E_vector_access _ | E_vector_subrange _ | E_vector_update _ | E_vector_update_subrange _ | E_vector_append _ ->
(* Should be re-written by type checker *)
- failwith "encountered raw vector operation when converting to ANF"
+ raise (Reporting.err_unreachable l __POS__ "encountered raw vector operation when converting to ANF")
| E_internal_value _ ->
(* Interpreter specific *)
- failwith "encountered E_internal_value when converting to ANF"
+ raise (Reporting.err_unreachable l __POS__ "encountered E_internal_value when converting to ANF")
| E_sizeof _ | E_constraint _ ->
(* Sizeof nodes removed by sizeof rewriting pass *)
- failwith "encountered E_sizeof or E_constraint node when converting to ANF"
+ raise (Reporting.err_unreachable l __POS__ "encountered E_sizeof or E_constraint node when converting to ANF")
| E_nondet _ ->
(* We don't compile E_nondet nodes *)
- failwith "encountered E_nondet node when converting to ANF"
+ raise (Reporting.err_unreachable l __POS__ "encountered E_nondet node when converting to ANF")
| E_internal_return _ | E_internal_plet _ ->
- failwith "encountered unexpected internal node when converting to ANF"
+ raise (Reporting.err_unreachable l __POS__ "encountered unexpected internal node when converting to ANF")
diff --git a/src/anf.mli b/src/anf.mli
index 9854b04c..5e162b7c 100644
--- a/src/anf.mli
+++ b/src/anf.mli
@@ -96,7 +96,7 @@ and 'a aval =
| AV_list of ('a aval) list * 'a
| AV_vector of ('a aval) list * 'a
| AV_record of ('a aval) Bindings.t * 'a
- | AV_C_fragment of fragment * 'a
+ | AV_C_fragment of fragment * 'a * ctyp
val gensym : unit -> id
diff --git a/src/ast_util.ml b/src/ast_util.ml
index 3d13c5c3..34dfd663 100644
--- a/src/ast_util.ml
+++ b/src/ast_util.ml
@@ -106,13 +106,13 @@ let mk_funcl id pat body = FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (pat, body),
let mk_qi_nc nc = QI_aux (QI_const nc, Parse_ast.Unknown)
-let mk_qi_id bk kid =
+let mk_qi_id k kid =
let kopt =
- KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (bk, Parse_ast.Unknown)], Parse_ast.Unknown), kid), Parse_ast.Unknown)
+ KOpt_aux (KOpt_kind (K_aux (k, Parse_ast.Unknown), kid), Parse_ast.Unknown)
in
QI_aux (QI_id kopt, Parse_ast.Unknown)
-let mk_qi_kopt kopt =QI_aux (QI_id kopt, Parse_ast.Unknown)
+let mk_qi_kopt kopt = QI_aux (QI_id kopt, Parse_ast.Unknown)
let mk_fundef funcls =
let tannot_opt = Typ_annot_opt_aux (Typ_annot_opt_none, Parse_ast.Unknown) in
@@ -126,21 +126,23 @@ let mk_letbind pat exp = LB_aux (LB_val (pat, exp), no_annot)
let mk_val_spec vs_aux =
DEF_spec (VS_aux (vs_aux, no_annot))
-let kopt_kid (KOpt_aux (kopt_aux, _)) =
- match kopt_aux with
- | KOpt_none kid | KOpt_kind (_, kid) -> kid
-
+let kopt_kid (KOpt_aux (KOpt_kind (_, kid), _)) = kid
+let kopt_kind (KOpt_aux (KOpt_kind (k, _), _)) = k
+
let is_nat_kopt = function
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_int, _)], _), _), _) -> true
- | KOpt_aux (KOpt_none _, _) -> true
+ | KOpt_aux (KOpt_kind (K_aux (K_int, _), _), _) -> true
| _ -> false
let is_order_kopt = function
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_order, _)], _), _), _) -> true
+ | KOpt_aux (KOpt_kind (K_aux (K_order, _), _), _) -> true
| _ -> false
let is_typ_kopt = function
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_type, _)], _), _), _) -> true
+ | KOpt_aux (KOpt_kind (K_aux (K_type, _), _), _) -> true
+ | _ -> false
+
+let is_bool_kopt = function
+ | KOpt_aux (KOpt_kind (K_aux (K_bool, _), _), _) -> true
| _ -> false
let string_of_kid = function
@@ -151,6 +153,27 @@ module Kid = struct
let compare kid1 kid2 = String.compare (string_of_kid kid1) (string_of_kid kid2)
end
+module Kind = struct
+ type t = kind
+ let compare (K_aux (aux1, _)) (K_aux (aux2, _)) =
+ match aux1, aux2 with
+ | K_int, K_int -> 0
+ | K_type, K_type -> 0
+ | K_order, K_order -> 0
+ | K_bool, K_bool -> 0
+ | K_int, _ -> 1 | _, K_int -> -1
+ | K_type, _ -> 1 | _, K_type -> -1
+ | K_order, _ -> 1 | _, K_order -> -1
+end
+
+module KOpt = struct
+ type t = kinded_id
+ let compare kopt1 kopt2 =
+ let lex_ord c1 c2 = if c1 = 0 then c2 else c1 in
+ lex_ord (Kid.compare (kopt_kid kopt1) (kopt_kid kopt2))
+ (Kind.compare (kopt_kind kopt1) (kopt_kind kopt2))
+end
+
module Id = struct
type t = id
let compare id1 id2 =
@@ -198,6 +221,8 @@ module Bindings = Map.Make(Id)
module IdSet = Set.Make(Id)
module KBindings = Map.Make(Kid)
module KidSet = Set.Make(Kid)
+module KOptSet = Set.Make(KOpt)
+module KOptMap = Map.Make(KOpt)
module NexpSet = Set.Make(Nexp)
module NexpMap = Map.Make(Nexp)
@@ -270,13 +295,60 @@ and nexp_simp_aux = function
end
| nexp -> nexp
+let rec constraint_simp (NC_aux (nc_aux, l)) =
+ let nc_aux = match nc_aux with
+ | NC_equal (nexp1, nexp2) ->
+ let nexp1, nexp2 = nexp_simp nexp1, nexp_simp nexp2 in
+ if nexp_identical nexp1 nexp2 then
+ NC_true
+ else
+ NC_equal (nexp1, nexp2)
+
+ | NC_and (nc1, nc2) ->
+ let nc1, nc2 = constraint_simp nc1, constraint_simp nc2 in
+ begin match nc1, nc2 with
+ | NC_aux (NC_true, _), NC_aux (nc, _) -> nc
+ | NC_aux (nc, _), NC_aux (NC_true, _) -> nc
+ | _, _ -> NC_and (nc1, nc2)
+ end
+
+ | NC_or (nc1, nc2) ->
+ let nc1, nc2 = constraint_simp nc1, constraint_simp nc2 in
+ begin match nc1, nc2 with
+ | NC_aux (NC_false, _), NC_aux (nc, _) -> nc
+ | NC_aux (nc, _), NC_aux (NC_false, _) -> nc
+ | NC_aux (NC_true, _), NC_aux (nc, _) -> NC_true
+ | NC_aux (nc, _), NC_aux (NC_true, _) -> NC_true
+ | _, _ -> NC_or (nc1, nc2)
+ end
+ | NC_bounded_ge (nexp1, nexp2) ->
+ NC_bounded_ge (nexp_simp nexp1, nexp_simp nexp2)
+ | NC_bounded_le (nexp1, nexp2) ->
+ NC_bounded_le (nexp_simp nexp1, nexp_simp nexp2)
+ | _ -> nc_aux
+ in
+ NC_aux (nc_aux, l)
+
+let rec constraint_conj (NC_aux (nc_aux, l) as nc) =
+ match nc_aux with
+ | NC_and (nc1, nc2) -> constraint_conj nc1 @ constraint_conj nc2
+ | _ -> [nc]
+
+let rec constraint_disj (NC_aux (nc_aux, l) as nc) =
+ match nc_aux with
+ | NC_or (nc1, nc2) -> constraint_disj nc1 @ constraint_disj nc2
+ | _ -> [nc]
+
let mk_typ typ = Typ_aux (typ, Parse_ast.Unknown)
-let mk_typ_arg arg = Typ_arg_aux (arg, Parse_ast.Unknown)
+let mk_typ_arg arg = A_aux (arg, Parse_ast.Unknown)
let mk_kid str = Kid_aux (Var ("'" ^ str), Parse_ast.Unknown)
let mk_infix_id str = Id_aux (DeIid str, Parse_ast.Unknown)
let mk_id_typ id = Typ_aux (Typ_id id, Parse_ast.Unknown)
+let mk_kopt kind_aux id =
+ KOpt_aux (KOpt_kind (K_aux (kind_aux, Parse_ast.Unknown), id), Parse_ast.Unknown)
+
let mk_ord ord_aux = Ord_aux (ord_aux, Parse_ast.Unknown)
let unknown_typ = mk_typ Typ_internal_unknown
@@ -286,23 +358,23 @@ let unit_typ = mk_id_typ (mk_id "unit")
let bit_typ = mk_id_typ (mk_id "bit")
let real_typ = mk_id_typ (mk_id "real")
let app_typ id args = mk_typ (Typ_app (id, args))
-let register_typ typ = mk_typ (Typ_app (mk_id "register", [mk_typ_arg (Typ_arg_typ typ)]))
+let register_typ typ = mk_typ (Typ_app (mk_id "register", [mk_typ_arg (A_typ typ)]))
let atom_typ nexp =
- mk_typ (Typ_app (mk_id "atom", [mk_typ_arg (Typ_arg_nexp (nexp_simp nexp))]))
+ mk_typ (Typ_app (mk_id "atom", [mk_typ_arg (A_nexp (nexp_simp nexp))]))
let range_typ nexp1 nexp2 =
- mk_typ (Typ_app (mk_id "range", [mk_typ_arg (Typ_arg_nexp (nexp_simp nexp1));
- mk_typ_arg (Typ_arg_nexp (nexp_simp nexp2))]))
+ mk_typ (Typ_app (mk_id "range", [mk_typ_arg (A_nexp (nexp_simp nexp1));
+ mk_typ_arg (A_nexp (nexp_simp nexp2))]))
let bool_typ = mk_id_typ (mk_id "bool")
let string_typ = mk_id_typ (mk_id "string")
-let list_typ typ = mk_typ (Typ_app (mk_id "list", [mk_typ_arg (Typ_arg_typ typ)]))
+let list_typ typ = mk_typ (Typ_app (mk_id "list", [mk_typ_arg (A_typ typ)]))
let tuple_typ typs = mk_typ (Typ_tup typs)
let function_typ arg_typs ret_typ eff = mk_typ (Typ_fn (arg_typs, ret_typ, eff))
let vector_typ n ord typ =
mk_typ (Typ_app (mk_id "vector",
- [mk_typ_arg (Typ_arg_nexp (nexp_simp n));
- mk_typ_arg (Typ_arg_order ord);
- mk_typ_arg (Typ_arg_typ typ)]))
+ [mk_typ_arg (A_nexp (nexp_simp n));
+ mk_typ_arg (A_order ord);
+ mk_typ_arg (A_typ typ)]))
let exc_typ = mk_id_typ (mk_id "exception")
@@ -324,40 +396,49 @@ let nc_lteq n1 n2 = NC_aux (NC_bounded_le (n1, n2), Parse_ast.Unknown)
let nc_gteq n1 n2 = NC_aux (NC_bounded_ge (n1, n2), Parse_ast.Unknown)
let nc_lt n1 n2 = nc_lteq (nsum n1 (nint 1)) n2
let nc_gt n1 n2 = nc_gteq n1 (nsum n2 (nint 1))
-let nc_and nc1 nc2 = mk_nc (NC_and (nc1, nc2))
let nc_or nc1 nc2 = mk_nc (NC_or (nc1, nc2))
+let nc_var kid = mk_nc (NC_var kid)
let nc_true = mk_nc NC_true
let nc_false = mk_nc NC_false
-let rec nc_negate (NC_aux (nc, l)) =
- match nc with
- | NC_bounded_ge (n1, n2) -> nc_lt n1 n2
- | NC_bounded_le (n1, n2) -> nc_gt n1 n2
- | NC_equal (n1, n2) -> nc_neq n1 n2
- | NC_not_equal (n1, n2) -> nc_eq n1 n2
- | NC_and (n1, n2) -> mk_nc (NC_or (nc_negate n1, nc_negate n2))
- | NC_or (n1, n2) -> mk_nc (NC_and (nc_negate n1, nc_negate n2))
- | NC_false -> mk_nc NC_true
- | NC_true -> mk_nc NC_false
- | NC_set (kid, []) -> nc_false
- | NC_set (kid, [int]) -> nc_neq (nvar kid) (nconstant int)
- | NC_set (kid, int :: ints) ->
- mk_nc (NC_and (nc_neq (nvar kid) (nconstant int), nc_negate (mk_nc (NC_set (kid, ints)))))
- | NC_app _ ->
- raise (Reporting_basic.err_unreachable l __POS__ "tried to negate constraint with unexpanded synonym")
+let nc_and nc1 nc2 =
+ match nc1, nc2 with
+ | _, NC_aux (NC_true, _) -> nc1
+ | NC_aux (NC_true, _), _ -> nc2
+ | _, _ -> mk_nc (NC_and (nc1, nc2))
+
+let arg_nexp ?loc:(l=Parse_ast.Unknown) n = A_aux (A_nexp n, l)
+let arg_order ?loc:(l=Parse_ast.Unknown) ord = A_aux (A_order ord, l)
+let arg_typ ?loc:(l=Parse_ast.Unknown) typ = A_aux (A_typ typ, l)
+let arg_bool ?loc:(l=Parse_ast.Unknown) nc = A_aux (A_bool nc, l)
+
+let arg_kopt (KOpt_aux (KOpt_kind (K_aux (k, _), v), l)) =
+ match k with
+ | K_int -> arg_nexp (nvar v)
+ | K_order -> arg_order (Ord_aux (Ord_var v, l))
+ | K_bool -> arg_bool (nc_var v)
+ | K_type -> arg_typ (mk_typ (Typ_var v))
+
+let nc_not nc = mk_nc (NC_app (mk_id "not", [arg_bool nc]))
let mk_typschm typq typ = TypSchm_aux (TypSchm_ts (typq, typ), Parse_ast.Unknown)
let mk_typquant qis = TypQ_aux (TypQ_tq qis, Parse_ast.Unknown)
let mk_fexp id exp = FE_aux (FE_Fexp (id, exp), no_annot)
-let mk_fexps fexps = FES_aux (FES_Fexps (fexps, false), no_annot)
let mk_effect effs =
Effect_aux (Effect_set (List.map (fun be_aux -> BE_aux (be_aux, Parse_ast.Unknown)) effs), Parse_ast.Unknown)
let no_effect = mk_effect []
+let quant_add qi typq =
+ match qi, typq with
+ | QI_aux (QI_const (NC_aux (NC_true, _)), _), _ -> typq
+ | QI_aux (QI_id _, _), TypQ_aux (TypQ_tq qis, l) -> TypQ_aux (TypQ_tq (qi :: qis), l)
+ | QI_aux (QI_const nc, _), TypQ_aux (TypQ_tq qis, l) -> TypQ_aux (TypQ_tq (qis @ [qi]), l)
+ | _, TypQ_aux (TypQ_no_forall, l) -> TypQ_aux (TypQ_tq [qi], l)
+
let quant_items : typquant -> quant_item list = function
| TypQ_aux (TypQ_tq qis, _) -> qis
| TypQ_aux (TypQ_no_forall, _) -> []
@@ -385,9 +466,19 @@ let quant_map_items f = function
| TypQ_aux (TypQ_no_forall, l) -> TypQ_aux (TypQ_no_forall, l)
| TypQ_aux (TypQ_tq qis, l) -> TypQ_aux (TypQ_tq (List.map f qis), l)
+let is_quant_kopt = function
+ | QI_aux (QI_id _, _) -> true
+ | _ -> false
+
+let is_quant_constraint = function
+ | QI_aux (QI_const _, _) -> true
+ | _ -> false
+
let unaux_nexp (Nexp_aux (nexp, _)) = nexp
let unaux_order (Ord_aux (ord, _)) = ord
let unaux_typ (Typ_aux (typ, _)) = typ
+let unaux_kind (K_aux (k, _)) = k
+let unaux_constraint (NC_aux (nc, _)) = nc
let rec map_exp_annot f (E_aux (exp, annot)) = E_aux (map_exp_annot_aux f exp, f annot)
and map_exp_annot_aux f = function
@@ -412,8 +503,8 @@ and map_exp_annot_aux f = function
| E_vector_append (exp1, exp2) -> E_vector_append (map_exp_annot f exp1, map_exp_annot f exp2)
| E_list xs -> E_list (List.map (map_exp_annot f) xs)
| E_cons (exp1, exp2) -> E_cons (map_exp_annot f exp1, map_exp_annot f exp2)
- | E_record fexps -> E_record (map_fexps_annot f fexps)
- | E_record_update (exp, fexps) -> E_record_update (map_exp_annot f exp, map_fexps_annot f fexps)
+ | E_record fexps -> E_record (List.map (map_fexp_annot f) fexps)
+ | E_record_update (exp, fexps) -> E_record_update (map_exp_annot f exp, List.map (map_fexp_annot f) fexps)
| E_field (exp, id) -> E_field (map_exp_annot f exp, id)
| E_case (exp, cases) -> E_case (map_exp_annot f exp, List.map (map_pexp_annot f) cases)
| E_try (exp, cases) -> E_try (map_exp_annot f exp, List.map (map_pexp_annot f) cases)
@@ -433,7 +524,6 @@ and map_opt_default_annot f (Def_val_aux (df, annot)) = Def_val_aux (map_opt_def
and map_opt_default_annot_aux f = function
| Def_val_empty -> Def_val_empty
| Def_val_dec exp -> Def_val_dec (map_exp_annot f exp)
-and map_fexps_annot f (FES_aux (FES_Fexps (fexps, b), annot)) = FES_aux (FES_Fexps (List.map (map_fexp_annot f) fexps, b), f annot)
and map_fexp_annot f (FE_aux (FE_Fexp (id, exp), annot)) = FE_aux (FE_Fexp (id, map_exp_annot f exp), f annot)
and map_pexp_annot f (Pat_aux (pexp, annot)) = Pat_aux (map_pexp_annot_aux f pexp, f annot)
and map_pexp_annot_aux f = function
@@ -530,8 +620,8 @@ let def_loc = function
| DEF_reg_dec (DEC_aux (_, (l, _)))
| DEF_fixity (_, _, Id_aux (_, l))
| DEF_overload (Id_aux (_, l), _) -> l
- | DEF_constraint (Id_aux (_, l), _, _) -> l
| DEF_internal_mutrec _ -> Parse_ast.Unknown
+ | DEF_pragma (_, _, l) -> l
let string_of_id = function
| Id_aux (Id v, _) -> v
@@ -576,14 +666,16 @@ let string_of_base_effect_aux = function
(*| BE_lset -> "lset"
| BE_lret -> "lret"*)
-let string_of_base_kind_aux = function
- | BK_type -> "Type"
- | BK_int -> "Int"
- | BK_order -> "Order"
+let string_of_kind_aux = function
+ | K_type -> "Type"
+ | K_int -> "Int"
+ | K_order -> "Order"
+ | K_bool -> "Bool"
-let string_of_base_kind (BK_aux (bk, _)) = string_of_base_kind_aux bk
+let string_of_kind (K_aux (k, _)) = string_of_kind_aux k
-let string_of_kind (K_aux (K_kind bks, _)) = string_of_list " -> " string_of_base_kind bks
+let string_of_kinded_id (KOpt_aux (KOpt_kind (k, kid), _)) =
+ "(" ^ string_of_kid kid ^ " : " ^ string_of_kind k ^ ")"
let string_of_base_effect = function
| BE_aux (beff, _) -> string_of_base_effect_aux beff
@@ -618,23 +710,26 @@ and string_of_typ_aux = function
| Typ_id id -> string_of_id id
| Typ_var kid -> string_of_kid kid
| Typ_tup typs -> "(" ^ string_of_list ", " string_of_typ typs ^ ")"
+ | Typ_app (id, args) when Id.compare id (mk_id "atom") = 0 -> "int(" ^ string_of_list ", " string_of_typ_arg args ^ ")"
+ | Typ_app (id, args) when Id.compare id (mk_id "atom_bool") = 0 -> "bool(" ^ string_of_list ", " string_of_typ_arg args ^ ")"
| Typ_app (id, args) -> string_of_id id ^ "(" ^ string_of_list ", " string_of_typ_arg args ^ ")"
| Typ_fn ([typ_arg], typ_ret, eff) ->
- string_of_typ typ_arg ^ " -> " ^ string_of_typ typ_ret ^ " effect " ^ string_of_effect eff
+ string_of_typ typ_arg ^ " -> " ^ string_of_typ typ_ret ^ " effect " ^ string_of_effect eff
| Typ_fn (typ_args, typ_ret, eff) ->
"(" ^ string_of_list ", " string_of_typ typ_args ^ ") -> "
^ string_of_typ typ_ret ^ " effect " ^ string_of_effect eff
| Typ_bidir (typ1, typ2) -> string_of_typ typ1 ^ " <-> " ^ string_of_typ typ2
| Typ_exist (kids, nc, typ) ->
- "{" ^ string_of_list " " string_of_kid kids ^ ", " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ ^ "}"
+ "{" ^ string_of_list " " string_of_kinded_id kids ^ ", " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ ^ "}"
and string_of_typ_arg = function
- | Typ_arg_aux (typ_arg, l) -> string_of_typ_arg_aux typ_arg
+ | A_aux (typ_arg, l) -> string_of_typ_arg_aux typ_arg
and string_of_typ_arg_aux = function
- | Typ_arg_nexp n -> string_of_nexp n
- | Typ_arg_typ typ -> string_of_typ typ
- | Typ_arg_order o -> string_of_order o
+ | A_nexp n -> string_of_nexp n
+ | A_typ typ -> string_of_typ typ
+ | A_order o -> string_of_order o
+ | A_bool nc -> string_of_n_constraint nc
and string_of_n_constraint = function
- | NC_aux (NC_equal (n1, n2), _) -> string_of_nexp n1 ^ " = " ^ string_of_nexp n2
+ | NC_aux (NC_equal (n1, n2), _) -> string_of_nexp n1 ^ " == " ^ string_of_nexp n2
| NC_aux (NC_not_equal (n1, n2), _) -> string_of_nexp n1 ^ " != " ^ string_of_nexp n2
| NC_aux (NC_bounded_ge (n1, n2), _) -> string_of_nexp n1 ^ " >= " ^ string_of_nexp n2
| NC_aux (NC_bounded_le (n1, n2), _) -> string_of_nexp n1 ^ " <= " ^ string_of_nexp n2
@@ -644,14 +739,14 @@ and string_of_n_constraint = function
"(" ^ string_of_n_constraint nc1 ^ " & " ^ string_of_n_constraint nc2 ^ ")"
| NC_aux (NC_set (kid, ns), _) ->
string_of_kid kid ^ " in {" ^ string_of_list ", " Big_int.to_string ns ^ "}"
- | NC_aux (NC_app (id, nexps), _) ->
- "where " ^ string_of_id id ^ "(" ^ Util.string_of_list ", " string_of_nexp nexps ^ ")"
+ | NC_aux (NC_app (Id_aux (DeIid op, _), [arg1; arg2]), _) ->
+ "(" ^ string_of_typ_arg arg1 ^ " " ^ op ^ " " ^ string_of_typ_arg arg2 ^ ")"
+ | NC_aux (NC_app (id, args), _) -> string_of_id id ^ "(" ^ string_of_list ", " string_of_typ_arg args ^ ")"
+ | NC_aux (NC_var v, _) -> string_of_kid v
| NC_aux (NC_true, _) -> "true"
| NC_aux (NC_false, _) -> "false"
-let string_of_kinded_id = function
- | KOpt_aux (KOpt_none kid, _) -> string_of_kid kid
- | KOpt_aux (KOpt_kind (k, kid), _) -> "(" ^ string_of_kid kid ^ " : " ^ string_of_kind k ^ ")"
+let string_of_kinded_id (KOpt_aux (KOpt_kind (k, kid), _)) = "(" ^ string_of_kid kid ^ " : " ^ string_of_kind k ^ ")"
let string_of_quant_item_aux = function
| QI_id kopt -> string_of_kinded_id kopt
@@ -724,9 +819,9 @@ let rec string_of_exp (E_aux (exp, _)) =
| E_throw exp -> "throw " ^ string_of_exp exp
| E_cons (x, xs) -> string_of_exp x ^ " :: " ^ string_of_exp xs
| E_list xs -> "[|" ^ string_of_list ", " string_of_exp xs ^ "|]"
- | E_record_update (exp, FES_aux (FES_Fexps (fexps, _), _)) ->
+ | E_record_update (exp, fexps) ->
"{ " ^ string_of_exp exp ^ " with " ^ string_of_list "; " string_of_fexp fexps ^ " }"
- | E_record (FES_aux (FES_Fexps (fexps, _), _)) ->
+ | E_record fexps ->
"{ " ^ string_of_list "; " string_of_fexp fexps ^ " }"
| E_var (lexp, binding, exp) -> "var " ^ string_of_lexp lexp ^ " = " ^ string_of_exp binding ^ " in " ^ string_of_exp exp
| E_internal_return exp -> "internal_return (" ^ string_of_exp exp ^ ")"
@@ -762,8 +857,9 @@ and string_of_pat (P_aux (pat, l)) =
| P_vector_concat pats -> string_of_list " @ " string_of_pat pats
| P_vector pats -> "[" ^ string_of_list ", " string_of_pat pats ^ "]"
| P_as (pat, id) -> "(" ^ string_of_pat pat ^ " as " ^ string_of_id id ^ ")"
+ | P_string_append [] -> "\"\""
| P_string_append pats -> string_of_list " ^ " string_of_pat pats
- | _ -> "PAT"
+ | P_record _ -> "PAT"
and string_of_mpat (MP_aux (pat, l)) =
match pat with
@@ -828,13 +924,13 @@ let id_of_fundef (FD_aux (FD_function (_, _, _, funcls), (l, _))) =
(fun (FCL_aux (FCL_Funcl (id, _), _)) id' ->
match id' with
| Some id' -> if string_of_id id' = string_of_id id then Some id'
- else raise (Reporting_basic.err_typ l
+ else raise (Reporting.err_typ l
("Function declaration expects all definitions to have the same name, "
^ string_of_id id ^ " differs from other definitions of " ^ string_of_id id'))
| None -> Some id) funcls None)
with
| Some id -> id
- | None -> raise (Reporting_basic.err_typ l "funcl list is empty")
+ | None -> raise (Reporting.err_typ l "funcl list is empty")
let id_of_type_def_aux = function
| TD_abbrev (id, _, _)
@@ -846,6 +942,13 @@ let id_of_type_def (TD_aux (td_aux, _)) = id_of_type_def_aux td_aux
let id_of_val_spec (VS_aux (VS_val_spec (_, id, _, _), _)) = id
+let id_of_dec_spec (DEC_aux (ds_aux, _)) =
+ match ds_aux with
+ | DEC_reg (_, id) -> id
+ | DEC_config (id, _, _) -> id
+ | DEC_alias (id, _) -> id
+ | DEC_typ_alias (_, id, _) -> id
+
let ids_of_def = function
| DEF_kind (KD_aux (KD_nabbrev (_, id, _, _), _)) -> IdSet.singleton id
| DEF_type td -> IdSet.singleton (id_of_type_def td)
@@ -895,8 +998,6 @@ module NC = struct
| NC_or (nc1,nc2), NC_or (nc3,nc4)
| NC_and (nc1,nc2), NC_and (nc3,nc4)
-> lex_ord compare compare nc1 nc3 nc2 nc4
- | NC_app (id1, nexps1), NC_app (id2, nexps2)
- -> lex_ord (Id.compare) (Util.compare_list Nexp.compare) id1 id2 nexps1 nexps2
| NC_true, NC_true
| NC_false, NC_false
-> 0
@@ -907,7 +1008,6 @@ module NC = struct
| NC_set _, _ -> -1 | _, NC_set _ -> 1
| NC_or _, _ -> -1 | _, NC_or _ -> 1
| NC_and _, _ -> -1 | _, NC_and _ -> 1
- | NC_app _, _ -> -1 | _, NC_app _ -> 1
| NC_true, _ -> -1 | _, NC_true -> 1
end
@@ -930,7 +1030,7 @@ module Typ = struct
| n -> n)
| Typ_tup ts1, Typ_tup ts2 -> Util.compare_list compare ts1 ts2
| Typ_exist (ks1,nc1,t1), Typ_exist (ks2,nc2,t2) ->
- (match Util.compare_list Kid.compare ks1 ks2 with
+ (match Util.compare_list KOpt.compare ks1 ks2 with
| 0 -> (match NC.compare nc1 nc2 with
| 0 -> compare t1 t2
| n -> n)
@@ -946,20 +1046,22 @@ module Typ = struct
| Typ_bidir _, _ -> -1 | _, Typ_bidir _ -> 1
| Typ_tup _, _ -> -1 | _, Typ_tup _ -> 1
| Typ_exist _, _ -> -1 | _, Typ_exist _ -> 1
- and arg_compare (Typ_arg_aux (ta1,_)) (Typ_arg_aux (ta2,_)) =
+ and arg_compare (A_aux (ta1,_)) (A_aux (ta2,_)) =
match ta1, ta2 with
- | Typ_arg_nexp n1, Typ_arg_nexp n2 -> Nexp.compare n1 n2
- | Typ_arg_typ t1, Typ_arg_typ t2 -> compare t1 t2
- | Typ_arg_order o1, Typ_arg_order o2 -> order_compare o1 o2
- | Typ_arg_nexp _, _ -> -1 | _, Typ_arg_nexp _ -> 1
- | Typ_arg_typ _, _ -> -1 | _, Typ_arg_typ _ -> 1
+ | A_nexp n1, A_nexp n2 -> Nexp.compare n1 n2
+ | A_typ t1, A_typ t2 -> compare t1 t2
+ | A_order o1, A_order o2 -> order_compare o1 o2
+ | A_bool nc1, A_bool nc2 -> NC.compare nc1 nc2
+ | A_nexp _, _ -> -1 | _, A_nexp _ -> 1
+ | A_typ _, _ -> -1 | _, A_typ _ -> 1
+ | A_order _, _ -> -1 | _, A_order _ -> 1
end
module TypMap = Map.Make(Typ)
let rec nexp_frees (Nexp_aux (nexp, l)) =
match nexp with
- | Nexp_id _ -> raise (Reporting_basic.err_typ l "Unimplemented Nexp_id in nexp_frees")
+ | Nexp_id _ -> raise (Reporting.err_typ l "Unimplemented Nexp_id in nexp_frees")
| Nexp_var kid -> KidSet.singleton kid
| Nexp_constant _ -> KidSet.empty
| Nexp_times (n1, n2) -> KidSet.union (nexp_frees n1) (nexp_frees n2)
@@ -977,7 +1079,7 @@ let rec lexp_to_exp (LEXP_aux (lexp_aux, annot) as le) =
let get_id (LEXP_aux(lexp,((l,_) as annot)) as le) = match lexp with
| LEXP_id id | LEXP_cast (_, id) -> E_aux (E_id id, annot)
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
("Unsupported sub-lexp " ^ string_of_lexp le ^ " in tuple")) in
rewrap (E_tuple (List.map get_id les))
| LEXP_vector (lexp, e) -> rewrap (E_vector_access (lexp_to_exp lexp, e))
@@ -1008,23 +1110,23 @@ let is_ref_typ (Typ_aux (typ_aux, _)) = match typ_aux with
let rec is_vector_typ = function
| Typ_aux (Typ_app (Id_aux (Id "vector",_), [_;_;_]), _) -> true
- | Typ_aux (Typ_app (Id_aux (Id "register",_), [Typ_arg_aux (Typ_arg_typ rtyp,_)]), _) ->
+ | Typ_aux (Typ_app (Id_aux (Id "register",_), [A_aux (A_typ rtyp,_)]), _) ->
is_vector_typ rtyp
| _ -> false
let typ_app_args_of = function
| Typ_aux (Typ_app (Id_aux (Id c,_), targs), l) ->
- (c, List.map (fun (Typ_arg_aux (a,_)) -> a) targs, l)
+ (c, List.map (fun (A_aux (a,_)) -> a) targs, l)
| Typ_aux (_, l) as typ ->
- raise (Reporting_basic.err_typ l
+ raise (Reporting.err_typ l
("typ_app_args_of called on non-app type " ^ string_of_typ typ))
let rec vector_typ_args_of typ = match typ_app_args_of typ with
- | ("vector", [Typ_arg_nexp len; Typ_arg_order ord; Typ_arg_typ etyp], l) ->
+ | ("vector", [A_nexp len; A_order ord; A_typ etyp], l) ->
(nexp_simp len, ord, etyp)
- | ("register", [Typ_arg_typ rtyp], _) -> vector_typ_args_of rtyp
+ | ("register", [A_typ rtyp], _) -> vector_typ_args_of rtyp
| (_, _, l) ->
- raise (Reporting_basic.err_typ l
+ raise (Reporting.err_typ l
("vector_typ_args_of called on non-vector type " ^ string_of_typ typ))
let vector_start_index typ =
@@ -1032,13 +1134,13 @@ let vector_start_index typ =
match ord with
| Ord_aux (Ord_inc, _) -> nint 0
| Ord_aux (Ord_dec, _) -> nexp_simp (nminus len (nint 1))
- | _ -> raise (Reporting_basic.err_typ (typ_loc typ) "Can't calculate start index without order")
+ | _ -> raise (Reporting.err_typ (typ_loc typ) "Can't calculate start index without order")
let is_order_inc = function
| Ord_aux (Ord_inc, _) -> true
| Ord_aux (Ord_dec, _) -> false
| Ord_aux (Ord_var _, l) ->
- raise (Reporting_basic.err_unreachable l __POS__ "is_order_inc called on vector with variable ordering")
+ raise (Reporting.err_unreachable l __POS__ "is_order_inc called on vector with variable ordering")
let is_bit_typ = function
| Typ_aux (Typ_id (Id_aux (Id "bit", _)), _) -> true
@@ -1082,7 +1184,7 @@ let rec tyvars_of_nexp (Nexp_aux (nexp,_)) =
| Nexp_neg n -> tyvars_of_nexp n
| Nexp_app (_, nexps) -> List.fold_left KidSet.union KidSet.empty (List.map tyvars_of_nexp nexps)
-let rec tyvars_of_nc (NC_aux (nc, _)) =
+let rec tyvars_of_constraint (NC_aux (nc, _)) =
match nc with
| NC_equal (nexp1, nexp2)
| NC_bounded_ge (nexp1, nexp2)
@@ -1092,13 +1194,14 @@ let rec tyvars_of_nc (NC_aux (nc, _)) =
| NC_set (kid, _) -> KidSet.singleton kid
| NC_or (nc1, nc2)
| NC_and (nc1, nc2) ->
- KidSet.union (tyvars_of_nc nc1) (tyvars_of_nc nc2)
- | NC_app (id, nexps) ->
- List.fold_left KidSet.union KidSet.empty (List.map tyvars_of_nexp nexps)
+ KidSet.union (tyvars_of_constraint nc1) (tyvars_of_constraint nc2)
+ | NC_app (id, args) ->
+ List.fold_left (fun s t -> KidSet.union s (tyvars_of_typ_arg t)) KidSet.empty args
+ | NC_var kid -> KidSet.singleton kid
| NC_true
| NC_false -> KidSet.empty
-let rec tyvars_of_typ (Typ_aux (t,_)) =
+and tyvars_of_typ (Typ_aux (t,_)) =
match t with
| Typ_internal_unknown -> KidSet.empty
| Typ_id _ -> KidSet.empty
@@ -1112,18 +1215,19 @@ let rec tyvars_of_typ (Typ_aux (t,_)) =
List.fold_left (fun s ta -> KidSet.union s (tyvars_of_typ_arg ta))
KidSet.empty tas
| Typ_exist (kids, nc, t) ->
- let s = KidSet.union (tyvars_of_typ t) (tyvars_of_nc nc) in
- List.fold_left (fun s k -> KidSet.remove k s) s kids
-and tyvars_of_typ_arg (Typ_arg_aux (ta,_)) =
+ let s = KidSet.union (tyvars_of_typ t) (tyvars_of_constraint nc) in
+ List.fold_left (fun s k -> KidSet.remove k s) s (List.map kopt_kid kids)
+and tyvars_of_typ_arg (A_aux (ta,_)) =
match ta with
- | Typ_arg_nexp nexp -> tyvars_of_nexp nexp
- | Typ_arg_typ typ -> tyvars_of_typ typ
- | Typ_arg_order _ -> KidSet.empty
+ | A_nexp nexp -> tyvars_of_nexp nexp
+ | A_typ typ -> tyvars_of_typ typ
+ | A_order _ -> KidSet.empty
+ | A_bool nc -> tyvars_of_constraint nc
let tyvars_of_quant_item (QI_aux (qi, _)) = match qi with
- | QI_id (KOpt_aux ((KOpt_none kid | KOpt_kind (_, kid)), _)) ->
+ | QI_id (KOpt_aux (KOpt_kind (_, kid), _)) ->
KidSet.singleton kid
- | QI_const nc -> tyvars_of_nc nc
+ | QI_const nc -> tyvars_of_constraint nc
let is_kid_generated kid = String.contains (string_of_kid kid) '#'
@@ -1135,7 +1239,7 @@ let rec undefined_of_typ mwords l annot (Typ_aux (typ_aux, _) as typ) =
| Typ_app (_,[size;_;_]) when mwords && is_bitvector_typ typ ->
wrap (E_app (mk_id "undefined_bitvector",
undefined_of_typ_args mwords l annot size)) typ
- | Typ_app (atom, [Typ_arg_aux (Typ_arg_nexp i, _)]) when string_of_id atom = "atom" ->
+ | Typ_app (atom, [A_aux (A_nexp i, _)]) when string_of_id atom = "atom" ->
wrap (E_sizeof i) typ
| Typ_app (id, args) ->
wrap (E_app (prepend_id "undefined_" id,
@@ -1150,11 +1254,11 @@ let rec undefined_of_typ mwords l annot (Typ_aux (typ_aux, _) as typ) =
case when re-writing those functions. *)
wrap (E_id (prepend_id "typ_" (id_of_kid kid))) typ
| Typ_internal_unknown | Typ_bidir _ | Typ_fn _ | Typ_exist _ -> assert false (* Typ_exist should be re-written *)
-and undefined_of_typ_args mwords l annot (Typ_arg_aux (typ_arg_aux, _) as typ_arg) =
+and undefined_of_typ_args mwords l annot (A_aux (typ_arg_aux, _) as typ_arg) =
match typ_arg_aux with
- | Typ_arg_nexp n -> [E_aux (E_sizeof n, (l, annot (atom_typ n)))]
- | Typ_arg_typ typ -> [undefined_of_typ mwords l annot typ]
- | Typ_arg_order _ -> []
+ | A_nexp n -> [E_aux (E_sizeof n, (l, annot (atom_typ n)))]
+ | A_typ typ -> [undefined_of_typ mwords l annot typ]
+ | A_order _ -> []
let destruct_pexp (Pat_aux (pexp,ann)) =
match pexp with
@@ -1242,8 +1346,8 @@ let rec subst id value (E_aux (e_aux, annot) as exp) =
| E_list exps -> E_list (List.map (subst id value) exps)
| E_cons (exp1, exp2) -> E_cons (subst id value exp1, subst id value exp2)
- | E_record fexps -> E_record (subst_fexps id value fexps)
- | E_record_update (exp, fexps) -> E_record_update (subst id value exp, subst_fexps id value fexps)
+ | E_record fexps -> E_record (List.map (subst_fexp id value) fexps)
+ | E_record_update (exp, fexps) -> E_record_update (subst id value exp, List.map (subst_fexp id value) fexps)
| E_field (exp, id') -> E_field (subst id value exp, id')
| E_case (exp, pexps) ->
@@ -1288,10 +1392,6 @@ and subst_pexp id value (Pat_aux (pexp_aux, annot)) =
in
Pat_aux (pexp_aux, annot)
-
-and subst_fexps id value (FES_aux (FES_Fexps (fexps, flag), annot)) =
- FES_aux (FES_Fexps (List.map (subst_fexp id value) fexps, flag), annot)
-
and subst_fexp id value (FE_aux (FE_Fexp (id', exp), annot)) =
FE_aux (FE_Fexp (id', subst id value exp), annot)
@@ -1320,175 +1420,193 @@ let hex_to_bin hex =
(* Functions for working with locations *)
-let locate_id l (Id_aux (name, _)) = Id_aux (name, l)
+let locate_id f (Id_aux (name, l)) = Id_aux (name, f l)
+
+let locate_kid f (Kid_aux (name, l)) = Kid_aux (name, f l)
-let locate_kid l (Kid_aux (name, _)) = Kid_aux (name, l)
+let locate_kind f (K_aux (kind, l)) = K_aux (kind, f l)
+
+let locate_kinded_id f (KOpt_aux (KOpt_kind (k, kid), l)) =
+ KOpt_aux (KOpt_kind (locate_kind f k, locate_kid f kid), f l)
-let locate_lit l (L_aux (lit, _)) = L_aux (lit, l)
+let locate_lit f (L_aux (lit, l)) = L_aux (lit, f l)
-let locate_base_effect l (BE_aux (base_effect, _)) = BE_aux (base_effect, l)
+let locate_base_effect f (BE_aux (base_effect, l)) = BE_aux (base_effect, f l)
-let locate_effect l (Effect_aux (Effect_set effects, _)) =
- Effect_aux (Effect_set (List.map (locate_base_effect l) effects), l)
+let locate_effect f (Effect_aux (Effect_set effects, l)) =
+ Effect_aux (Effect_set (List.map (locate_base_effect f) effects), f l)
+
+let locate_order f (Ord_aux (ord_aux, l)) =
+ let ord_aux = match ord_aux with
+ | Ord_inc -> Ord_inc
+ | Ord_dec -> Ord_dec
+ | Ord_var v -> Ord_var (locate_kid f v)
+ in
+ Ord_aux (ord_aux, f l)
-let rec locate_nexp l (Nexp_aux (nexp_aux, _)) =
+let rec locate_nexp f (Nexp_aux (nexp_aux, l)) =
let nexp_aux = match nexp_aux with
- | Nexp_id id -> Nexp_id (locate_id l id)
- | Nexp_var kid -> Nexp_var (locate_kid l kid)
+ | Nexp_id id -> Nexp_id (locate_id f id)
+ | Nexp_var kid -> Nexp_var (locate_kid f kid)
| Nexp_constant n -> Nexp_constant n
- | Nexp_app (id, nexps) -> Nexp_app (locate_id l id, List.map (locate_nexp l) nexps)
- | Nexp_times (nexp1, nexp2) -> Nexp_times (locate_nexp l nexp1, locate_nexp l nexp2)
- | Nexp_sum (nexp1, nexp2) -> Nexp_sum (locate_nexp l nexp1, locate_nexp l nexp2)
- | Nexp_minus (nexp1, nexp2) -> Nexp_minus (locate_nexp l nexp1, locate_nexp l nexp2)
- | Nexp_exp nexp -> Nexp_exp (locate_nexp l nexp)
- | Nexp_neg nexp -> Nexp_neg (locate_nexp l nexp)
+ | Nexp_app (id, nexps) -> Nexp_app (locate_id f id, List.map (locate_nexp f) nexps)
+ | Nexp_times (nexp1, nexp2) -> Nexp_times (locate_nexp f nexp1, locate_nexp f nexp2)
+ | Nexp_sum (nexp1, nexp2) -> Nexp_sum (locate_nexp f nexp1, locate_nexp f nexp2)
+ | Nexp_minus (nexp1, nexp2) -> Nexp_minus (locate_nexp f nexp1, locate_nexp f nexp2)
+ | Nexp_exp nexp -> Nexp_exp (locate_nexp f nexp)
+ | Nexp_neg nexp -> Nexp_neg (locate_nexp f nexp)
in
- Nexp_aux (nexp_aux, l)
+ Nexp_aux (nexp_aux, f l)
-let rec locate_nc l (NC_aux (nc_aux, _)) =
+let rec locate_nc f (NC_aux (nc_aux, l)) =
let nc_aux = match nc_aux with
- | NC_equal (nexp1, nexp2) -> NC_equal (locate_nexp l nexp1, locate_nexp l nexp2)
- | NC_bounded_ge (nexp1, nexp2) -> NC_bounded_ge (locate_nexp l nexp1, locate_nexp l nexp2)
- | NC_bounded_le (nexp1, nexp2) -> NC_bounded_le (locate_nexp l nexp1, locate_nexp l nexp2)
- | NC_not_equal (nexp1, nexp2) -> NC_not_equal (locate_nexp l nexp1, locate_nexp l nexp2)
- | NC_set (kid, nums) -> NC_set (locate_kid l kid, nums)
- | NC_or (nc1, nc2) -> NC_or (locate_nc l nc1, locate_nc l nc2)
- | NC_and (nc1, nc2) -> NC_and (locate_nc l nc1, locate_nc l nc2)
- | NC_app (id, nexps) -> NC_app (id, List.map (locate_nexp l) nexps)
+ | NC_equal (nexp1, nexp2) -> NC_equal (locate_nexp f nexp1, locate_nexp f nexp2)
+ | NC_bounded_ge (nexp1, nexp2) -> NC_bounded_ge (locate_nexp f nexp1, locate_nexp f nexp2)
+ | NC_bounded_le (nexp1, nexp2) -> NC_bounded_le (locate_nexp f nexp1, locate_nexp f nexp2)
+ | NC_not_equal (nexp1, nexp2) -> NC_not_equal (locate_nexp f nexp1, locate_nexp f nexp2)
+ | NC_set (kid, nums) -> NC_set (locate_kid f kid, nums)
+ | NC_or (nc1, nc2) -> NC_or (locate_nc f nc1, locate_nc f nc2)
+ | NC_and (nc1, nc2) -> NC_and (locate_nc f nc1, locate_nc f nc2)
| NC_true -> NC_true
| NC_false -> NC_false
+ | NC_var v -> NC_var (locate_kid f v)
+ | NC_app (id, args) -> NC_app (locate_id f id, List.map (locate_typ_arg f) args)
in
- NC_aux (nc_aux, l)
+ NC_aux (nc_aux, f l)
-let rec locate_typ l (Typ_aux (typ_aux, _)) =
+and locate_typ f (Typ_aux (typ_aux, l)) =
let typ_aux = match typ_aux with
| Typ_internal_unknown -> Typ_internal_unknown
- | Typ_id id -> Typ_id (locate_id l id)
- | Typ_var kid -> Typ_var (locate_kid l kid)
+ | Typ_id id -> Typ_id (locate_id f id)
+ | Typ_var kid -> Typ_var (locate_kid f kid)
| Typ_fn (arg_typs, ret_typ, effect) ->
- Typ_fn (List.map (locate_typ l) arg_typs, locate_typ l ret_typ, locate_effect l effect)
- | Typ_bidir (typ1, typ2) -> Typ_bidir (locate_typ l typ1, locate_typ l typ2)
- | Typ_tup typs -> Typ_tup (List.map (locate_typ l) typs)
- | Typ_exist (kids, constr, typ) -> Typ_exist (List.map (locate_kid l) kids, locate_nc l constr, locate_typ l typ)
- | Typ_app (id, typ_args) -> Typ_app (locate_id l id, List.map (locate_typ_arg l) typ_args)
+ Typ_fn (List.map (locate_typ f) arg_typs, locate_typ f ret_typ, locate_effect f effect)
+ | Typ_bidir (typ1, typ2) -> Typ_bidir (locate_typ f typ1, locate_typ f typ2)
+ | Typ_tup typs -> Typ_tup (List.map (locate_typ f) typs)
+ | Typ_exist (kopts, constr, typ) -> Typ_exist (List.map (locate_kinded_id f) kopts, locate_nc f constr, locate_typ f typ)
+ | Typ_app (id, typ_args) -> Typ_app (locate_id f id, List.map (locate_typ_arg f) typ_args)
in
- Typ_aux (typ_aux, l)
+ Typ_aux (typ_aux, f l)
-and locate_typ_arg l (Typ_arg_aux (typ_arg_aux, _)) =
+and locate_typ_arg f (A_aux (typ_arg_aux, l)) =
let typ_arg_aux = match typ_arg_aux with
- | Typ_arg_nexp nexp -> Typ_arg_nexp nexp
- | Typ_arg_typ typ -> Typ_arg_typ (locate_typ l typ)
- | Typ_arg_order ord -> Typ_arg_order ord
+ | A_nexp nexp -> A_nexp (locate_nexp f nexp)
+ | A_typ typ -> A_typ (locate_typ f typ)
+ | A_order ord -> A_order (locate_order f ord)
+ | A_bool nc -> A_bool (locate_nc f nc)
in
- Typ_arg_aux (typ_arg_aux, l)
+ A_aux (typ_arg_aux, f l)
-let rec locate_typ_pat l (TP_aux (tp_aux, _)) =
+let rec locate_typ_pat f (TP_aux (tp_aux, l)) =
let tp_aux = match tp_aux with
| TP_wild -> TP_wild
- | TP_var kid -> TP_var (locate_kid l kid)
- | TP_app (id, tps) -> TP_app (locate_id l id, List.map (locate_typ_pat l) tps)
+ | TP_var kid -> TP_var (locate_kid f kid)
+ | TP_app (id, tps) -> TP_app (locate_id f id, List.map (locate_typ_pat f) tps)
in
- TP_aux (tp_aux, l)
+ TP_aux (tp_aux, f l)
-let rec locate_pat : 'a. l -> 'a pat -> 'a pat = fun l (P_aux (p_aux, (_, annot))) ->
+let rec locate_pat : 'a. (l -> l) -> 'a pat -> 'a pat = fun f (P_aux (p_aux, (l, annot))) ->
let p_aux = match p_aux with
- | P_lit lit -> P_lit (locate_lit l lit)
+ | P_lit lit -> P_lit (locate_lit f lit)
| P_wild -> P_wild
- | P_or (pat1, pat2) -> P_or (locate_pat l pat1, locate_pat l pat2)
- | P_not pat -> P_not (locate_pat l pat)
- | P_as (pat, id) -> P_as (locate_pat l pat, locate_id l id)
- | P_typ (typ, pat) -> P_typ (locate_typ l typ, locate_pat l pat)
- | P_id id -> P_id (locate_id l id)
- | P_var (pat, typ_pat) -> P_var (locate_pat l pat, locate_typ_pat l typ_pat)
- | P_app (id, pats) -> P_app (locate_id l id, List.map (locate_pat l) pats)
- | P_record (fpats, semi) -> P_record (List.map (locate_fpat l) fpats, semi)
- | P_vector pats -> P_vector (List.map (locate_pat l) pats)
- | P_vector_concat pats -> P_vector_concat (List.map (locate_pat l) pats)
- | P_tup pats -> P_tup (List.map (locate_pat l) pats)
- | P_list pats -> P_list (List.map (locate_pat l) pats)
- | P_cons (hd_pat, tl_pat) -> P_cons (locate_pat l hd_pat, locate_pat l tl_pat)
- | P_string_append pats -> P_string_append (List.map (locate_pat l) pats)
+ | P_or (pat1, pat2) -> P_or (locate_pat f pat1, locate_pat f pat2)
+ | P_not pat -> P_not (locate_pat f pat)
+ | P_as (pat, id) -> P_as (locate_pat f pat, locate_id f id)
+ | P_typ (typ, pat) -> P_typ (locate_typ f typ, locate_pat f pat)
+ | P_id id -> P_id (locate_id f id)
+ | P_var (pat, typ_pat) -> P_var (locate_pat f pat, locate_typ_pat f typ_pat)
+ | P_app (id, pats) -> P_app (locate_id f id, List.map (locate_pat f) pats)
+ | P_record (fpats, semi) -> P_record (List.map (locate_fpat f) fpats, semi)
+ | P_vector pats -> P_vector (List.map (locate_pat f) pats)
+ | P_vector_concat pats -> P_vector_concat (List.map (locate_pat f) pats)
+ | P_tup pats -> P_tup (List.map (locate_pat f) pats)
+ | P_list pats -> P_list (List.map (locate_pat f) pats)
+ | P_cons (hd_pat, tl_pat) -> P_cons (locate_pat f hd_pat, locate_pat f tl_pat)
+ | P_string_append pats -> P_string_append (List.map (locate_pat f) pats)
in
- P_aux (p_aux, (l, annot))
+ P_aux (p_aux, (f l, annot))
-and locate_fpat : 'a. l -> 'a fpat -> 'a fpat = fun l (FP_aux (FP_Fpat (id, pat), (_, annot))) ->
- FP_aux (FP_Fpat (locate_id l id, locate_pat l pat), (l, annot))
+and locate_fpat : 'a. (l -> l) -> 'a fpat -> 'a fpat = fun f (FP_aux (FP_Fpat (id, pat), (l, annot))) ->
+ FP_aux (FP_Fpat (locate_id f id, locate_pat f pat), (f l, annot))
-let rec locate : 'a. l -> 'a exp -> 'a exp = fun l (E_aux (e_aux, (_, annot))) ->
+let rec locate : 'a. (l -> l) -> 'a exp -> 'a exp = fun f (E_aux (e_aux, (l, annot))) ->
let e_aux = match e_aux with
- | E_block exps -> E_block (List.map (locate l) exps)
- | E_nondet exps -> E_nondet (List.map (locate l) exps)
- | E_id id -> E_id (locate_id l id)
- | E_lit lit -> E_lit (locate_lit l lit)
- | E_cast (typ, exp) -> E_cast (locate_typ l typ, locate l exp)
- | E_app (f, exps) -> E_app (locate_id l f, List.map (locate l) exps)
- | E_app_infix (exp1, op, exp2) -> E_app_infix (locate l exp1, locate_id l op, locate l exp2)
- | E_tuple exps -> E_tuple (List.map (locate l) exps)
- | E_if (cond_exp, then_exp, else_exp) -> E_if (locate l cond_exp, locate l then_exp, locate l else_exp)
- | E_loop (loop, cond, body) -> E_loop (loop, locate l cond, locate l body)
+ | E_block exps -> E_block (List.map (locate f) exps)
+ | E_nondet exps -> E_nondet (List.map (locate f) exps)
+ | E_id id -> E_id (locate_id f id)
+ | E_lit lit -> E_lit (locate_lit f lit)
+ | E_cast (typ, exp) -> E_cast (locate_typ f typ, locate f exp)
+ | E_app (id, exps) -> E_app (locate_id f id, List.map (locate f) exps)
+ | E_app_infix (exp1, op, exp2) -> E_app_infix (locate f exp1, locate_id f op, locate f exp2)
+ | E_tuple exps -> E_tuple (List.map (locate f) exps)
+ | E_if (cond_exp, then_exp, else_exp) -> E_if (locate f cond_exp, locate f then_exp, locate f else_exp)
+ | E_loop (loop, cond, body) -> E_loop (loop, locate f cond, locate f body)
| E_for (id, exp1, exp2, exp3, ord, exp4) ->
- E_for (locate_id l id, locate l exp1, locate l exp2, locate l exp3, ord, locate l exp4)
- | E_vector exps -> E_vector (List.map (locate l) exps)
- | E_vector_access (exp1, exp2) -> E_vector_access (locate l exp1, locate l exp2)
- | E_vector_subrange (exp1, exp2, exp3) -> E_vector_subrange (locate l exp1, locate l exp2, locate l exp3)
- | E_vector_update (exp1, exp2, exp3) -> E_vector_update (locate l exp1, locate l exp2, locate l exp3)
+ E_for (locate_id f id, locate f exp1, locate f exp2, locate f exp3, ord, locate f exp4)
+ | E_vector exps -> E_vector (List.map (locate f) exps)
+ | E_vector_access (exp1, exp2) -> E_vector_access (locate f exp1, locate f exp2)
+ | E_vector_subrange (exp1, exp2, exp3) -> E_vector_subrange (locate f exp1, locate f exp2, locate f exp3)
+ | E_vector_update (exp1, exp2, exp3) -> E_vector_update (locate f exp1, locate f exp2, locate f exp3)
| E_vector_update_subrange (exp1, exp2, exp3, exp4) ->
- E_vector_update_subrange (locate l exp1, locate l exp2, locate l exp3, locate l exp4)
+ E_vector_update_subrange (locate f exp1, locate f exp2, locate f exp3, locate f exp4)
| E_vector_append (exp1, exp2) ->
- E_vector_append (locate l exp1, locate l exp2)
- | E_list exps -> E_list (List.map (locate l) exps)
- | E_cons (exp1, exp2) -> E_cons (locate l exp1, locate l exp2)
- | E_record fexps -> E_record (locate_fexps l fexps)
- | E_record_update (exp, fexps) -> E_record_update (locate l exp, locate_fexps l fexps)
- | E_field (exp, id) -> E_field (locate l exp, locate_id l id)
- | E_case (exp, cases) -> E_case (locate l exp, List.map (locate_pexp l) cases)
- | E_let (letbind, exp) -> E_let (locate_letbind l letbind, locate l exp)
- | E_assign (lexp, exp) -> E_assign (locate_lexp l lexp, locate l exp)
- | E_sizeof nexp -> E_sizeof (locate_nexp l nexp)
- | E_return exp -> E_return (locate l exp)
- | E_exit exp -> E_exit (locate l exp)
- | E_ref id -> E_ref (locate_id l id)
- | E_throw exp -> E_throw (locate l exp)
- | E_try (exp, cases) -> E_try (locate l exp, List.map (locate_pexp l) cases)
- | E_assert (exp, message) -> E_assert (locate l exp, locate l message)
- | E_constraint constr -> E_constraint (locate_nc l constr)
- | E_var (lexp, exp1, exp2) -> E_var (locate_lexp l lexp, locate l exp1, locate l exp2)
- | E_internal_plet (pat, exp1, exp2) -> E_internal_plet (locate_pat l pat, locate l exp1, locate l exp2)
- | E_internal_return exp -> E_internal_return (locate l exp)
+ E_vector_append (locate f exp1, locate f exp2)
+ | E_list exps -> E_list (List.map (locate f) exps)
+ | E_cons (exp1, exp2) -> E_cons (locate f exp1, locate f exp2)
+ | E_record fexps -> E_record (List.map (locate_fexp f) fexps)
+ | E_record_update (exp, fexps) -> E_record_update (locate f exp, List.map (locate_fexp f) fexps)
+ | E_field (exp, id) -> E_field (locate f exp, locate_id f id)
+ | E_case (exp, cases) -> E_case (locate f exp, List.map (locate_pexp f) cases)
+ | E_let (letbind, exp) -> E_let (locate_letbind f letbind, locate f exp)
+ | E_assign (lexp, exp) -> E_assign (locate_lexp f lexp, locate f exp)
+ | E_sizeof nexp -> E_sizeof (locate_nexp f nexp)
+ | E_return exp -> E_return (locate f exp)
+ | E_exit exp -> E_exit (locate f exp)
+ | E_ref id -> E_ref (locate_id f id)
+ | E_throw exp -> E_throw (locate f exp)
+ | E_try (exp, cases) -> E_try (locate f exp, List.map (locate_pexp f) cases)
+ | E_assert (exp, message) -> E_assert (locate f exp, locate f message)
+ | E_constraint constr -> E_constraint (locate_nc f constr)
+ | E_var (lexp, exp1, exp2) -> E_var (locate_lexp f lexp, locate f exp1, locate f exp2)
+ | E_internal_plet (pat, exp1, exp2) -> E_internal_plet (locate_pat f pat, locate f exp1, locate f exp2)
+ | E_internal_return exp -> E_internal_return (locate f exp)
| E_internal_value value -> E_internal_value value
in
- E_aux (e_aux, (l, annot))
+ E_aux (e_aux, (f l, annot))
-and locate_letbind : 'a. l -> 'a letbind -> 'a letbind = fun l (LB_aux (LB_val (pat, exp), (_, annot))) ->
- LB_aux (LB_val (locate_pat l pat, locate l exp), (l, annot))
+and locate_letbind : 'a. (l -> l) -> 'a letbind -> 'a letbind = fun f (LB_aux (LB_val (pat, exp), (l, annot))) ->
+ LB_aux (LB_val (locate_pat f pat, locate f exp), (f l, annot))
-and locate_pexp : 'a. l -> 'a pexp -> 'a pexp = fun l (Pat_aux (pexp_aux, (_, annot))) ->
+and locate_pexp : 'a. (l -> l) -> 'a pexp -> 'a pexp = fun f (Pat_aux (pexp_aux, (l, annot))) ->
let pexp_aux = match pexp_aux with
- | Pat_exp (pat, exp) -> Pat_exp (locate_pat l pat, locate l exp)
- | Pat_when (pat, guard, exp) -> Pat_when (locate_pat l pat, locate l guard, locate l exp)
+ | Pat_exp (pat, exp) -> Pat_exp (locate_pat f pat, locate f exp)
+ | Pat_when (pat, guard, exp) -> Pat_when (locate_pat f pat, locate f guard, locate f exp)
in
- Pat_aux (pexp_aux, (l, annot))
+ Pat_aux (pexp_aux, (f l, annot))
-and locate_lexp : 'a. l -> 'a lexp -> 'a lexp = fun l (LEXP_aux (lexp_aux, (_, annot))) ->
+and locate_lexp : 'a. (l -> l) -> 'a lexp -> 'a lexp = fun f (LEXP_aux (lexp_aux, (l, annot))) ->
let lexp_aux = match lexp_aux with
- | LEXP_id id -> LEXP_id (locate_id l id)
- | LEXP_deref exp -> LEXP_deref (locate l exp)
- | LEXP_memory (id, exps) -> LEXP_memory (locate_id l id, List.map (locate l) exps)
- | LEXP_cast (typ, id) -> LEXP_cast (locate_typ l typ, locate_id l id)
- | LEXP_tup lexps -> LEXP_tup (List.map (locate_lexp l) lexps)
- | LEXP_vector_concat lexps -> LEXP_vector_concat (List.map (locate_lexp l) lexps)
- | LEXP_vector (lexp, exp) -> LEXP_vector (locate_lexp l lexp, locate l exp)
- | LEXP_vector_range (lexp, exp1, exp2) -> LEXP_vector_range (locate_lexp l lexp, locate l exp1, locate l exp2)
- | LEXP_field (lexp, id) -> LEXP_field (locate_lexp l lexp, locate_id l id)
+ | LEXP_id id -> LEXP_id (locate_id f id)
+ | LEXP_deref exp -> LEXP_deref (locate f exp)
+ | LEXP_memory (id, exps) -> LEXP_memory (locate_id f id, List.map (locate f) exps)
+ | LEXP_cast (typ, id) -> LEXP_cast (locate_typ f typ, locate_id f id)
+ | LEXP_tup lexps -> LEXP_tup (List.map (locate_lexp f) lexps)
+ | LEXP_vector_concat lexps -> LEXP_vector_concat (List.map (locate_lexp f) lexps)
+ | LEXP_vector (lexp, exp) -> LEXP_vector (locate_lexp f lexp, locate f exp)
+ | LEXP_vector_range (lexp, exp1, exp2) -> LEXP_vector_range (locate_lexp f lexp, locate f exp1, locate f exp2)
+ | LEXP_field (lexp, id) -> LEXP_field (locate_lexp f lexp, locate_id f id)
in
- LEXP_aux (lexp_aux, (l, annot))
+ LEXP_aux (lexp_aux, (f l, annot))
-and locate_fexps : 'a. l -> 'a fexps -> 'a fexps = fun l (FES_aux (FES_Fexps (fexps, semi), (_, annot))) ->
- FES_aux (FES_Fexps (List.map (locate_fexp l) fexps, semi), (l, annot))
+and locate_fexp : 'a. (l -> l) -> 'a fexp -> 'a fexp = fun f (FE_aux (FE_Fexp (id, exp), (l, annot))) ->
+ FE_aux (FE_Fexp (locate_id f id, locate f exp), (f l, annot))
-and locate_fexp : 'a. l -> 'a fexp -> 'a fexp = fun l (FE_aux (FE_Fexp (id, exp), (_, annot))) ->
- FE_aux (FE_Fexp (locate_id l id, locate l exp), (l, annot))
+let unique_ref = ref 0
+let unique l =
+ let l = Parse_ast.Unique (!unique_ref, l) in
+ incr unique_ref;
+ l
let extern_assoc backend exts =
try
@@ -1498,3 +1616,111 @@ let extern_assoc backend exts =
Some (List.assoc "_" exts)
with Not_found ->
None
+
+(**************************************************************************)
+(* 1. Substitutions *)
+(**************************************************************************)
+
+let order_subst_aux sv subst = function
+ | Ord_var kid ->
+ begin match subst with
+ | A_aux (A_order ord, _) when Kid.compare kid sv = 0 ->
+ unaux_order ord
+ | _ -> Ord_var kid
+ end
+ | Ord_inc -> Ord_inc
+ | Ord_dec -> Ord_dec
+
+let order_subst sv subst (Ord_aux (ord, l)) = Ord_aux (order_subst_aux sv subst ord, l)
+
+let rec nexp_subst sv subst (Nexp_aux (nexp, l)) = Nexp_aux (nexp_subst_aux sv subst nexp, l)
+and nexp_subst_aux sv subst = function
+ | Nexp_var kid ->
+ begin match subst with
+ | A_aux (A_nexp n, _) when Kid.compare kid sv = 0 -> unaux_nexp n
+ | _ -> Nexp_var kid
+ end
+ | Nexp_id id -> Nexp_id id
+ | Nexp_constant c -> Nexp_constant c
+ | Nexp_times (nexp1, nexp2) -> Nexp_times (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
+ | Nexp_sum (nexp1, nexp2) -> Nexp_sum (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
+ | Nexp_minus (nexp1, nexp2) -> Nexp_minus (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
+ | Nexp_app (id, nexps) -> Nexp_app (id, List.map (nexp_subst sv subst) nexps)
+ | Nexp_exp nexp -> Nexp_exp (nexp_subst sv subst nexp)
+ | Nexp_neg nexp -> Nexp_neg (nexp_subst sv subst nexp)
+
+let rec nexp_set_to_or l subst = function
+ | [] -> raise (Reporting.err_unreachable l __POS__ "Empty set in constraint")
+ | [int] -> NC_equal (subst, nconstant int)
+ | (int :: ints) -> NC_or (mk_nc (NC_equal (subst, nconstant int)), mk_nc (nexp_set_to_or l subst ints))
+
+let rec constraint_subst sv subst (NC_aux (nc, l)) = NC_aux (constraint_subst_aux l sv subst nc, l)
+and constraint_subst_aux l sv subst = function
+ | NC_equal (n1, n2) -> NC_equal (nexp_subst sv subst n1, nexp_subst sv subst n2)
+ | NC_bounded_ge (n1, n2) -> NC_bounded_ge (nexp_subst sv subst n1, nexp_subst sv subst n2)
+ | NC_bounded_le (n1, n2) -> NC_bounded_le (nexp_subst sv subst n1, nexp_subst sv subst n2)
+ | NC_not_equal (n1, n2) -> NC_not_equal (nexp_subst sv subst n1, nexp_subst sv subst n2)
+ | NC_set (kid, ints) as set_nc ->
+ begin match subst with
+ | A_aux (A_nexp n, _) when Kid.compare kid sv = 0 ->
+ nexp_set_to_or l n ints
+ | _ -> set_nc
+ end
+ | NC_or (nc1, nc2) -> NC_or (constraint_subst sv subst nc1, constraint_subst sv subst nc2)
+ | NC_and (nc1, nc2) -> NC_and (constraint_subst sv subst nc1, constraint_subst sv subst nc2)
+ | NC_app (id, args) -> NC_app (id, List.map (typ_arg_subst sv subst) args)
+ | NC_var kid ->
+ begin match subst with
+ | A_aux (A_bool nc, _) when Kid.compare kid sv = 0 ->
+ unaux_constraint nc
+ | _ -> NC_var kid
+ end
+ | NC_false -> NC_false
+ | NC_true -> NC_true
+
+and typ_subst sv subst (Typ_aux (typ, l)) = Typ_aux (typ_subst_aux sv subst typ, l)
+and typ_subst_aux sv subst = function
+ | Typ_internal_unknown -> Typ_internal_unknown
+ | Typ_id v -> Typ_id v
+ | Typ_var kid ->
+ begin match subst with
+ | A_aux (A_typ typ, _) when Kid.compare kid sv = 0 ->
+ unaux_typ typ
+ | _ -> Typ_var kid
+ end
+ | Typ_fn (arg_typs, ret_typ, effs) -> Typ_fn (List.map (typ_subst sv subst) arg_typs, typ_subst sv subst ret_typ, effs)
+ | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst sv subst typ1, typ_subst sv subst typ2)
+ | Typ_tup typs -> Typ_tup (List.map (typ_subst sv subst) typs)
+ | Typ_app (f, args) -> Typ_app (f, List.map (typ_arg_subst sv subst) args)
+ | Typ_exist (kopts, nc, typ) when KidSet.mem sv (KidSet.of_list (List.map kopt_kid kopts)) ->
+ Typ_exist (kopts, nc, typ)
+ | Typ_exist (kopts, nc, typ) ->
+ Typ_exist (kopts, constraint_subst sv subst nc, typ_subst sv subst typ)
+
+and typ_arg_subst sv subst (A_aux (arg, l)) = A_aux (typ_arg_subst_aux sv subst arg, l)
+and typ_arg_subst_aux sv subst = function
+ | A_nexp nexp -> A_nexp (nexp_subst sv subst nexp)
+ | A_typ typ -> A_typ (typ_subst sv subst typ)
+ | A_order ord -> A_order (order_subst sv subst ord)
+ | A_bool nc -> A_bool (constraint_subst sv subst nc)
+
+let subst_kid subst sv v x =
+ x
+ |> subst sv (mk_typ_arg (A_bool (nc_var v)))
+ |> subst sv (mk_typ_arg (A_nexp (nvar v)))
+ |> subst sv (mk_typ_arg (A_order (Ord_aux (Ord_var v, Parse_ast.Unknown))))
+ |> subst sv (mk_typ_arg (A_typ (mk_typ (Typ_var v))))
+
+let quant_item_subst_kid_aux sv subst = function
+ | QI_id (KOpt_aux (KOpt_kind (k, kid), l)) as qid ->
+ if Kid.compare kid sv = 0 then QI_id (KOpt_aux (KOpt_kind (k, subst), l)) else qid
+ | QI_const nc ->
+ QI_const (subst_kid constraint_subst sv subst nc)
+
+let quant_item_subst_kid sv subst (QI_aux (quant, l)) = QI_aux (quant_item_subst_kid_aux sv subst quant, l)
+
+let typquant_subst_kid_aux sv subst = function
+ | TypQ_tq quants -> TypQ_tq (List.map (quant_item_subst_kid sv subst) quants)
+ | TypQ_no_forall -> TypQ_no_forall
+
+let typquant_subst_kid sv subst (TypQ_aux (typq, l)) = TypQ_aux (typquant_subst_kid_aux sv subst typq, l)
diff --git a/src/ast_util.mli b/src/ast_util.mli
index 54f18ae8..dc9f8594 100644
--- a/src/ast_util.mli
+++ b/src/ast_util.mli
@@ -85,18 +85,20 @@ val mk_fundef : (unit funcl) list -> unit def
val mk_val_spec : val_spec_aux -> unit def
val mk_typschm : typquant -> typ -> typschm
val mk_typquant : quant_item list -> typquant
-val mk_qi_id : base_kind_aux -> kid -> quant_item
+val mk_qi_id : kind_aux -> kid -> quant_item
val mk_qi_nc : n_constraint -> quant_item
val mk_qi_kopt : kinded_id -> quant_item
val mk_fexp : id -> unit exp -> unit fexp
-val mk_fexps : (unit fexp) list -> unit fexps
val mk_letbind : unit pat -> unit exp -> unit letbind
+val mk_kopt : kind_aux -> kid -> kinded_id
val unaux_exp : 'a exp -> 'a exp_aux
val unaux_pat : 'a pat -> 'a pat_aux
val unaux_nexp : nexp -> nexp_aux
val unaux_order : order -> order_aux
val unaux_typ : typ -> typ_aux
+val unaux_kind : kind -> kind_aux
+val unaux_constraint : n_constraint -> n_constraint_aux
val untyp_pat : 'a pat -> 'a pat * typ option
val uncast_exp : 'a exp -> 'a exp * typ option
@@ -106,10 +108,12 @@ val dec_ord : order
(* Utilites for working with kinded_ids *)
val kopt_kid : kinded_id -> kid
+val kopt_kind : kinded_id -> kind
val is_nat_kopt : kinded_id -> bool
val is_order_kopt : kinded_id -> bool
val is_typ_kopt : kinded_id -> bool
-
+val is_bool_kopt : kinded_id -> bool
+
(* Some handy utility functions for constructing types. *)
val mk_typ : typ_aux -> typ
val mk_typ_arg : typ_arg_aux -> typ_arg
@@ -138,6 +142,12 @@ val no_effect : effect
val mk_effect : base_effect_aux list -> effect
val nexp_simp : nexp -> nexp
+val constraint_simp : n_constraint -> n_constraint
+
+(* If a constraint is a conjunction, return a list of all the top-level conjuncts *)
+val constraint_conj : n_constraint -> n_constraint list
+(* Same as constraint_conj but for disjunctions *)
+val constraint_disj : n_constraint -> n_constraint list
(* Utilities for building n-expressions *)
val nconstant : Big_int.num -> nexp
@@ -148,7 +158,7 @@ val ntimes : nexp -> nexp -> nexp
val npow2 : nexp -> nexp
val nvar : kid -> nexp
val napp : id -> nexp list -> nexp
-val nid : id -> nexp (* NOTE: Nexp_id's don't do anything currently *)
+val nid : id -> nexp
(* Numeric constraint builders *)
val nc_eq : nexp -> nexp -> n_constraint
@@ -159,21 +169,29 @@ val nc_lt : nexp -> nexp -> n_constraint
val nc_gt : nexp -> nexp -> n_constraint
val nc_and : n_constraint -> n_constraint -> n_constraint
val nc_or : n_constraint -> n_constraint -> n_constraint
+val nc_not : n_constraint -> n_constraint
val nc_true : n_constraint
val nc_false : n_constraint
val nc_set : kid -> Big_int.num list -> n_constraint
val nc_int_set : kid -> int list -> n_constraint
+val nc_var : kid -> n_constraint
-(* Negate a n_constraint. Note that there's no NC_not constructor, so
- this flips all the inequalites a the n_constraint leaves and uses
- de-morgans to switch and to or and vice versa. *)
-val nc_negate : n_constraint -> n_constraint
+val arg_nexp : ?loc:l -> nexp -> typ_arg
+val arg_order : ?loc:l -> order -> typ_arg
+val arg_typ : ?loc:l -> typ -> typ_arg
+val arg_bool : ?loc:l -> n_constraint -> typ_arg
+val arg_kopt : kinded_id -> typ_arg
+(* Functions for working with type quantifiers *)
+val quant_add : quant_item -> typquant -> typquant
val quant_items : typquant -> quant_item list
val quant_kopts : typquant -> kinded_id list
val quant_split : typquant -> kinded_id list * n_constraint list
val quant_map_items : (quant_item -> quant_item) -> typquant -> typquant
+val is_quant_kopt : quant_item -> bool
+val is_quant_constraint : quant_item -> bool
+
(* Functions to map over the annotations in sub-expressions *)
val map_exp_annot : ('a annot -> 'b annot) -> 'a exp -> 'b exp
val map_pat_annot : ('a annot -> 'b annot) -> 'a pat -> 'b pat
@@ -195,12 +213,10 @@ val def_loc : 'a def -> Parse_ast.l
(* For debugging and error messages only: Not guaranteed to produce
parseable SAIL, or even print all language constructs! *)
-(* TODO: replace with existing pretty-printer *)
val string_of_id : id -> string
val string_of_kid : kid -> string
val string_of_base_effect_aux : base_effect_aux -> string
-val string_of_base_kind_aux : base_kind_aux -> string
-val string_of_base_kind : base_kind -> string
+val string_of_kind_aux : kind_aux -> string
val string_of_kind : kind -> string
val string_of_base_effect : base_effect -> string
val string_of_effect : effect -> string
@@ -226,6 +242,7 @@ val string_of_index_range : index_range -> string
val id_of_fundef : 'a fundef -> id
val id_of_type_def : 'a type_def -> id
val id_of_val_spec : 'a val_spec -> id
+val id_of_dec_spec : 'a dec_spec -> id
val id_of_kid : kid -> id
val kid_of_id : id -> kid
@@ -244,6 +261,16 @@ module Kid : sig
val compare : kid -> kid -> int
end
+module Kind : sig
+ type t = kind
+ val compare : kind -> kind -> int
+end
+
+module KOpt : sig
+ type t = kinded_id
+ val compare : kinded_id -> kinded_id -> int
+end
+
module Nexp : sig
type t = nexp
val compare : nexp -> nexp -> int
@@ -272,6 +299,14 @@ module NexpMap : sig
include Map.S with type key = nexp
end
+module KOptSet : sig
+ include Set.S with type elt = kinded_id
+end
+
+module KOptMap : sig
+ include Map.S with type key = kinded_id
+end
+
module BESet : sig
include Set.S with type elt = base_effect
end
@@ -320,6 +355,7 @@ val union_effects : effect -> effect -> effect
val tyvars_of_nexp : nexp -> KidSet.t
val tyvars_of_typ : typ -> KidSet.t
+val tyvars_of_constraint : n_constraint -> KidSet.t
val tyvars_of_quant_item : quant_item -> KidSet.t
val is_kid_generated : kid -> bool
@@ -353,19 +389,39 @@ val subst : id -> 'a exp -> 'a exp -> 'a exp
val hex_to_bin : string -> string
-
(** locate takes an expression and recursively sets the location in
- every subexpression to the provided location. Expressions build
- using mk_exp and similar do not have locations, so they can then be
- annotated as e.g. locate (gen_loc l) (mk_exp ...) where l is the
- location from which the code is being generated. *)
-val locate : l -> 'a exp -> 'a exp
+ every subexpression using a function that takes the orginal
+ location as an argument. Expressions build using mk_exp and similar
+ do not have locations, so they can then be annotated as e.g. locate
+ (gen_loc l) (mk_exp ...) where l is the location from which the
+ code is being generated. *)
+val locate : (l -> l) -> 'a exp -> 'a exp
+
+val locate_pat : (l -> l) -> 'a pat -> 'a pat
-val locate_pat : l -> 'a pat -> 'a pat
+val locate_lexp : (l -> l) -> 'a lexp -> 'a lexp
-val locate_lexp : l -> 'a lexp -> 'a lexp
+val locate_typ : (l -> l) -> typ -> typ
-val locate_typ : l -> typ -> typ
+(* Make a unique location by giving it a Parse_ast.Unique wrapper with
+ a generated number. *)
+val unique : l -> l
val extern_assoc : string -> (string * string) list -> string option
+
+(** Substitutions *)
+
+(* The function X_subst substitutes a type argument into something of
+ type X. The type of the type argument determines which kind of type
+ variables willb e replaced *)
+val nexp_subst : kid -> typ_arg -> nexp -> nexp
+val constraint_subst : kid -> typ_arg -> n_constraint -> n_constraint
+val order_subst : kid -> typ_arg -> order -> order
+val typ_subst : kid -> typ_arg -> typ -> typ
+val typ_arg_subst : kid -> typ_arg -> typ_arg -> typ_arg
+
+val subst_kid : (kid -> typ_arg -> 'a -> 'a) -> kid -> kid -> 'a -> 'a
+
+val quant_item_subst_kid : kid -> kid -> quant_item -> quant_item
+val typquant_subst_kid : kid -> kid -> typquant -> typquant
diff --git a/src/bytecode_interpreter.ml b/src/bytecode_interpreter.ml
new file mode 100644
index 00000000..398e0c9d
--- /dev/null
+++ b/src/bytecode_interpreter.ml
@@ -0,0 +1,162 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast
+open Ast_util
+open Bytecode
+open Bytecode_util
+
+module StringMap = Map.Make(String)
+
+type 'a frame = {
+ jump_table : int StringMap.t;
+ locals : 'a Bindings.t;
+ pc : int;
+ instrs : instr array
+ }
+
+type 'a gstate = {
+ globals : 'a Bindings.t;
+ cdefs : cdef list
+ }
+
+type 'a stack = {
+ top : 'a frame;
+ ret : ('a -> 'a frame) list
+ }
+
+let make_jump_table instrs =
+ let rec aux n = function
+ | I_aux (I_label label, _) :: instrs -> StringMap.add label n (aux (n + 1) instrs)
+ | _ :: instrs -> aux (n + 1) instrs
+ | [] -> StringMap.empty
+ in
+ aux 0 instrs
+
+let new_gstate cdefs = {
+ globals = Bindings.empty;
+ cdefs = cdefs
+ }
+
+let new_stack instrs = {
+ top = {
+ jump_table = make_jump_table instrs;
+ locals = Bindings.empty;
+ pc = 0;
+ instrs = Array.of_list instrs
+ };
+ ret = []
+ }
+
+let with_top stack f =
+ { stack with top = f (stack.top) }
+
+let eval_fragment gstate locals = function
+ | F_id id ->
+ begin match Bindings.find_opt id locals with
+ | Some vl -> vl
+ | None ->
+ begin match Bindings.find_opt id gstate.globals with
+ | Some vl -> vl
+ | None -> failwith "Identifier not found"
+ end
+ end
+ | F_lit vl -> vl
+ | _ -> failwith "Cannot eval fragment"
+
+let is_function id = function
+ | CDEF_fundef (id', _, _, _) when Id.compare id id' = 0 -> true
+ | _ -> false
+
+let step (gstate, stack) =
+ let I_aux (instr_aux, (_, l)) = stack.top.instrs.(stack.top.pc) in
+ match instr_aux with
+ | I_decl _ ->
+ gstate, with_top stack (fun frame -> { frame with pc = frame.pc + 1 })
+
+ | I_init (_, id, (fragment, _)) ->
+ let vl = eval_fragment gstate stack.top.locals fragment in
+ gstate,
+ with_top stack (fun frame -> { frame with pc = frame.pc + 1; locals = Bindings.add id vl frame.locals })
+
+ | I_jump ((fragment, _), label) ->
+ let vl = eval_fragment gstate stack.top.locals fragment in
+ gstate,
+ begin match vl with
+ | V_bool true ->
+ with_top stack (fun frame -> { frame with pc = StringMap.find label frame.jump_table })
+ | V_bool false ->
+ with_top stack (fun frame -> { frame with pc = frame.pc + 1 })
+ | _ ->
+ failwith "Type error"
+ end
+
+ | I_funcall (clexp, _, id, cvals) ->
+ let args = List.map (fun (fragment, _) -> eval_fragment gstate stack.top.locals fragment) cvals in
+ let params, instrs =
+ match List.find_opt (is_function id) gstate.cdefs with
+ | Some (CDEF_fundef (_, _, params, instrs)) -> params, instrs
+ | _ -> failwith "Function not found"
+ in
+ gstate,
+ {
+ top = {
+ jump_table = make_jump_table instrs;
+ locals = List.fold_left2 (fun locals param arg -> Bindings.add param arg locals) Bindings.empty params args;
+ pc = 0;
+ instrs = Array.of_list instrs;
+ };
+ ret = (fun vl -> { stack.top with pc = stack.top.pc + 1 }) :: stack.ret
+ }
+
+ | I_goto label ->
+ gstate, with_top stack (fun frame -> { frame with pc = StringMap.find label frame.jump_table })
+
+ | _ -> raise (Reporting.err_unreachable l __POS__ "Unhandled instruction")
diff --git a/src/bytecode_util.ml b/src/bytecode_util.ml
index 6334210e..3ced48b6 100644
--- a/src/bytecode_util.ml
+++ b/src/bytecode_util.ml
@@ -67,6 +67,9 @@ let instr_number () =
let idecl ?loc:(l=Parse_ast.Unknown) ctyp id =
I_aux (I_decl (ctyp, id), (instr_number (), l))
+let ireset ?loc:(l=Parse_ast.Unknown) ctyp id =
+ I_aux (I_reset (ctyp, id), (instr_number (), l))
+
let iinit ?loc:(l=Parse_ast.Unknown) ctyp id cval =
I_aux (I_init (ctyp, id, cval), (instr_number (), l))
@@ -82,6 +85,9 @@ let iextern ?loc:(l=Parse_ast.Unknown) clexp id cvals =
let icopy l clexp cval =
I_aux (I_copy (clexp, cval), (instr_number (), l))
+let ialias l clexp cval =
+ I_aux (I_alias (clexp, cval), (instr_number (), l))
+
let iclear ?loc:(l=Parse_ast.Unknown) ctyp id =
I_aux (I_clear (ctyp, id), (instr_number (), l))
@@ -131,6 +137,77 @@ let rec frag_rename from_id to_id = function
| F_raw raw -> F_raw raw
| F_poly f -> F_poly (frag_rename from_id to_id f)
+let cval_rename from_id to_id (frag, ctyp) = (frag_rename from_id to_id frag, ctyp)
+
+let rec clexp_rename from_id to_id = function
+ | CL_id (id, ctyp) when Id.compare id from_id = 0 -> CL_id (to_id, ctyp)
+ | CL_id (id, ctyp) -> CL_id (id, ctyp)
+ | CL_field (clexp, field) ->
+ CL_field (clexp_rename from_id to_id clexp, field)
+ | CL_addr clexp ->
+ CL_addr (clexp_rename from_id to_id clexp)
+ | CL_tuple (clexp, n) ->
+ CL_tuple (clexp_rename from_id to_id clexp, n)
+ | CL_current_exception ctyp -> CL_current_exception ctyp
+ | CL_have_exception -> CL_have_exception
+
+let rec instr_rename from_id to_id (I_aux (instr, aux)) =
+ let instr = match instr with
+ | I_decl (ctyp, id) when Id.compare id from_id = 0 -> I_decl (ctyp, to_id)
+ | I_decl (ctyp, id) -> I_decl (ctyp, id)
+
+ | I_init (ctyp, id, cval) when Id.compare id from_id = 0 ->
+ I_init (ctyp, to_id, cval_rename from_id to_id cval)
+ | I_init (ctyp, id, cval) ->
+ I_init (ctyp, id, cval_rename from_id to_id cval)
+
+ | I_if (cval, then_instrs, else_instrs, ctyp2) ->
+ I_if (cval_rename from_id to_id cval,
+ List.map (instr_rename from_id to_id) then_instrs,
+ List.map (instr_rename from_id to_id) else_instrs,
+ ctyp2)
+
+ | I_jump (cval, label) -> I_jump (cval_rename from_id to_id cval, label)
+
+ | I_funcall (clexp, extern, id, args) ->
+ I_funcall (clexp_rename from_id to_id clexp, extern, id, List.map (cval_rename from_id to_id) args)
+
+ | I_copy (clexp, cval) -> I_copy (clexp_rename from_id to_id clexp, cval_rename from_id to_id cval)
+ | I_alias (clexp, cval) -> I_alias (clexp_rename from_id to_id clexp, cval_rename from_id to_id cval)
+
+ | I_clear (ctyp, id) when Id.compare id from_id = 0 -> I_clear (ctyp, to_id)
+ | I_clear (ctyp, id) -> I_clear (ctyp, id)
+
+ | I_return cval -> I_return (cval_rename from_id to_id cval)
+
+ | I_block instrs -> I_block (List.map (instr_rename from_id to_id) instrs)
+
+ | I_try_block instrs -> I_try_block (List.map (instr_rename from_id to_id) instrs)
+
+ | I_throw cval -> I_throw (cval_rename from_id to_id cval)
+
+ | I_comment str -> I_comment str
+
+ | I_raw str -> I_raw str
+
+ | I_label label -> I_label label
+
+ | I_goto label -> I_goto label
+
+ | I_undefined ctyp -> I_undefined ctyp
+
+ | I_match_failure -> I_match_failure
+
+ | I_reset (ctyp, id) when Id.compare id from_id = 0 -> I_reset (ctyp, to_id)
+ | I_reset (ctyp, id) -> I_reset (ctyp, id)
+
+ | I_reinit (ctyp, id, cval) when Id.compare id from_id = 0 ->
+ I_reinit (ctyp, to_id, cval_rename from_id to_id cval)
+ | I_reinit (ctyp, id, cval) ->
+ I_reinit (ctyp, id, cval_rename from_id to_id cval)
+ in
+ I_aux (instr, aux)
+
(**************************************************************************)
(* 1. Instruction pretty printer *)
(**************************************************************************)
@@ -175,12 +252,14 @@ and string_of_fragment' ?zencode:(zencode=true) f =
(* String representation of ctyps here is only for debugging and
intermediate language pretty-printer. *)
and string_of_ctyp = function
- | CT_int -> "mpz_t"
- | CT_bits true -> "bv_t(dec)"
- | CT_bits false -> "bv_t(inc)"
- | CT_bits64 (n, true) -> "uint64_t(" ^ string_of_int n ^ ", dec)"
- | CT_bits64 (n, false) -> "uint64_t(" ^ string_of_int n ^ ", int)"
- | CT_int64 -> "int64_t"
+ | CT_int -> "int"
+ | CT_lbits true -> "lbits(dec)"
+ | CT_lbits false -> "lbits(inc)"
+ | CT_fbits (n, true) -> "fbits(" ^ string_of_int n ^ ", dec)"
+ | CT_fbits (n, false) -> "fbits(" ^ string_of_int n ^ ", int)"
+ | CT_sbits true -> "sbits(dec)"
+ | CT_sbits false -> "sbits(inc)"
+ | CT_int64 -> "int64"
| CT_bit -> "bit"
| CT_unit -> "unit"
| CT_bool -> "bool"
@@ -197,12 +276,14 @@ and string_of_ctyp = function
(** This function is like string_of_ctyp, but recursively prints all
constructors in variants and structs. Used for debug output. *)
and full_string_of_ctyp = function
- | CT_int -> "mpz_t"
- | CT_bits true -> "bv_t(dec)"
- | CT_bits false -> "bv_t(inc)"
- | CT_bits64 (n, true) -> "uint64_t(" ^ string_of_int n ^ ", dec)"
- | CT_bits64 (n, false) -> "uint64_t(" ^ string_of_int n ^ ", int)"
- | CT_int64 -> "int64_t"
+ | CT_int -> "int"
+ | CT_lbits true -> "lbits(dec)"
+ | CT_lbits false -> "lbits(inc)"
+ | CT_fbits (n, true) -> "fbits(" ^ string_of_int n ^ ", dec)"
+ | CT_fbits (n, false) -> "fbits(" ^ string_of_int n ^ ", int)"
+ | CT_sbits true -> "sbits(dec)"
+ | CT_sbits false -> "sbits(inc)"
+ | CT_int64 -> "int64"
| CT_bit -> "bit"
| CT_unit -> "unit"
| CT_bool -> "bool"
@@ -222,7 +303,8 @@ and full_string_of_ctyp = function
| CT_poly -> "*"
let rec map_ctyp f = function
- | (CT_int | CT_int64 | CT_bits _ | CT_bits64 _ | CT_bit | CT_unit | CT_bool | CT_real | CT_string | CT_poly | CT_enum _) as ctyp -> f ctyp
+ | (CT_int | CT_int64 | CT_lbits _ | CT_fbits _ | CT_sbits _
+ | CT_bit | CT_unit | CT_bool | CT_real | CT_string | CT_poly | CT_enum _) as ctyp -> f ctyp
| CT_tup ctyps -> f (CT_tup (List.map (map_ctyp f) ctyps))
| CT_ref ctyp -> f (CT_ref (map_ctyp f ctyp))
| CT_vector (direction, ctyp) -> f (CT_vector (direction, map_ctyp f ctyp))
@@ -233,8 +315,9 @@ let rec map_ctyp f = function
let rec ctyp_equal ctyp1 ctyp2 =
match ctyp1, ctyp2 with
| CT_int, CT_int -> true
- | CT_bits d1, CT_bits d2 -> d1 = d2
- | CT_bits64 (m1, d1), CT_bits64 (m2, d2) -> m1 = m2 && d1 = d2
+ | CT_lbits d1, CT_lbits d2 -> d1 = d2
+ | CT_sbits d1, CT_sbits d2 -> d1 = d2
+ | CT_fbits (m1, d1), CT_fbits (m2, d2) -> m1 = m2 && d1 = d2
| CT_bit, CT_bit -> true
| CT_int64, CT_int64 -> true
| CT_unit, CT_unit -> true
@@ -271,8 +354,9 @@ let rec ctyp_unify ctyp1 ctyp2 =
let rec ctyp_suprema = function
| CT_int -> CT_int
- | CT_bits d -> CT_bits d
- | CT_bits64 (_, d) -> CT_bits d
+ | CT_lbits d -> CT_lbits d
+ | CT_fbits (_, d) -> CT_lbits d
+ | CT_sbits d -> CT_lbits d
| CT_int64 -> CT_int
| CT_unit -> CT_unit
| CT_bool -> CT_bool
@@ -298,7 +382,7 @@ let rec ctyp_ids = function
IdSet.add id (List.fold_left (fun ids (_, ctyp) -> IdSet.union (ctyp_ids ctyp) ids) IdSet.empty ctors)
| CT_tup ctyps -> List.fold_left (fun ids ctyp -> IdSet.union (ctyp_ids ctyp) ids) IdSet.empty ctyps
| CT_vector (_, ctyp) | CT_list ctyp | CT_ref ctyp -> ctyp_ids ctyp
- | CT_int | CT_int64 | CT_bits _ | CT_bits64 _ | CT_unit
+ | CT_int | CT_int64 | CT_lbits _ | CT_fbits _ | CT_sbits _ | CT_unit
| CT_bool | CT_real | CT_bit | CT_string | CT_poly -> IdSet.empty
let rec unpoly = function
@@ -310,7 +394,7 @@ let rec unpoly = function
| f -> f
let rec is_polymorphic = function
- | CT_int | CT_int64 | CT_bits _ | CT_bits64 _ | CT_bit | CT_unit | CT_bool | CT_real | CT_string -> false
+ | CT_int | CT_int64 | CT_lbits _ | CT_fbits _ | CT_sbits _ | CT_bit | CT_unit | CT_bool | CT_real | CT_string -> false
| CT_tup ctyps -> List.exists is_polymorphic ctyps
| CT_enum _ -> false
| CT_struct (_, ctors) | CT_variant (_, ctors) -> List.exists (fun (_, ctyp) -> is_polymorphic ctyp) ctors
@@ -370,6 +454,8 @@ let rec pp_instr ?short:(short=false) (I_aux (instr, aux)) =
string (string_of_id f |> Util.green |> Util.clear) ^^ parens (separate_map (string ", ") pp_cval args) ]
| I_copy (clexp, cval) ->
separate space [pp_clexp clexp; string "="; pp_cval cval]
+ | I_alias (clexp, cval) ->
+ pp_keyword "alias" ^^ separate space [pp_clexp clexp; string "="; pp_cval cval]
| I_clear (ctyp, id) ->
pp_keyword "kill" ^^ pp_id id ^^ string " : " ^^ pp_ctyp ctyp
| I_return cval ->
@@ -497,6 +583,7 @@ let instr_deps = function
| I_jump (cval, label) -> cval_deps cval, NS.singleton (G_label label)
| I_funcall (clexp, _, _, cvals) -> List.fold_left NS.union NS.empty (List.map cval_deps cvals), clexp_deps clexp
| I_copy (clexp, cval) -> cval_deps cval, clexp_deps clexp
+ | I_alias (clexp, cval) -> cval_deps cval, clexp_deps clexp
| I_clear (_, id) -> NS.singleton (G_id id), NS.singleton (G_id id)
| I_throw cval | I_return cval -> cval_deps cval, NS.empty
| I_block _ | I_try_block _ -> NS.empty, NS.empty
@@ -621,6 +708,7 @@ let rec map_instr_ctyp f (I_aux (instr, aux)) =
| I_funcall (clexp, extern, id, cvals) ->
I_funcall (map_clexp_ctyp f clexp, extern, id, List.map (fun (frag, ctyp) -> frag, f ctyp) cvals)
| I_copy (clexp, (frag, ctyp)) -> I_copy (map_clexp_ctyp f clexp, (frag, f ctyp))
+ | I_alias (clexp, (frag, ctyp)) -> I_alias (map_clexp_ctyp f clexp, (frag, f ctyp))
| I_clear (ctyp, id) -> I_clear (f ctyp, id)
| I_return (frag, ctyp) -> I_return (frag, f ctyp)
| I_block instrs -> I_block (List.map (map_instr_ctyp f) instrs)
@@ -637,7 +725,7 @@ let rec map_instr_ctyp f (I_aux (instr, aux)) =
let rec map_instr f (I_aux (instr, aux)) =
let instr = match instr with
| I_decl _ | I_init _ | I_reset _ | I_reinit _
- | I_funcall _ | I_copy _ | I_clear _ | I_jump _ | I_throw _ | I_return _
+ | I_funcall _ | I_copy _ | I_alias _ | I_clear _ | I_jump _ | I_throw _ | I_return _
| I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure | I_undefined _ -> instr
| I_if (cval, instrs1, instrs2, ctyp) ->
I_if (cval, List.map (map_instr f) instrs1, List.map (map_instr f) instrs2, ctyp)
@@ -679,9 +767,52 @@ let rec map_instrs f (I_aux (instr, aux)) =
| I_decl _ | I_init _ | I_reset _ | I_reinit _ -> instr
| I_if (cval, instrs1, instrs2, ctyp) ->
I_if (cval, f (List.map (map_instrs f) instrs1), f (List.map (map_instrs f) instrs2), ctyp)
- | I_funcall _ | I_copy _ | I_clear _ | I_jump _ | I_throw _ | I_return _ -> instr
+ | I_funcall _ | I_copy _ | I_alias _ | I_clear _ | I_jump _ | I_throw _ | I_return _ -> instr
| I_block instrs -> I_block (f (List.map (map_instrs f) instrs))
| I_try_block instrs -> I_try_block (f (List.map (map_instrs f) instrs))
| I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure | I_undefined _ -> instr
in
I_aux (instr, aux)
+
+let rec instr_ids (I_aux (instr, _)) =
+ let reads, writes = instr_deps instr in
+ let get_id = function
+ | G_id id -> Some id
+ | _ -> None
+ in
+ NS.elements reads @ NS.elements writes
+ |> List.map get_id
+ |> Util.option_these
+ |> IdSet.of_list
+
+let rec instr_reads (I_aux (instr, _)) =
+ let reads, _ = instr_deps instr in
+ let get_id = function
+ | G_id id -> Some id
+ | _ -> None
+ in
+ NS.elements reads
+ |> List.map get_id
+ |> Util.option_these
+ |> IdSet.of_list
+
+let rec instr_writes (I_aux (instr, _)) =
+ let _, writes = instr_deps instr in
+ let get_id = function
+ | G_id id -> Some id
+ | _ -> None
+ in
+ NS.elements writes
+ |> List.map get_id
+ |> Util.option_these
+ |> IdSet.of_list
+
+let rec filter_instrs f instrs =
+ let filter_instrs' = function
+ | I_aux (I_block instrs, aux) -> I_aux (I_block (filter_instrs f instrs), aux)
+ | I_aux (I_try_block instrs, aux) -> I_aux (I_try_block (filter_instrs f instrs), aux)
+ | I_aux (I_if (cval, instrs1, instrs2, ctyp), aux) ->
+ I_aux (I_if (cval, filter_instrs f instrs1, filter_instrs f instrs2, ctyp), aux)
+ | instr -> instr
+ in
+ List.filter f (List.map filter_instrs' instrs)
diff --git a/src/c_backend.ml b/src/c_backend.ml
index d825bbae..65702764 100644
--- a/src/c_backend.ml
+++ b/src/c_backend.ml
@@ -61,7 +61,8 @@ open Anf
module Big_int = Nat_big_num
let c_verbosity = ref 0
-let opt_ddump_flow_graphs = ref false
+let opt_debug_flow_graphs = ref false
+let opt_debug_function = ref ""
let opt_trace = ref false
let opt_static = ref false
let opt_no_main = ref false
@@ -70,12 +71,14 @@ let opt_no_main = ref false
let optimize_primops = ref false
let optimize_hoist_allocations = ref false
let optimize_struct_updates = ref false
+let optimize_alias = ref false
+let optimize_experimental = ref false
let c_debug str =
if !c_verbosity > 0 then prerr_endline (Lazy.force str) else ()
let c_error ?loc:(l=Parse_ast.Unknown) message =
- raise (Reporting_basic.err_general l ("\nC backend: " ^ message))
+ raise (Reporting.err_general l ("\nC backend: " ^ message))
let zencode_id = function
| Id_aux (Id str, l) -> Id_aux (Id (Util.zencode_string str), l)
@@ -88,6 +91,13 @@ let zencode_id = function
let max_int64 = Big_int.of_int64 Int64.max_int
let min_int64 = Big_int.of_int64 Int64.min_int
+(** The context type contains two type-checking
+ environments. ctx.local_env contains the closest typechecking
+ environment, usually from the expression we are compiling, whereas
+ ctx.tc_env is the global type checking environment from
+ type-checking the entire AST. We also keep track of local variables
+ in ctx.locals, so we know when their type changes due to flow
+ typing. *)
type ctx =
{ records : (ctyp Bindings.t) Bindings.t;
enums : IdSet.t Bindings.t;
@@ -114,97 +124,112 @@ let initial_ctx env =
optimize_z3 = true;
}
-(** Convert a sail type into a C-type **)
+(** Convert a sail type into a C-type. This function can be quite
+ slow, because it uses ctx.local_env and Z3 to analyse the Sail
+ types and attempts to fit them into the smallest possible C
+ types, provided ctx.optimize_z3 is true (default) **)
let rec ctyp_of_typ ctx typ =
let Typ_aux (typ_aux, l) as typ = Env.expand_synonyms ctx.tc_env typ in
match typ_aux with
- | Typ_id id when string_of_id id = "bit" -> CT_bit
- | Typ_id id when string_of_id id = "bool" -> CT_bool
- | Typ_id id when string_of_id id = "int" -> CT_int
- | Typ_id id when string_of_id id = "nat" -> CT_int
+ | Typ_id id when string_of_id id = "bit" -> CT_bit
+ | Typ_id id when string_of_id id = "bool" -> CT_bool
+ | Typ_id id when string_of_id id = "int" -> CT_int
+ | Typ_id id when string_of_id id = "nat" -> CT_int
+ | Typ_id id when string_of_id id = "unit" -> CT_unit
+ | Typ_id id when string_of_id id = "string" -> CT_string
+ | Typ_id id when string_of_id id = "real" -> CT_real
+
+ | Typ_app (id, _) when string_of_id id = "atom_bool" -> CT_bool
+
| Typ_app (id, _) when string_of_id id = "range" || string_of_id id = "atom" ->
- begin
- match destruct_range Env.empty typ with
- | None -> assert false (* Checked if range type in guard *)
- | Some (kids, constr, n, m) ->
- match nexp_simp n, nexp_simp m with
- | Nexp_aux (Nexp_constant n, _), Nexp_aux (Nexp_constant m, _)
- when Big_int.less_equal min_int64 n && Big_int.less_equal m max_int64 ->
+ begin match destruct_range Env.empty typ with
+ | None -> assert false (* Checked if range type in guard *)
+ | Some (kids, constr, n, m) ->
+ match nexp_simp n, nexp_simp m with
+ | Nexp_aux (Nexp_constant n, _), Nexp_aux (Nexp_constant m, _)
+ when Big_int.less_equal min_int64 n && Big_int.less_equal m max_int64 ->
+ CT_int64
+ | n, m when ctx.optimize_z3 ->
+ if prove ctx.local_env (nc_lteq (nconstant min_int64) n) && prove ctx.local_env (nc_lteq m (nconstant max_int64)) then
CT_int64
- | n, m when ctx.optimize_z3 ->
- if prove ctx.local_env (nc_lteq (nconstant min_int64) n) && prove ctx.local_env (nc_lteq m (nconstant max_int64)) then
- CT_int64
- else
- CT_int
- | _ -> CT_int
+ else
+ CT_int
+ | _ -> CT_int
end
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ typ, _)]) when string_of_id id = "list" ->
+ | Typ_app (id, [A_aux (A_typ typ, _)]) when string_of_id id = "list" ->
CT_list (ctyp_of_typ ctx typ)
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp n, _);
- Typ_arg_aux (Typ_arg_order ord, _);
- Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id vtyp_id, _)), _)])
+ (* When converting a sail bitvector type into C, we have three options in order of efficiency:
+ - If the length is obviously static and smaller than 64, use the fixed bits type (aka uint64_t), fbits.
+ - If the length is less than 64, then use a small bits type, sbits.
+ - If the length may be larger than 64, use a large bits type lbits. *)
+ | Typ_app (id, [A_aux (A_nexp n, _);
+ A_aux (A_order ord, _);
+ A_aux (A_typ (Typ_aux (Typ_id vtyp_id, _)), _)])
when string_of_id id = "vector" && string_of_id vtyp_id = "bit" ->
- begin
- let direction = match ord with Ord_aux (Ord_dec, _) -> true | Ord_aux (Ord_inc, _) -> false | _ -> assert false in
- match nexp_simp n with
- | Nexp_aux (Nexp_constant n, _) when Big_int.less_equal n (Big_int.of_int 64) -> CT_bits64 (Big_int.to_int n, direction)
- | _ when not ctx.optimize_z3 -> CT_bits direction
- | _ -> CT_bits direction
- (* This is extremely slow :(
- match solve ctx.local_env n with
- | Some n when Big_int.less_equal n (Big_int.of_int 64) -> CT_bits64 (Big_int.to_int n, direction)
- | _ -> CT_bits direction
- *)
+ let direction = match ord with Ord_aux (Ord_dec, _) -> true | Ord_aux (Ord_inc, _) -> false | _ -> assert false in
+ begin match nexp_simp n with
+ | Nexp_aux (Nexp_constant n, _) when Big_int.less_equal n (Big_int.of_int 64) -> CT_fbits (Big_int.to_int n, direction)
+ | n when ctx.optimize_z3 && prove ctx.local_env (nc_lteq n (nint 64)) -> CT_sbits direction
+ | _ -> CT_lbits direction
end
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp n, _);
- Typ_arg_aux (Typ_arg_order ord, _);
- Typ_arg_aux (Typ_arg_typ typ, _)])
+
+ | Typ_app (id, [A_aux (A_nexp n, _);
+ A_aux (A_order ord, _);
+ A_aux (A_typ typ, _)])
when string_of_id id = "vector" ->
let direction = match ord with Ord_aux (Ord_dec, _) -> true | Ord_aux (Ord_inc, _) -> false | _ -> assert false in
CT_vector (direction, ctyp_of_typ ctx typ)
- | Typ_id id when string_of_id id = "unit" -> CT_unit
- | Typ_id id when string_of_id id = "string" -> CT_string
- | Typ_id id when string_of_id id = "real" -> CT_real
-
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ typ, _)]) when string_of_id id = "register" ->
+ | Typ_app (id, [A_aux (A_typ typ, _)]) when string_of_id id = "register" ->
CT_ref (ctyp_of_typ ctx typ)
- | Typ_id id | Typ_app (id, _) when Bindings.mem id ctx.records -> CT_struct (id, Bindings.find id ctx.records |> Bindings.bindings)
+ | Typ_id id | Typ_app (id, _) when Bindings.mem id ctx.records -> CT_struct (id, Bindings.find id ctx.records |> Bindings.bindings)
| Typ_id id | Typ_app (id, _) when Bindings.mem id ctx.variants -> CT_variant (id, Bindings.find id ctx.variants |> Bindings.bindings)
| Typ_id id when Bindings.mem id ctx.enums -> CT_enum (id, Bindings.find id ctx.enums |> IdSet.elements)
| Typ_tup typs -> CT_tup (List.map (ctyp_of_typ ctx) typs)
| Typ_exist _ when ctx.optimize_z3 ->
- (* Use Type_check.destruct_exist when optimising with z3, to ensure that we
- don't cause any type variable clashes in local_env. *)
- begin match destruct_exist ctx.local_env typ with
+ (* Use Type_check.destruct_exist when optimising with z3, to
+ ensure that we don't cause any type variable clashes in
+ local_env, and that we can optimize the existential based upon
+ it's constraints. *)
+ begin match destruct_exist (Env.expand_synonyms ctx.local_env typ) with
| Some (kids, nc, typ) ->
let env = add_existential l kids nc ctx.local_env in
ctyp_of_typ { ctx with local_env = env } typ
- | None -> c_error "Existential cannot be destructured. This should be impossible!"
+ | None -> raise (Reporting.err_unreachable l __POS__ "Existential cannot be destructured!")
end
| Typ_exist (_, _, typ) -> ctyp_of_typ ctx typ
- | Typ_var kid -> CT_poly (* c_error ~loc:l ("Polymorphic type encountered " ^ string_of_kid kid) *)
+ | Typ_var kid -> CT_poly
| _ -> c_error ~loc:l ("No C type for type " ^ string_of_typ typ)
let rec is_stack_ctyp ctyp = match ctyp with
- | CT_bits64 _ | CT_int64 | CT_bit | CT_unit | CT_bool | CT_enum _ -> true
- | CT_bits _ | CT_int | CT_real | CT_string | CT_list _ | CT_vector _ -> false
+ | CT_fbits _ | CT_sbits _ | CT_int64 | CT_bit | CT_unit | CT_bool | CT_enum _ -> true
+ | CT_lbits _ | CT_int | CT_real | CT_string | CT_list _ | CT_vector _ -> false
| CT_struct (_, fields) -> List.for_all (fun (_, ctyp) -> is_stack_ctyp ctyp) fields
- | CT_variant (_, ctors) -> false (* List.for_all (fun (_, ctyp) -> is_stack_ctyp ctyp) ctors *) (*FIXME*)
+ | CT_variant (_, ctors) -> false (* List.for_all (fun (_, ctyp) -> is_stack_ctyp ctyp) ctors *) (* FIXME *)
| CT_tup ctyps -> List.for_all is_stack_ctyp ctyps
| CT_ref ctyp -> true
| CT_poly -> true
let is_stack_typ ctx typ = is_stack_ctyp (ctyp_of_typ ctx typ)
+let is_fbits_typ ctx typ =
+ match ctyp_of_typ ctx typ with
+ | CT_fbits _ -> true
+ | _ -> false
+
+let is_sbits_typ ctx typ =
+ match ctyp_of_typ ctx typ with
+ | CT_sbits _ -> true
+ | _ -> false
+
let ctor_bindings = List.fold_left (fun map (id, ctyp) -> Bindings.add id ctyp map) Bindings.empty
(**************************************************************************)
@@ -235,15 +260,15 @@ let hex_char =
let literal_to_fragment (L_aux (l_aux, _) as lit) =
match l_aux with
| L_num n when Big_int.less_equal min_int64 n && Big_int.less_equal n max_int64 ->
- Some (F_lit (V_int n))
+ Some (F_lit (V_int n), CT_int64)
| L_hex str when String.length str <= 16 ->
let padding = 16 - String.length str in
let padding = Util.list_init padding (fun _ -> Sail2_values.B0) in
let content = Util.string_to_list str |> List.map hex_char |> List.concat in
- Some (F_lit (V_bits (padding @ content)))
- | L_unit -> Some (F_lit V_unit)
- | L_true -> Some (F_lit (V_bool true))
- | L_false -> Some (F_lit (V_bool false))
+ Some (F_lit (V_bits (padding @ content)), CT_fbits (String.length str * 4, true))
+ | L_unit -> Some (F_lit V_unit, CT_unit)
+ | L_true -> Some (F_lit (V_bool true), CT_bool)
+ | L_false -> Some (F_lit (V_bool false), CT_bool)
| _ -> None
let c_literals ctx =
@@ -251,7 +276,7 @@ let c_literals ctx =
| AV_lit (lit, typ) as v when is_stack_ctyp (ctyp_of_typ { ctx with local_env = env } typ) ->
begin
match literal_to_fragment lit with
- | Some frag -> AV_C_fragment (frag, typ)
+ | Some (frag, ctyp) -> AV_C_fragment (frag, typ, ctyp)
| None -> v
end
| AV_tuple avals -> AV_tuple (List.map (c_literal env l) avals)
@@ -286,34 +311,45 @@ let rec c_aval ctx = function
| AV_lit (lit, typ) as v ->
begin
match literal_to_fragment lit with
- | Some frag -> AV_C_fragment (frag, typ)
+ | Some (frag, ctyp) -> AV_C_fragment (frag, typ, ctyp)
| None -> v
end
- | AV_C_fragment (str, typ) -> AV_C_fragment (str, typ)
+ | AV_C_fragment (str, typ, ctyp) -> AV_C_fragment (str, typ, ctyp)
(* An id can be converted to a C fragment if it's type can be
stack-allocated. *)
| AV_id (id, lvar) as v ->
begin
match lvar with
- | Local (_, typ) when is_stack_typ ctx typ ->
- begin
- try
- (* We need to check that id's type hasn't changed due to flow typing *)
- let _, ctyp = Bindings.find id ctx.locals in
- if is_stack_ctyp ctyp then
- AV_C_fragment (F_id id, typ)
- else
- v (* id's type went from heap -> stack due to flow typing, so it's really still heap allocated! *)
- with
- Not_found -> failwith ("could not find " ^ string_of_id id ^ " in local variables")
- end
+ | Local (_, typ) ->
+ let ctyp = ctyp_of_typ ctx typ in
+ if is_stack_ctyp ctyp then
+ begin
+ try
+ (* We need to check that id's type hasn't changed due to flow typing *)
+ let _, ctyp' = Bindings.find id ctx.locals in
+ if ctyp_equal ctyp ctyp' then
+ AV_C_fragment (F_id id, typ, ctyp)
+ else
+ (* id's type changed due to flow
+ typing, so it's really still heap allocated! *)
+ v
+ with
+ (* Hack: Assuming global letbindings don't change from flow typing... *)
+ Not_found -> AV_C_fragment (F_id id, typ, ctyp)
+ end
+ else
+ v
| Register (_, _, typ) when is_stack_typ ctx typ ->
- AV_C_fragment (F_id id, typ)
+ let ctyp = ctyp_of_typ ctx typ in
+ if is_stack_ctyp ctyp then
+ AV_C_fragment (F_id id, typ, ctyp)
+ else
+ v
| _ -> v
end
| AV_vector (v, typ) when is_bitvector v && List.length v <= 64 ->
let bitstring = F_lit (V_bits (List.map value_of_aval_bit v)) in
- AV_C_fragment (bitstring, typ)
+ AV_C_fragment (bitstring, typ, CT_fbits (List.length v, true))
| AV_tuple avals -> AV_tuple (List.map (c_aval ctx) avals)
| aval -> aval
@@ -322,7 +358,7 @@ let is_c_fragment = function
| _ -> false
let c_fragment = function
- | AV_C_fragment (frag, _) -> frag
+ | AV_C_fragment (frag, _, _) -> frag
| _ -> assert false
let v_mask_lower i = F_lit (V_bits (Util.list_init i (fun _ -> Sail2_values.B1)))
@@ -339,9 +375,10 @@ let rec analyze_functions ctx f (AE_aux (aexp, env, l)) =
| AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, aval, analyze_functions ctx f aexp)
- | AE_let (mut, id, typ1, aexp1, aexp2, typ2) ->
+ | AE_let (mut, id, typ1, aexp1, (AE_aux (_, env2, _) as aexp2), typ2) ->
let aexp1 = analyze_functions ctx f aexp1 in
- let ctyp1 = ctyp_of_typ ctx typ1 in
+ (* Use aexp2's environment because it will contain constraints for id *)
+ let ctyp1 = ctyp_of_typ { ctx with local_env = env2 } typ1 in
let ctx = { ctx with locals = Bindings.add id (mut, ctyp1) ctx.locals } in
AE_let (mut, id, typ1, aexp1, analyze_functions ctx f aexp2, typ2)
@@ -357,11 +394,14 @@ let rec analyze_functions ctx f (AE_aux (aexp, env, l)) =
let aexp2 = analyze_functions ctx f aexp2 in
let aexp3 = analyze_functions ctx f aexp3 in
let aexp4 = analyze_functions ctx f aexp4 in
+ (* Currently we assume that loop indexes are always safe to put into an int64 *)
+ let ctx = { ctx with locals = Bindings.add id (Immutable, CT_int64) ctx.locals } in
AE_for (id, aexp1, aexp2, aexp3, order, aexp4)
| AE_case (aval, cases, typ) ->
- let analyze_case (pat, aexp1, aexp2) =
+ let analyze_case (AP_aux (_, env, _) as pat, aexp1, aexp2) =
let pat_bindings = Bindings.bindings (apat_types pat) in
+ let ctx = { ctx with local_env = env } in
let ctx =
List.fold_left (fun ctx (id, typ) -> { ctx with locals = Bindings.add id (Immutable, ctyp_of_typ ctx typ) ctx.locals }) ctx pat_bindings
in
@@ -387,85 +427,138 @@ let analyze_primop' ctx id args typ =
c_debug (lazy ("Analyzing primop " ^ extern ^ "(" ^ Util.string_of_list ", " (fun aval -> Pretty_print_sail.to_string (pp_aval aval)) args ^ ")"));
match extern, args with
- | "eq_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
- AE_val (AV_C_fragment (F_op (v1, "==", v2), typ))
+ | "eq_bits", [AV_C_fragment (v1, _, CT_fbits _); AV_C_fragment (v2, _, _)] ->
+ AE_val (AV_C_fragment (F_op (v1, "==", v2), typ, CT_bool))
+ | "eq_bits", [AV_C_fragment (v1, _, CT_sbits _); AV_C_fragment (v2, _, _)] ->
+ AE_val (AV_C_fragment (F_call ("eq_sbits", [v1; v2]), typ, CT_bool))
- | "neq_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
- AE_val (AV_C_fragment (F_op (v1, "!=", v2), typ))
+ | "neq_bits", [AV_C_fragment (v1, _, CT_fbits _); AV_C_fragment (v2, _, _)] ->
+ AE_val (AV_C_fragment (F_op (v1, "!=", v2), typ, CT_bool))
+ | "neq_bits", [AV_C_fragment (v1, _, CT_sbits _); AV_C_fragment (v2, _, _)] ->
+ AE_val (AV_C_fragment (F_call ("neq_sbits", [v1; v2]), typ, CT_bool))
- | "eq_int", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
- AE_val (AV_C_fragment (F_op (v1, "==", v2), typ))
+ | "eq_int", [AV_C_fragment (v1, typ1, _); AV_C_fragment (v2, typ2, _)] ->
+ AE_val (AV_C_fragment (F_op (v1, "==", v2), typ, CT_bool))
| "zeros", [_] ->
begin match destruct_vector ctx.tc_env typ with
| Some (Nexp_aux (Nexp_constant n, _), _, Typ_aux (Typ_id id, _))
when string_of_id id = "bit" && Big_int.less_equal n (Big_int.of_int 64) ->
- AE_val (AV_C_fragment (F_raw "0x0", typ))
+ AE_val (AV_C_fragment (F_raw "0x0", typ, CT_fbits (Big_int.to_int n, true)))
| _ -> no_change
end
- | "gteq", [AV_C_fragment (v1, _); AV_C_fragment (v2, _)] ->
- AE_val (AV_C_fragment (F_op (v1, ">=", v2), typ))
+ | "gteq", [AV_C_fragment (v1, _, _); AV_C_fragment (v2, _, _)] ->
+ AE_val (AV_C_fragment (F_op (v1, ">=", v2), typ, CT_bool))
- | "xor_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
- AE_val (AV_C_fragment (F_op (v1, "^", v2), typ))
+ | "xor_bits", [AV_C_fragment (v1, _, (CT_fbits _ as ctyp)); AV_C_fragment (v2, _, CT_fbits _)] ->
+ AE_val (AV_C_fragment (F_op (v1, "^", v2), typ, ctyp))
+ | "xor_bits", [AV_C_fragment (v1, _, (CT_sbits _ as ctyp)); AV_C_fragment (v2, _, CT_sbits _)] ->
+ AE_val (AV_C_fragment (F_call ("xor_sbits", [v1; v2]), typ, ctyp))
- | "or_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
- AE_val (AV_C_fragment (F_op (v1, "|", v2), typ))
+ | "or_bits", [AV_C_fragment (v1, _, (CT_fbits _ as ctyp)); AV_C_fragment (v2, _, CT_fbits _)] ->
+ AE_val (AV_C_fragment (F_op (v1, "|", v2), typ, ctyp))
- | "and_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
- AE_val (AV_C_fragment (F_op (v1, "&", v2), typ))
+ | "and_bits", [AV_C_fragment (v1, _, (CT_fbits _ as ctyp)); AV_C_fragment (v2, _, CT_fbits _)] ->
+ AE_val (AV_C_fragment (F_op (v1, "&", v2), typ, ctyp))
- | "not_bits", [AV_C_fragment (v, _)] ->
+ | "not_bits", [AV_C_fragment (v, _, ctyp)] ->
begin match destruct_vector ctx.tc_env typ with
| Some (Nexp_aux (Nexp_constant n, _), _, Typ_aux (Typ_id id, _))
when string_of_id id = "bit" && Big_int.less_equal n (Big_int.of_int 64) ->
- AE_val (AV_C_fragment (F_op (F_unary ("~", v), "&", v_mask_lower (Big_int.to_int n)), typ))
+ AE_val (AV_C_fragment (F_op (F_unary ("~", v), "&", v_mask_lower (Big_int.to_int n)), typ, ctyp))
| _ -> no_change
end
- | "vector_subrange", [AV_C_fragment (vec, _); AV_C_fragment (f, _); AV_C_fragment (t, _)] when is_stack_typ ctx typ ->
+ | "vector_subrange", [AV_C_fragment (vec, _, CT_fbits _); AV_C_fragment (f, _, _); AV_C_fragment (t, _, _)]
+ when is_fbits_typ ctx typ ->
let len = F_op (f, "-", F_op (t, "-", v_one)) in
- AE_val (AV_C_fragment (F_op (F_call ("safe_rshift", [F_raw "UINT64_MAX"; F_op (v_int 64, "-", len)]), "&", F_op (vec, ">>", t)), typ))
+ AE_val (AV_C_fragment (F_op (F_call ("safe_rshift", [F_raw "UINT64_MAX"; F_op (v_int 64, "-", len)]), "&", F_op (vec, ">>", t)),
+ typ,
+ ctyp_of_typ ctx typ))
- | "vector_access", [AV_C_fragment (vec, _); AV_C_fragment (n, _)] ->
- AE_val (AV_C_fragment (F_op (v_one, "&", F_op (vec, ">>", n)), typ))
+ | "vector_access", [AV_C_fragment (vec, _, CT_fbits _); AV_C_fragment (n, _, _)] ->
+ AE_val (AV_C_fragment (F_op (v_one, "&", F_op (vec, ">>", n)), typ, CT_bit))
- | "eq_bit", [AV_C_fragment (a, _); AV_C_fragment (b, _)] ->
- AE_val (AV_C_fragment (F_op (a, "==", b), typ))
+ | "eq_bit", [AV_C_fragment (a, _, _); AV_C_fragment (b, _, _)] ->
+ AE_val (AV_C_fragment (F_op (a, "==", b), typ, CT_bool))
- | "slice", [AV_C_fragment (vec, _); AV_C_fragment (start, _); AV_C_fragment (len, _)] ->
- AE_val (AV_C_fragment (F_op (F_call ("safe_rshift", [F_raw "UINT64_MAX"; F_op (v_int 64, "-", len)]), "&", F_op (vec, ">>", start)), typ))
+ | "slice", [AV_C_fragment (vec, _, CT_fbits _); AV_C_fragment (start, _, _); AV_C_fragment (len, _, _)]
+ when is_fbits_typ ctx typ ->
+ AE_val (AV_C_fragment (F_op (F_call ("safe_rshift", [F_raw "UINT64_MAX"; F_op (v_int 64, "-", len)]), "&", F_op (vec, ">>", start)),
+ typ,
+ ctyp_of_typ ctx typ))
- | "undefined_bit", _ ->
- AE_val (AV_C_fragment (F_lit (V_bit Sail2_values.B0), typ))
+ | "slice", [AV_C_fragment (vec, _, CT_fbits _); AV_C_fragment (start, _, _); AV_C_fragment (len, _, _)]
+ when is_sbits_typ ctx typ ->
+ AE_val (AV_C_fragment (F_call ("sslice", [vec; start; len]), typ, ctyp_of_typ ctx typ))
- | "undefined_vector", [AV_C_fragment (len, _); _] ->
+ | "undefined_bit", _ ->
+ AE_val (AV_C_fragment (F_lit (V_bit Sail2_values.B0), typ, CT_bit))
+
+ (* Optimized routines for all combinations of fixed and small bits
+ appends, where the result is guaranteed to be smaller than 64. *)
+ | "append", [AV_C_fragment (vec1, _, CT_fbits (0, ord1)); AV_C_fragment (vec2, _, CT_fbits (n2, ord2)) as v2]
+ when ord1 = ord2 ->
+ AE_val v2
+ | "append", [AV_C_fragment (vec1, _, CT_fbits (n1, ord1)); AV_C_fragment (vec2, _, CT_fbits (n2, ord2))]
+ when ord1 = ord2 && n1 + n2 <= 64 ->
+ AE_val (AV_C_fragment (F_op (F_op (vec1, "<<", v_int n2), "|", vec2), typ, CT_fbits (n1 + n2, ord1)))
+
+ | "append", [AV_C_fragment (vec1, _, CT_sbits ord1); AV_C_fragment (vec2, _, CT_fbits (n2, ord2))]
+ when ord1 = ord2 && is_sbits_typ ctx typ ->
+ AE_val (AV_C_fragment (F_call ("append_sf", [vec1; vec2; v_int n2]), typ, ctyp_of_typ ctx typ))
+
+ | "append", [AV_C_fragment (vec1, _, CT_fbits (n1, ord1)); AV_C_fragment (vec2, _, CT_sbits ord2)]
+ when ord1 = ord2 && is_sbits_typ ctx typ ->
+ AE_val (AV_C_fragment (F_call ("append_fs", [vec1; v_int n1; vec2]), typ, ctyp_of_typ ctx typ))
+
+ | "append", [AV_C_fragment (vec1, _, CT_sbits ord1); AV_C_fragment (vec2, _, CT_sbits ord2)]
+ when ord1 = ord2 && is_sbits_typ ctx typ ->
+ AE_val (AV_C_fragment (F_call ("append_ss", [vec1; vec2]), typ, ctyp_of_typ ctx typ))
+
+ | "undefined_vector", [AV_C_fragment (len, _, _); _] ->
begin match destruct_vector ctx.tc_env typ with
| Some (Nexp_aux (Nexp_constant n, _), _, Typ_aux (Typ_id id, _))
when string_of_id id = "bit" && Big_int.less_equal n (Big_int.of_int 64) ->
- AE_val (AV_C_fragment (F_lit (V_bit Sail2_values.B0), typ))
+ AE_val (AV_C_fragment (F_lit (V_bit Sail2_values.B0), typ, ctyp_of_typ ctx typ))
| _ -> no_change
end
- | "sail_uint", [AV_C_fragment (frag, vtyp)] ->
+ | "sail_unsigned", [AV_C_fragment (frag, vtyp, _)] ->
begin match destruct_vector ctx.tc_env vtyp with
| Some (Nexp_aux (Nexp_constant n, _), _, _)
when Big_int.less_equal n (Big_int.of_int 63) && is_stack_typ ctx typ ->
- AE_val (AV_C_fragment (frag, typ))
+ AE_val (AV_C_fragment (F_call ("fast_unsigned", [frag]), typ, ctyp_of_typ ctx typ))
| _ -> no_change
end
- | "replicate_bits", [AV_C_fragment (vec, vtyp); AV_C_fragment (times, _)] ->
+ | "add_int", [AV_C_fragment (op1, _, _); AV_C_fragment (op2, _, _)] ->
+ begin match destruct_range Env.empty typ with
+ | None -> no_change
+ | Some (kids, constr, n, m) ->
+ match nexp_simp n, nexp_simp m with
+ | Nexp_aux (Nexp_constant n, _), Nexp_aux (Nexp_constant m, _)
+ when Big_int.less_equal min_int64 n && Big_int.less_equal m max_int64 ->
+ AE_val (AV_C_fragment (F_op (op1, "+", op2), typ, CT_int64))
+ | n, m when prove ctx.local_env (nc_lteq (nconstant min_int64) n) && prove ctx.local_env (nc_lteq m (nconstant max_int64)) ->
+ AE_val (AV_C_fragment (F_op (op1, "+", op2), typ, CT_int64))
+ | _ -> no_change
+ end
+
+ | "neg_int", [AV_C_fragment (frag, _, _)] ->
+ AE_val (AV_C_fragment (F_op (v_int 0, "-", frag), typ, CT_int64))
+
+ | "replicate_bits", [AV_C_fragment (vec, vtyp, _); AV_C_fragment (times, _, _)] ->
begin match destruct_vector ctx.tc_env typ, destruct_vector ctx.tc_env vtyp with
| Some (Nexp_aux (Nexp_constant n, _), _, _), Some (Nexp_aux (Nexp_constant m, _), _, _)
when Big_int.less_equal n (Big_int.of_int 64) ->
- AE_val (AV_C_fragment (F_call ("fast_replicate_bits", [F_lit (V_int m); vec; times]), typ))
+ AE_val (AV_C_fragment (F_call ("fast_replicate_bits", [F_lit (V_int m); vec; times]), typ, ctyp_of_typ ctx typ))
| _ -> no_change
end
| "undefined_bool", _ ->
- AE_val (AV_C_fragment (F_lit (V_bool false), typ))
+ AE_val (AV_C_fragment (F_lit (V_bool false), typ, CT_bool))
| _, _ ->
c_debug (lazy ("No optimization routine found"));
@@ -552,7 +645,7 @@ let rec instr_ctyps (I_aux (instr, aux)) =
ctyp :: cval_ctyp cval :: List.concat (List.map instr_ctyps instrs1 @ List.map instr_ctyps instrs2)
| I_funcall (clexp, _, _, cvals) ->
clexp_ctyp clexp :: List.map cval_ctyp cvals
- | I_copy (clexp, cval) -> [clexp_ctyp clexp; cval_ctyp cval]
+ | I_copy (clexp, cval) | I_alias (clexp, cval) -> [clexp_ctyp clexp; cval_ctyp cval]
| I_block instrs | I_try_block instrs -> List.concat (List.map instr_ctyps instrs)
| I_throw cval | I_jump (cval, _) | I_return cval -> [cval_ctyp cval]
| I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure -> []
@@ -566,12 +659,15 @@ let cdef_ctyps ctx = function
| CDEF_reg_dec (_, ctyp, instrs) -> ctyp :: List.concat (List.map instr_ctyps instrs)
| CDEF_spec (_, ctyps, ctyp) -> ctyp :: ctyps
| CDEF_fundef (id, _, _, instrs) ->
- let _, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
+ let quant, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
let arg_typs, ret_typ = match fn_typ with
| Typ_fn (arg_typs, ret_typ, _) -> arg_typs, ret_typ
| _ -> assert false
in
- let arg_ctyps, ret_ctyp = List.map (ctyp_of_typ ctx) arg_typs, ctyp_of_typ ctx ret_typ in
+ let arg_ctyps, ret_ctyp =
+ List.map (ctyp_of_typ ctx) arg_typs,
+ ctyp_of_typ { ctx with local_env = add_typquant (id_loc id) quant ctx.local_env } ret_typ
+ in
ret_ctyp :: arg_ctyps @ List.concat (List.map instr_ctyps instrs)
| CDEF_startup (id, instrs) | CDEF_finish (id, instrs) -> List.concat (List.map instr_ctyps instrs)
@@ -614,7 +710,10 @@ let rec chunkify n xs =
| xs, ys -> xs :: chunkify n ys
let rec compile_aval l ctx = function
- | AV_C_fragment (frag, typ) ->
+ | AV_C_fragment (frag, typ, ctyp) ->
+ let ctyp' = ctyp_of_typ ctx typ in
+ if not (ctyp_equal ctyp ctyp') then
+ raise (Reporting.err_unreachable l __POS__ (string_of_ctyp ctyp ^ " != " ^ string_of_ctyp ctyp'));
[], (frag, ctyp_of_typ ctx typ), []
| AV_id (id, typ) ->
@@ -657,6 +756,8 @@ let rec compile_aval l ctx = function
(F_id gs, CT_real),
[iclear CT_real gs]
+ | AV_lit (L_aux (L_unit, _), _) -> [], (F_lit V_unit, CT_unit), []
+
| AV_lit (L_aux (_, l) as lit, _) ->
c_error ~loc:l ("Encountered unexpected literal " ^ string_of_lit lit)
@@ -698,9 +799,9 @@ let rec compile_aval l ctx = function
let len = List.length avals in
match destruct_vector ctx.tc_env typ with
| Some (_, Ord_aux (Ord_inc, _), _) ->
- [], (bitstring, CT_bits64 (len, false)), []
+ [], (bitstring, CT_fbits (len, false)), []
| Some (_, Ord_aux (Ord_dec, _), _) ->
- [], (bitstring, CT_bits64 (len, true)), []
+ [], (bitstring, CT_fbits (len, true)), []
| Some _ ->
c_error "Encountered order polymorphic bitvector literal"
| None ->
@@ -715,15 +816,15 @@ let rec compile_aval l ctx = function
let first_chunk = bitstring (Util.take (len mod 64) avals) in
let chunks = Util.drop (len mod 64) avals |> chunkify 64 |> List.map bitstring in
let gs = gensym () in
- [iinit (CT_bits true) gs (first_chunk, CT_bits64 (len mod 64, true))]
- @ List.map (fun chunk -> ifuncall (CL_id (gs, CT_bits true))
+ [iinit (CT_lbits true) gs (first_chunk, CT_fbits (len mod 64, true))]
+ @ List.map (fun chunk -> ifuncall (CL_id (gs, CT_lbits true))
(mk_id "append_64")
- [(F_id gs, CT_bits true); (chunk, CT_bits64 (64, true))]) chunks,
- (F_id gs, CT_bits true),
- [iclear (CT_bits true) gs]
+ [(F_id gs, CT_lbits true); (chunk, CT_fbits (64, true))]) chunks,
+ (F_id gs, CT_lbits true),
+ [iclear (CT_lbits true) gs]
(* If we have a bitvector value, that isn't a literal then we need to set bits individually. *)
- | AV_vector (avals, Typ_aux (Typ_app (id, [_; Typ_arg_aux (Typ_arg_order ord, _); Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id bit_id, _)), _)]), _))
+ | AV_vector (avals, Typ_aux (Typ_app (id, [_; A_aux (A_order ord, _); A_aux (A_typ (Typ_aux (Typ_id bit_id, _)), _)]), _))
when string_of_id bit_id = "bit" && string_of_id id = "vector" && List.length avals <= 64 ->
let len = List.length avals in
let direction = match ord with
@@ -732,7 +833,7 @@ let rec compile_aval l ctx = function
| Ord_aux (Ord_var _, _) -> c_error "Polymorphic vector direction found"
in
let gs = gensym () in
- let ctyp = CT_bits64 (len, direction) in
+ let ctyp = CT_fbits (len, direction) in
let mask i = V_bits (Util.list_init (63 - i) (fun _ -> Sail2_values.B0) @ [Sail2_values.B1] @ Util.list_init i (fun _ -> Sail2_values.B0)) in
let aval_mask i aval =
let setup, cval, cleanup = compile_aval l ctx aval in
@@ -750,7 +851,7 @@ let rec compile_aval l ctx = function
[]
(* Compiling a vector literal that isn't a bitvector *)
- | AV_vector (avals, Typ_aux (Typ_app (id, [_; Typ_arg_aux (Typ_arg_order ord, _); Typ_arg_aux (Typ_arg_typ typ, _)]), _))
+ | AV_vector (avals, Typ_aux (Typ_app (id, [_; A_aux (A_order ord, _); A_aux (A_typ typ, _)]), _))
when string_of_id id = "vector" ->
let len = List.length avals in
let direction = match ord with
@@ -779,7 +880,7 @@ let rec compile_aval l ctx = function
| AV_list (avals, Typ_aux (typ, _)) ->
let ctyp = match typ with
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ typ, _)]) when string_of_id id = "list" -> ctyp_of_typ ctx typ
+ | Typ_app (id, [A_aux (A_typ typ, _)]) when string_of_id id = "list" -> ctyp_of_typ ctx typ
| _ -> c_error "Invalid list type"
in
let gs = gensym () in
@@ -954,8 +1055,8 @@ let pointer_assign ctyp1 ctyp2 =
let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
let ctx = { ctx with local_env = env } in
match aexp_aux with
- | AE_let (mut, id, binding_typ, binding, body, body_typ) ->
- let binding_ctyp = ctyp_of_typ ctx binding_typ in
+ | AE_let (mut, id, binding_typ, binding, (AE_aux (_, body_env, _) as body), body_typ) ->
+ let binding_ctyp = ctyp_of_typ { ctx with local_env = body_env } binding_typ in
let setup, call, cleanup = compile_aexp ctx binding in
let letb_setup, letb_cleanup =
[idecl binding_ctyp id; iblock (setup @ [call (CL_id (id, binding_ctyp))] @ cleanup)], [iclear binding_ctyp id]
@@ -980,7 +1081,7 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
let compile_case (apat, guard, body) =
let trivial_guard = match guard with
| AE_aux (AE_val (AV_lit (L_aux (L_true, _), _)), _, _)
- | AE_aux (AE_val (AV_C_fragment (F_lit (V_bool true), _)), _, _) -> true
+ | AE_aux (AE_val (AV_C_fragment (F_lit (V_bool true), _, _)), _, _) -> true
| _ -> false
in
let case_label = label "case_" in
@@ -1021,7 +1122,7 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
let compile_case (apat, guard, body) =
let trivial_guard = match guard with
| AE_aux (AE_val (AV_lit (L_aux (L_true, _), _)), _, _)
- | AE_aux (AE_val (AV_C_fragment (F_lit (V_bool true), _)), _, _) -> true
+ | AE_aux (AE_val (AV_C_fragment (F_lit (V_bool true), _, _)), _, _) -> true
| _ -> false
in
let try_label = label "try_" in
@@ -1134,7 +1235,11 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
[]
| AE_assign (id, assign_typ, aexp) ->
- let assign_ctyp = ctyp_of_typ ctx assign_typ in
+ let assign_ctyp =
+ match Bindings.find_opt id ctx.locals with
+ | Some (_, ctyp) -> ctyp
+ | None -> ctyp_of_typ ctx assign_typ
+ in
let setup, call, cleanup = compile_aexp ctx aexp in
setup @ [call (CL_id (id, assign_ctyp))], (fun clexp -> icopy l clexp unit_fragment), cleanup
@@ -1224,14 +1329,8 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
cleanup
| AE_for (loop_var, loop_from, loop_to, loop_step, Ord_aux (ord, _), body) ->
- (* This is a bit of a hack, we force loop_var to be CT_int64 by
- forcing it's type to be a known nexp that will map to
- CT_int64. *)
- let make_small _ _ = function
- | AV_id (id, Local (Immutable, typ)) when Id.compare id loop_var = 0 -> AV_id (id, Local (Immutable, atom_typ (nint 0)))
- | aval -> aval
- in
- let body = map_aval make_small body in
+ (* We assume that all loop indices are safe to put in a CT_int64. *)
+ let ctx = { ctx with locals = Bindings.add loop_var (Immutable, CT_int64) ctx.locals } in
let is_inc = match ord with
| Ord_inc -> true
@@ -1471,7 +1570,7 @@ let rec map_try_block f (I_aux (instr, aux)) =
| I_decl _ | I_reset _ | I_init _ | I_reinit _ -> instr
| I_if (cval, instrs1, instrs2, ctyp) ->
I_if (cval, List.map (map_try_block f) instrs1, List.map (map_try_block f) instrs2, ctyp)
- | I_funcall _ | I_copy _ | I_clear _ | I_throw _ | I_return _ -> instr
+ | I_funcall _ | I_copy _ | I_alias _ | I_clear _ | I_throw _ | I_return _ -> instr
| I_block instrs -> I_block (List.map (map_try_block f) instrs)
| I_try_block instrs -> I_try_block (f (List.map (map_try_block f) instrs))
| I_comment _ | I_label _ | I_goto _ | I_raw _ | I_jump _ | I_match_failure | I_undefined _ -> instr
@@ -1570,7 +1669,18 @@ let rec compile_def ctx = function
let aexp = no_shadow (pat_ids pat) (anf exp) in
c_debug (lazy (Pretty_print_sail.to_string (pp_aexp aexp)));
let aexp = analyze_functions ctx analyze_primop (c_literals ctx aexp) in
- c_debug (lazy (Pretty_print_sail.to_string (pp_aexp aexp)));
+
+ if Id.compare (mk_id !opt_debug_function) id = 0 then
+ let header =
+ Printf.sprintf "Sail ANF for %s %s %s. (%s) -> %s" Util.("function" |> red |> clear) (string_of_id id)
+ (string_of_typquant quant)
+ Util.(string_of_list ", " (fun typ -> string_of_typ typ |> yellow |> clear) arg_typs)
+ Util.(string_of_typ ret_typ |> yellow |> clear)
+
+ in
+ prerr_endline (Util.header header (List.length arg_typs + 2));
+ prerr_endline (Pretty_print_sail.to_string (pp_aexp aexp))
+ else ();
(* Compile the function arguments as patterns. *)
let arg_setup, compiled_args, arg_cleanup = compile_arg_pats ctx fundef_label pat arg_ctyps in
@@ -1617,7 +1727,7 @@ let rec compile_def ctx = function
| DEF_val (LB_aux (LB_val (pat, exp), _)) ->
c_debug (lazy ("Compiling letbind " ^ string_of_pat pat));
- let ctyp = ctyp_of_typ ctx (pat_typ_of pat) in
+ let ctyp = ctyp_of_typ ctx (typ_of_pat pat) in
let aexp = analyze_functions ctx analyze_primop (c_literals ctx (no_shadow IdSet.empty (anf exp))) in
let setup, call, cleanup = compile_aexp ctx aexp in
let apat = anf_pat ~global:true pat in
@@ -1714,6 +1824,7 @@ let rec instrs_rename from_id to_id =
| I_aux (I_funcall (clexp, extern, id, cvals), aux) :: instrs ->
I_aux (I_funcall (lrename clexp, extern, rename id, List.map crename cvals), aux) :: irename instrs
| I_aux (I_copy (clexp, cval), aux) :: instrs -> I_aux (I_copy (lrename clexp, crename cval), aux) :: irename instrs
+ | I_aux (I_alias (clexp, cval), aux) :: instrs -> I_aux (I_alias (lrename clexp, crename cval), aux) :: irename instrs
| I_aux (I_clear (ctyp, id), aux) :: instrs -> I_aux (I_clear (ctyp, rename id), aux) :: irename instrs
| I_aux (I_return cval, aux) :: instrs -> I_aux (I_return (crename cval), aux) :: irename instrs
| I_aux (I_block block, aux) :: instrs -> I_aux (I_block (irename block), aux) :: irename instrs
@@ -1723,7 +1834,7 @@ let rec instrs_rename from_id to_id =
| [] -> []
let hoist_ctyp = function
- | CT_int | CT_bits _ | CT_struct _ -> true
+ | CT_int | CT_lbits _ | CT_struct _ -> true
| _ -> false
let hoist_counter = ref 0
@@ -1784,39 +1895,39 @@ let flat_id () =
incr flat_counter;
id
-let flatten_instrs =
- let rec flatten = function
- | I_aux (I_decl (ctyp, decl_id), aux) :: instrs ->
- let fid = flat_id () in
- I_aux (I_decl (ctyp, fid), aux) :: flatten (instrs_rename decl_id fid instrs)
-
- | I_aux ((I_block block | I_try_block block), _) :: instrs ->
- flatten block @ flatten instrs
-
- | I_aux (I_if (cval, then_instrs, else_instrs, _), _) :: instrs ->
- let then_label = label "then_" in
- let endif_label = label "endif_" in
- [ijump cval then_label]
- @ flatten else_instrs
- @ [igoto endif_label]
- @ [ilabel then_label]
- @ flatten then_instrs
- @ [ilabel endif_label]
- @ flatten instrs
-
- | I_aux (I_comment _, _) :: instrs -> flatten instrs
-
- | instr :: instrs -> instr :: flatten instrs
- | [] -> []
- in
+let rec flatten_instrs = function
+ | I_aux (I_decl (ctyp, decl_id), aux) :: instrs ->
+ let fid = flat_id () in
+ I_aux (I_decl (ctyp, fid), aux) :: flatten_instrs (instrs_rename decl_id fid instrs)
+
+ | I_aux ((I_block block | I_try_block block), _) :: instrs ->
+ flatten_instrs block @ flatten_instrs instrs
+
+ | I_aux (I_if (cval, then_instrs, else_instrs, _), _) :: instrs ->
+ let then_label = label "then_" in
+ let endif_label = label "endif_" in
+ [ijump cval then_label]
+ @ flatten_instrs else_instrs
+ @ [igoto endif_label]
+ @ [ilabel then_label]
+ @ flatten_instrs then_instrs
+ @ [ilabel endif_label]
+ @ flatten_instrs instrs
+
+ | I_aux (I_comment _, _) :: instrs -> flatten_instrs instrs
+
+ | instr :: instrs -> instr :: flatten_instrs instrs
+ | [] -> []
+
+let flatten_cdef =
function
| CDEF_fundef (function_id, heap_return, args, body) ->
flat_counter := 0;
- CDEF_fundef (function_id, heap_return, args, flatten body)
+ CDEF_fundef (function_id, heap_return, args, flatten_instrs body)
| CDEF_let (n, bindings, instrs) ->
flat_counter := 0;
- CDEF_let (n, bindings, flatten instrs)
+ CDEF_let (n, bindings, flatten_instrs instrs)
| cdef -> cdef
@@ -1947,75 +2058,299 @@ let sort_ctype_defs cdefs =
ctype_defs @ cdefs
- (*
-(* When this optimization fires we know we have bytecode of the form
-
- recreate x : S; x = y; ...
-
- when this continues with x.A = a, x.B = b etc until y = x. Then
- provided there are no further references to x we can eliminate
- the variable x.
-
- Must be called after hoist_allocations, otherwise does nothing. *)
-let fix_struct_updates ctx =
- (* FIXME need to check no remaining references *)
- let rec fix_updates struct_id id = function
- | I_aux (I_copy (CL_field (struct_id', field, ctyp), cval), aux) :: instrs
- when Id.compare struct_id struct_id' = 0 ->
- Util.option_map (fun instrs -> I_aux (I_copy (CL_field (id, field, ctyp), cval), aux) :: instrs) (fix_updates struct_id id instrs)
- | I_aux (I_copy (CL_id id', (F_id struct_id', ctyp)), aux) :: instrs
- when Id.compare struct_id struct_id' = 0 && Id.compare id id' = 0->
- Some instrs
- | _ -> None
+let removed = icomment "REMOVED"
+
+let is_not_removed = function
+ | I_aux (I_comment "REMOVED", _) -> false
+ | _ -> true
+
+(** This optimization looks for patterns of the form:
+
+ create x : t;
+ x = y;
+ // modifications to x, and no changes to y
+ y = x;
+ // no further changes to x
+ kill x;
+
+ If found, we can remove the variable x, and directly modify y instead. *)
+let remove_alias ctx =
+ let pattern ctyp id =
+ let alias = ref None in
+ let rec scan ctyp id n instrs =
+ match n, !alias, instrs with
+ | 0, None, I_aux (I_copy (CL_id (id', ctyp'), (F_id a, ctyp'')), _) :: instrs
+ when Id.compare id id' = 0 && ctyp_equal ctyp ctyp' && ctyp_equal ctyp' ctyp'' ->
+ alias := Some a;
+ scan ctyp id 1 instrs
+
+ | 1, Some a, I_aux (I_copy (CL_id (a', ctyp'), (F_id id', ctyp'')), _) :: instrs
+ when Id.compare a a' = 0 && Id.compare id id' = 0 && ctyp_equal ctyp ctyp' && ctyp_equal ctyp' ctyp'' ->
+ scan ctyp id 2 instrs
+
+ | 1, Some a, instr :: instrs ->
+ if IdSet.mem a (instr_ids instr) then
+ None
+ else
+ scan ctyp id 1 instrs
+
+ | 2, Some a, I_aux (I_clear (ctyp', id'), _) :: instrs
+ when Id.compare id id' = 0 && ctyp_equal ctyp ctyp' ->
+ scan ctyp id 2 instrs
+
+ | 2, Some a, instr :: instrs ->
+ if IdSet.mem id (instr_ids instr) then
+ None
+ else
+ scan ctyp id 2 instrs
+
+ | 2, Some a, [] -> !alias
+
+ | n, _, _ :: instrs when n = 0 || n > 2 -> scan ctyp id n instrs
+ | _, _, I_aux (_, (_, l)) :: instrs -> raise (Reporting.err_unreachable l __POS__ "optimize_alias")
+ | _, _, [] -> None
+ in
+ scan ctyp id 0
in
- let rec fix_updates_ret struct_id id = function
- | I_aux (I_copy (CL_field (struct_id', field, ctyp), cval), aux) :: instrs
- when Id.compare struct_id struct_id' = 0 ->
- Util.option_map (fun instrs -> I_aux (I_copy (CL_addr_field (id, field, ctyp), cval), aux) :: instrs) (fix_updates_ret struct_id id instrs)
- | I_aux (I_copy (CL_addr id', (F_id struct_id', ctyp)), aux) :: instrs
- when Id.compare struct_id struct_id' = 0 && Id.compare id id' = 0->
- Some instrs
- | _ -> None
+ let remove_alias id alias = function
+ | I_aux (I_copy (CL_id (id', _), (F_id alias', _)), _)
+ when Id.compare id id' = 0 && Id.compare alias alias' = 0 -> removed
+ | I_aux (I_copy (CL_id (alias', _), (F_id id', _)), _)
+ when Id.compare id id' = 0 && Id.compare alias alias' = 0 -> removed
+ | I_aux (I_clear (_, id'), _) -> removed
+ | instr -> instr
in
- let rec opt hr = function
- | (I_aux (I_reset (ctyp, struct_id), _) as instr1)
- :: (I_aux (I_copy (CL_id (struct_id', _), (F_id id, ctyp')), _) as instr2)
- :: instrs
- when is_ct_struct ctyp && ctyp_equal ctyp ctyp' && Id.compare struct_id struct_id' = 0 ->
- begin match fix_updates struct_id id instrs with
- | None -> instr1 :: instr2 :: opt hr instrs
- | Some updated -> opt hr updated
+ let rec opt = function
+ | I_aux (I_decl (ctyp, id), _) as instr :: instrs ->
+ begin match pattern ctyp id instrs with
+ | None -> instr :: opt instrs
+ | Some alias ->
+ let instrs = List.map (map_instr (remove_alias id alias)) instrs in
+ filter_instrs is_not_removed (List.map (instr_rename id alias) instrs)
end
- | (I_aux (I_reset (ctyp, struct_id), _) as instr) :: instrs
- when is_ct_struct ctyp && Util.is_some hr ->
- let id = match hr with Some id -> id | None -> assert false in
- begin match fix_updates_ret struct_id id instrs with
- | None -> instr :: opt hr instrs
- | Some updated -> opt hr updated
+ | I_aux (I_block block, aux) :: instrs -> I_aux (I_block (opt block), aux) :: opt instrs
+ | I_aux (I_try_block block, aux) :: instrs -> I_aux (I_try_block (opt block), aux) :: opt instrs
+ | I_aux (I_if (cval, then_instrs, else_instrs, ctyp), aux) :: instrs ->
+ I_aux (I_if (cval, opt then_instrs, opt else_instrs, ctyp), aux) :: opt instrs
+
+ | instr :: instrs ->
+ instr :: opt instrs
+ | [] -> []
+ in
+ function
+ | CDEF_fundef (function_id, heap_return, args, body) ->
+ [CDEF_fundef (function_id, heap_return, args, opt body)]
+ | cdef -> [cdef]
+
+
+(** This pass ensures that all variables created by I_decl have unique names *)
+let unique_names =
+ let unique_counter = ref 0 in
+ let unique_id () =
+ let id = mk_id ("u#" ^ string_of_int !unique_counter) in
+ incr unique_counter;
+ id
+ in
+
+ let rec opt seen = function
+ | I_aux (I_decl (ctyp, id), aux) :: instrs when IdSet.mem id seen ->
+ let id' = unique_id () in
+ let instrs', seen = opt seen instrs in
+ I_aux (I_decl (ctyp, id'), aux) :: instrs_rename id id' instrs', seen
+
+ | I_aux (I_decl (ctyp, id), aux) :: instrs ->
+ let instrs', seen = opt (IdSet.add id seen) instrs in
+ I_aux (I_decl (ctyp, id), aux) :: instrs', seen
+
+ | I_aux (I_block block, aux) :: instrs ->
+ let block', seen = opt seen block in
+ let instrs', seen = opt seen instrs in
+ I_aux (I_block block', aux) :: instrs', seen
+
+ | I_aux (I_try_block block, aux) :: instrs ->
+ let block', seen = opt seen block in
+ let instrs', seen = opt seen instrs in
+ I_aux (I_try_block block', aux) :: instrs', seen
+
+ | I_aux (I_if (cval, then_instrs, else_instrs, ctyp), aux) :: instrs ->
+ let then_instrs', seen = opt seen then_instrs in
+ let else_instrs', seen = opt seen else_instrs in
+ let instrs', seen = opt seen instrs in
+ I_aux (I_if (cval, then_instrs', else_instrs', ctyp), aux) :: instrs', seen
+
+ | instr :: instrs ->
+ let instrs', seen = opt seen instrs in
+ instr :: instrs', seen
+
+ | [] -> [], seen
+ in
+ function
+ | CDEF_fundef (function_id, heap_return, args, body) ->
+ [CDEF_fundef (function_id, heap_return, args, fst (opt IdSet.empty body))]
+ | CDEF_reg_dec (id, ctyp, instrs) ->
+ [CDEF_reg_dec (id, ctyp, fst (opt IdSet.empty instrs))]
+ | CDEF_let (n, bindings, instrs) ->
+ [CDEF_let (n, bindings, fst (opt IdSet.empty instrs))]
+ | cdef -> [cdef]
+
+(** This optimization looks for patterns of the form
+
+ create x : t;
+ create y : t;
+ // modifications to y, no changes to x
+ x = y;
+ kill y;
+
+ If found we can replace y by x *)
+let combine_variables ctx =
+ let pattern ctyp id =
+ let combine = ref None in
+ let rec scan id n instrs =
+ match n, !combine, instrs with
+ | 0, None, I_aux (I_block block, _) :: instrs ->
+ begin match scan id 0 block with
+ | Some combine -> Some combine
+ | None -> scan id 0 instrs
+ end
+
+ | 0, None, I_aux (I_decl (ctyp', id'), _) :: instrs when ctyp_equal ctyp ctyp' ->
+ combine := Some id';
+ scan id 1 instrs
+
+ | 1, Some c, I_aux (I_copy (CL_id (id', ctyp'), (F_id c', ctyp'')), _) :: instrs
+ when Id.compare c c' = 0 && Id.compare id id' = 0 && ctyp_equal ctyp ctyp' && ctyp_equal ctyp' ctyp'' ->
+ scan id 2 instrs
+
+ (* Ignore seemingly early clears of x, as this can happen along exception paths *)
+ | 1, Some c, I_aux (I_clear (_, id'), _) :: instrs
+ when Id.compare id id' = 0 ->
+ scan id 1 instrs
+
+ | 1, Some c, instr :: instrs ->
+ if IdSet.mem id (instr_ids instr) then
+ None
+ else
+ scan id 1 instrs
+
+ | 2, Some c, I_aux (I_clear (ctyp', c'), _) :: instrs
+ when Id.compare c c' = 0 && ctyp_equal ctyp ctyp' ->
+ !combine
+
+ | 2, Some c, instr :: instrs ->
+ if IdSet.mem c (instr_ids instr) then
+ None
+ else
+ scan id 2 instrs
+
+ | 2, Some c, [] -> !combine
+
+ | n, _, _ :: instrs -> scan id n instrs
+ | _, _, [] -> None
+ in
+ scan id 0
+ in
+ let remove_variable id = function
+ | I_aux (I_decl (_, id'), _) when Id.compare id id' = 0 -> removed
+ | I_aux (I_clear (_, id'), _) when Id.compare id id' = 0 -> removed
+ | instr -> instr
+ in
+ let is_not_self_assignment = function
+ | I_aux (I_copy (CL_id (id, _), (F_id id', _)), _) when Id.compare id id' = 0 -> false
+ | _ -> true
+ in
+ let rec opt = function
+ | (I_aux (I_decl (ctyp, id), _) as instr) :: instrs ->
+ begin match pattern ctyp id instrs with
+ | None -> instr :: opt instrs
+ | Some combine ->
+ let instrs = List.map (map_instr (remove_variable combine)) instrs in
+ let instrs = filter_instrs (fun i -> is_not_removed i && is_not_self_assignment i)
+ (List.map (instr_rename combine id) instrs) in
+ opt (instr :: instrs)
end
- | I_aux (I_block block, aux) :: instrs -> I_aux (I_block (opt hr block), aux) :: opt hr instrs
- | I_aux (I_try_block block, aux) :: instrs -> I_aux (I_try_block (opt hr block), aux) :: opt hr instrs
+ | I_aux (I_block block, aux) :: instrs -> I_aux (I_block (opt block), aux) :: opt instrs
+ | I_aux (I_try_block block, aux) :: instrs -> I_aux (I_try_block (opt block), aux) :: opt instrs
| I_aux (I_if (cval, then_instrs, else_instrs, ctyp), aux) :: instrs ->
- I_aux (I_if (cval, opt hr then_instrs, opt hr else_instrs, ctyp), aux) :: opt hr instrs
+ I_aux (I_if (cval, opt then_instrs, opt else_instrs, ctyp), aux) :: opt instrs
- | instr :: instrs -> instr :: opt hr instrs
+ | instr :: instrs ->
+ instr :: opt instrs
| [] -> []
in
function
| CDEF_fundef (function_id, heap_return, args, body) ->
- [CDEF_fundef (function_id, heap_return, args, opt heap_return body)]
+ [CDEF_fundef (function_id, heap_return, args, opt body)]
+ | cdef -> [cdef]
+
+(** hoist_alias looks for patterns like
+
+ recreate x; y = x; // no furthner mentions of x
+
+ Provided x has a certain type, then we can make y an alias to x
+ (denoted in the IR as 'alias y = x'). This only works if y also has
+ a lifespan that also spans the entire function body. It's possible
+ we may need to do a more thorough lifetime evaluation to get this
+ to be 100% correct - so it's behind the -Oexperimental flag
+ for now. Some benchmarking shows that this kind of optimization
+ is very valuable however! *)
+let hoist_alias ctx =
+ (* Must return true for a subset of the types hoist_ctyp would return true for. *)
+ let is_struct = function
+ | CT_struct _ -> true
+ | _ -> false
+ in
+ let pattern heap_return id ctyp instrs =
+ let rec scan instrs =
+ match instrs with
+ (* The only thing that has a longer lifetime than id is the
+ function return, so we want to make sure we avoid that
+ case. *)
+ | (I_aux (I_copy (clexp, (F_id id', ctyp')), aux) as instr) :: instrs
+ when not (IdSet.mem heap_return (instr_writes instr)) && Id.compare id id' = 0
+ && ctyp_equal (clexp_ctyp clexp) ctyp && ctyp_equal ctyp ctyp' ->
+ if List.exists (IdSet.mem id) (List.map instr_ids instrs) then
+ instr :: scan instrs
+ else
+ I_aux (I_alias (clexp, (F_id id', ctyp')), aux) :: instrs
+
+ | instr :: instrs -> instr :: scan instrs
+ | [] -> []
+ in
+ scan instrs
+ in
+ let optimize heap_return =
+ let rec opt = function
+ | (I_aux (I_reset (ctyp, id), _) as instr) :: instrs when not (is_stack_ctyp ctyp) && is_struct ctyp ->
+ instr :: opt (pattern heap_return id ctyp instrs)
+
+ | I_aux (I_block block, aux) :: instrs -> I_aux (I_block (opt block), aux) :: opt instrs
+ | I_aux (I_try_block block, aux) :: instrs -> I_aux (I_try_block (opt block), aux) :: opt instrs
+ | I_aux (I_if (cval, then_instrs, else_instrs, ctyp), aux) :: instrs ->
+ I_aux (I_if (cval, opt then_instrs, opt else_instrs, ctyp), aux) :: opt instrs
+
+ | instr :: instrs ->
+ instr :: opt instrs
+ | [] -> []
+ in
+ opt
+ in
+ function
+ | CDEF_fundef (function_id, Some heap_return, args, body) ->
+ [CDEF_fundef (function_id, Some heap_return, args, optimize heap_return body)]
| cdef -> [cdef]
- *)
let concatMap f xs = List.concat (List.map f xs)
let optimize ctx cdefs =
let nothing cdefs = cdefs in
cdefs
+ |> (if !optimize_alias then concatMap unique_names else nothing)
+ |> (if !optimize_alias then concatMap (remove_alias ctx) else nothing)
+ |> (if !optimize_alias then concatMap (combine_variables ctx) else nothing)
|> (if !optimize_hoist_allocations then concatMap (hoist_allocations ctx) else nothing)
-(* |> (if !optimize_struct_updates then concatMap (fix_struct_updates ctx) else nothing) *)
+ |> (if !optimize_hoist_allocations && !optimize_experimental then concatMap (hoist_alias ctx) else nothing)
(**************************************************************************)
(* 6. Code generation *)
@@ -2026,12 +2361,13 @@ let codegen_id id = string (sgen_id id)
let rec sgen_ctyp = function
| CT_unit -> "unit"
- | CT_bit -> "mach_bits"
+ | CT_bit -> "fbits"
| CT_bool -> "bool"
- | CT_bits64 _ -> "mach_bits"
+ | CT_fbits _ -> "fbits"
+ | CT_sbits _ -> "sbits"
| CT_int64 -> "mach_int"
| CT_int -> "sail_int"
- | CT_bits _ -> "sail_bits"
+ | CT_lbits _ -> "lbits"
| CT_tup _ as tup -> "struct " ^ Util.zencode_string ("tuple_" ^ string_of_ctyp tup)
| CT_struct (id, _) -> "struct " ^ sgen_id id
| CT_enum (id, _) -> "enum " ^ sgen_id id
@@ -2045,12 +2381,13 @@ let rec sgen_ctyp = function
let rec sgen_ctyp_name = function
| CT_unit -> "unit"
- | CT_bit -> "mach_bits"
+ | CT_bit -> "fbits"
| CT_bool -> "bool"
- | CT_bits64 _ -> "mach_bits"
+ | CT_fbits _ -> "fbits"
+ | CT_sbits _ -> "sbits"
| CT_int64 -> "mach_int"
| CT_int -> "sail_int"
- | CT_bits _ -> "sail_bits"
+ | CT_lbits _ -> "lbits"
| CT_tup _ as tup -> Util.zencode_string ("tuple_" ^ string_of_ctyp tup)
| CT_struct (id, _) -> sgen_id id
| CT_enum (id, _) -> sgen_id id
@@ -2064,9 +2401,11 @@ let rec sgen_ctyp_name = function
let sgen_cval_param (frag, ctyp) =
match ctyp with
- | CT_bits direction ->
+ | CT_lbits direction ->
+ string_of_fragment frag ^ ", " ^ string_of_bool direction
+ | CT_sbits direction ->
string_of_fragment frag ^ ", " ^ string_of_bool direction
- | CT_bits64 (len, direction) ->
+ | CT_fbits (len, direction) ->
string_of_fragment frag ^ ", UINT64_C(" ^ string_of_int len ^ ") , " ^ string_of_bool direction
| _ ->
string_of_fragment frag
@@ -2077,7 +2416,7 @@ let rec sgen_clexp = function
| CL_id (id, _) -> "&" ^ sgen_id id
| CL_field (clexp, field) -> "&((" ^ sgen_clexp clexp ^ ")->" ^ Util.zencode_string field ^ ")"
| CL_tuple (clexp, n) -> "&((" ^ sgen_clexp clexp ^ ")->ztup" ^ string_of_int n ^ ")"
- | CL_addr clexp -> "*(" ^ sgen_clexp clexp ^ ")"
+ | CL_addr clexp -> "(*(" ^ sgen_clexp clexp ^ "))"
| CL_have_exception -> "have_exception"
| CL_current_exception _ -> "current_exception"
@@ -2085,7 +2424,7 @@ let rec sgen_clexp_pure = function
| CL_id (id, _) -> sgen_id id
| CL_field (clexp, field) -> sgen_clexp_pure clexp ^ "." ^ Util.zencode_string field
| CL_tuple (clexp, n) -> sgen_clexp_pure clexp ^ ".ztup" ^ string_of_int n
- | CL_addr clexp -> "*(" ^ sgen_clexp_pure clexp ^ ")"
+ | CL_addr clexp -> "(*(" ^ sgen_clexp_pure clexp ^ "))"
| CL_have_exception -> "have_exception"
| CL_current_exception _ -> "current_exception"
@@ -2138,6 +2477,9 @@ let rec codegen_instr fid ctx (I_aux (instr, (_, l))) =
| I_copy (clexp, cval) -> codegen_conversion l clexp cval
+ | I_alias (clexp, cval) ->
+ ksprintf string " %s = %s;" (sgen_clexp_pure clexp) (sgen_cval cval)
+
| I_jump (cval, label) ->
ksprintf string " if (%s) goto %s;" (sgen_cval cval) label
@@ -2146,12 +2488,12 @@ let rec codegen_instr fid ctx (I_aux (instr, (_, l))) =
^^ twice space ^^ codegen_instr fid ctx then_instr
| I_if (cval, then_instrs, [], ctyp) ->
string " if" ^^ space ^^ parens (string (sgen_cval cval)) ^^ space
- ^^ surround 2 0 lbrace (separate_map hardline (codegen_instr fid ctx) then_instrs) (twice space ^^ rbrace)
+ ^^ surround 0 0 lbrace (separate_map hardline (codegen_instr fid ctx) then_instrs) (twice space ^^ rbrace)
| I_if (cval, then_instrs, else_instrs, ctyp) ->
string " if" ^^ space ^^ parens (string (sgen_cval cval)) ^^ space
- ^^ surround 2 0 lbrace (separate_map hardline (codegen_instr fid ctx) then_instrs) (twice space ^^ rbrace)
+ ^^ surround 0 0 lbrace (separate_map hardline (codegen_instr fid ctx) then_instrs) (twice space ^^ rbrace)
^^ space ^^ string "else" ^^ space
- ^^ surround 2 0 lbrace (separate_map hardline (codegen_instr fid ctx) else_instrs) (twice space ^^ rbrace)
+ ^^ surround 0 0 lbrace (separate_map hardline (codegen_instr fid ctx) else_instrs) (twice space ^^ rbrace)
| I_block instrs ->
string " {"
@@ -2195,30 +2537,32 @@ let rec codegen_instr fid ctx (I_aux (instr, (_, l))) =
end
| "vector_update_subrange", _ -> Printf.sprintf "vector_update_subrange_%s" (sgen_ctyp_name ctyp)
| "vector_subrange", _ -> Printf.sprintf "vector_subrange_%s" (sgen_ctyp_name ctyp)
- | "vector_update", CT_bits64 _ -> "update_mach_bits"
- | "vector_update", CT_bits _ -> "update_sail_bits"
+ | "vector_update", CT_fbits _ -> "update_fbits"
+ | "vector_update", CT_lbits _ -> "update_lbits"
| "vector_update", _ -> Printf.sprintf "vector_update_%s" (sgen_ctyp_name ctyp)
| "string_of_bits", _ ->
begin match cval_ctyp (List.nth args 0) with
- | CT_bits64 _ -> "string_of_mach_bits"
- | CT_bits _ -> "string_of_sail_bits"
+ | CT_fbits _ -> "string_of_fbits"
+ | CT_lbits _ -> "string_of_lbits"
| _ -> assert false
end
| "decimal_string_of_bits", _ ->
begin match cval_ctyp (List.nth args 0) with
- | CT_bits64 _ -> "decimal_string_of_mach_bits"
- | CT_bits _ -> "decimal_string_of_sail_bits"
+ | CT_fbits _ -> "decimal_string_of_fbits"
+ | CT_lbits _ -> "decimal_string_of_lbits"
| _ -> assert false
end
| "internal_vector_update", _ -> Printf.sprintf "internal_vector_update_%s" (sgen_ctyp_name ctyp)
| "internal_vector_init", _ -> Printf.sprintf "internal_vector_init_%s" (sgen_ctyp_name ctyp)
- | "undefined_vector", CT_bits64 _ -> "UNDEFINED(mach_bits)"
- | "undefined_vector", CT_bits _ -> "UNDEFINED(sail_bits)"
- | "undefined_bit", _ -> "UNDEFINED(mach_bits)"
+ | "undefined_vector", CT_fbits _ -> "UNDEFINED(fbits)"
+ | "undefined_vector", CT_lbits _ -> "UNDEFINED(lbits)"
+ | "undefined_bit", _ -> "UNDEFINED(fbits)"
| "undefined_vector", _ -> Printf.sprintf "UNDEFINED(vector_%s)" (sgen_ctyp_name ctyp)
| fname, _ -> fname
in
- if fname = "reg_deref" then
+ if fname = "sail_assert" && !optimize_experimental then
+ empty
+ else if fname = "reg_deref" then
if is_stack_ctyp ctyp then
string (Printf.sprintf " %s = *(%s);" (sgen_clexp_pure x) c_args)
else
@@ -2234,26 +2578,13 @@ let rec codegen_instr fid ctx (I_aux (instr, (_, l))) =
| I_clear (ctyp, id) ->
string (Printf.sprintf " KILL(%s)(&%s);" (sgen_ctyp_name ctyp) (sgen_id id))
- | I_init (ctyp, id, cval) when is_stack_ctyp ctyp ->
- if ctyp_equal ctyp (cval_ctyp cval) then
- ksprintf string " %s %s = %s;" (sgen_ctyp ctyp) (sgen_id id) (sgen_cval cval)
- else
- ksprintf string " %s %s = CREATE_OF(%s, %s)(%s);"
- (sgen_ctyp ctyp) (sgen_id id) (sgen_ctyp_name ctyp) (sgen_ctyp_name (cval_ctyp cval)) (sgen_cval cval)
| I_init (ctyp, id, cval) ->
- ksprintf string " %s %s;" (sgen_ctyp ctyp) (sgen_id id) ^^ hardline
- ^^ ksprintf string " CREATE_OF(%s, %s)(&%s, %s);"
- (sgen_ctyp_name ctyp) (sgen_ctyp_name (cval_ctyp cval)) (sgen_id id) (sgen_cval_param cval)
+ codegen_instr fid ctx (idecl ctyp id) ^^ hardline
+ ^^ codegen_conversion Parse_ast.Unknown (CL_id (id, ctyp)) cval
- | I_reinit (ctyp, id, cval) when is_stack_ctyp ctyp ->
- if ctyp_equal ctyp (cval_ctyp cval) then
- ksprintf string " %s %s = %s;" (sgen_ctyp ctyp) (sgen_id id) (sgen_cval cval)
- else
- ksprintf string " %s %s = CREATE_OF(%s, %s)(%s);"
- (sgen_ctyp ctyp) (sgen_id id) (sgen_ctyp_name ctyp) (sgen_ctyp_name (cval_ctyp cval)) (sgen_cval cval)
| I_reinit (ctyp, id, cval) ->
- ksprintf string " RECREATE_OF(%s, %s)(&%s, %s);"
- (sgen_ctyp_name ctyp) (sgen_ctyp_name (cval_ctyp cval)) (sgen_id id) (sgen_cval_param cval)
+ codegen_instr fid ctx (ireset ctyp id) ^^ hardline
+ ^^ codegen_conversion Parse_ast.Unknown (CL_id (id, ctyp)) cval
| I_reset (ctyp, id) when is_stack_ctyp ctyp ->
string (Printf.sprintf " %s %s;" (sgen_ctyp ctyp) (sgen_id id))
@@ -2272,7 +2603,8 @@ let rec codegen_instr fid ctx (I_aux (instr, (_, l))) =
| CT_unit -> "UNIT", []
| CT_bit -> "UINT64_C(0)", []
| CT_int64 -> "INT64_C(0xdeadc0de)", []
- | CT_bits64 _ -> "UINT64_C(0xdeadc0de)", []
+ | CT_fbits _ -> "UINT64_C(0xdeadc0de)", []
+ | CT_sbits _ -> "undefined_sbits()", []
| CT_bool -> "false", []
| CT_enum (_, ctor :: _) -> sgen_id ctor, []
| CT_tup ctyps when is_stack_ctyp ctyp ->
@@ -2716,7 +3048,7 @@ let codegen_vector ctx (direction, ctyp) =
^^ string (Printf.sprintf " rop->data = malloc(len * sizeof(%s));\n" (sgen_ctyp ctyp))
^^ (if not (is_stack_ctyp ctyp) then
string " for (int i = 0; i < len; i++) {\n"
- ^^ string (Printf.sprintf " CREATE(%s)((rop->data) + i);\n" (sgen_ctyp ctyp))
+ ^^ string (Printf.sprintf " CREATE(%s)((rop->data) + i);\n" (sgen_ctyp_name ctyp))
^^ string " }\n"
else empty)
^^ string "}"
@@ -2776,9 +3108,7 @@ let codegen_def' ctx = function
string (Printf.sprintf "%svoid %s(%s *rop, %s);" static (sgen_id id) (sgen_ctyp ret_ctyp) (Util.string_of_list ", " sgen_ctyp arg_ctyps))
| CDEF_fundef (id, ret_arg, args, instrs) as def ->
- if !opt_ddump_flow_graphs then make_dot id (instrs_graph instrs) else ();
-
- c_debug (lazy (Pretty_print_sail.to_string (separate_map hardline pp_instr instrs)));
+ if !opt_debug_flow_graphs then make_dot id (instrs_graph instrs) else ();
(* Extract type information about the function from the environment. *)
let quant, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
@@ -2797,6 +3127,18 @@ let codegen_def' ctx = function
^ Util.string_of_list ", " string_of_ctyp arg_ctyps)
else ();
+ (* If this function is set as opt_debug_function, then output its IR *)
+ if Id.compare (mk_id !opt_debug_function) id = 0 then
+ let header =
+ Printf.sprintf "Sail IR for %s %s(%s) : (%s) -> %s" Util.("function" |> red |> clear) (string_of_id id)
+ (Util.string_of_list ", " string_of_id args)
+ (Util.string_of_list ", " (fun ctyp -> Util.(string_of_ctyp ctyp |> yellow |> clear)) arg_ctyps)
+ Util.(string_of_ctyp ret_ctyp |> yellow |> clear)
+ in
+ prerr_endline (Util.header header (List.length arg_ctyps + 2));
+ prerr_endline (Pretty_print_sail.to_string (separate_map hardline pp_instr instrs))
+ else ();
+
let instrs = add_local_labels instrs in
let args = Util.string_of_list ", " (fun x -> x) (List.map2 (fun ctyp arg -> sgen_ctyp ctyp ^ " " ^ sgen_id arg) arg_ctyps args) in
let function_header =
@@ -2878,7 +3220,7 @@ let rec ctyp_dependencies = function
| CT_ref ctyp -> ctyp_dependencies ctyp
| CT_struct (_, ctors) -> List.concat (List.map (fun (_, ctyp) -> ctyp_dependencies ctyp) ctors)
| CT_variant (_, ctors) -> List.concat (List.map (fun (_, ctyp) -> ctyp_dependencies ctyp) ctors)
- | CT_int | CT_int64 | CT_bits _ | CT_bits64 _ | CT_unit | CT_bool | CT_real | CT_bit | CT_string | CT_enum _ | CT_poly -> []
+ | CT_int | CT_int64 | CT_lbits _ | CT_fbits _ | CT_sbits _ | CT_unit | CT_bool | CT_real | CT_bit | CT_string | CT_enum _ | CT_poly -> []
let codegen_ctg ctx = function
| CTG_vector (direction, ctyp) -> codegen_vector ctx (direction, ctyp)
@@ -2921,10 +3263,9 @@ let sgen_finish = function
Printf.sprintf " finish_%s();" (sgen_id id)
| _ -> assert false
- (*
let instrument_tracing ctx =
let module StringSet = Set.Make(String) in
- let traceable = StringSet.of_list ["mach_bits"; "sail_string"; "sail_bits"; "sail_int"; "unit"; "bool"] in
+ let traceable = StringSet.of_list ["fbits"; "sail_string"; "lbits"; "sail_int"; "unit"; "bool"] in
let rec instrument = function
| (I_aux (I_funcall (clexp, _, id, args), _) as instr) :: instrs ->
let trace_start =
@@ -2944,12 +3285,14 @@ let instrument_tracing ctx =
trace_arg cval :: iraw "trace_argsep();" :: trace_args cvals
in
let trace_end = iraw "trace_end();" in
- let trace_ret =
+ let trace_ret = iraw "trace_unknown();"
+ (*
let ctyp_name = sgen_ctyp_name ctyp in
if StringSet.mem ctyp_name traceable then
iraw (Printf.sprintf "trace_%s(%s);" (sgen_ctyp_name ctyp) (sgen_clexp_pure clexp))
else
iraw "trace_unknown();"
+ *)
in
[trace_start]
@ trace_args args
@@ -2972,11 +3315,10 @@ let instrument_tracing ctx =
| CDEF_fundef (function_id, heap_return, args, body) ->
CDEF_fundef (function_id, heap_return, args, instrument body)
| cdef -> cdef
- *)
let bytecode_ast ctx rewrites (Defs defs) =
- let assert_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_assert") "(bool, string) -> unit effect {escape}" in
- let exit_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_exit") "unit -> unit effect {escape}" in
+ let assert_vs = Initial_check.extern_of_string (mk_id "sail_assert") "(bool, string) -> unit effect {escape}" in
+ let exit_vs = Initial_check.extern_of_string (mk_id "sail_exit") "unit -> unit effect {escape}" in
let ctx = { ctx with tc_env = snd (Type_error.check ctx.tc_env (Defs [assert_vs; exit_vs])) } in
let chunks, ctx = List.fold_left (fun (chunks, ctx) def -> let defs, ctx = compile_def ctx def in defs :: chunks, ctx) ([], ctx) defs in
@@ -3017,17 +3359,15 @@ let compile_ast ctx c_includes (Defs defs) =
let ctx = { ctx with recursive_functions = recursive_functions } in
c_debug (lazy (Util.string_of_list ", " string_of_id (IdSet.elements recursive_functions)));
- let assert_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_assert") "(bool, string) -> unit effect {escape}" in
- let exit_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_exit") "unit -> unit effect {escape}" in
+ let assert_vs = Initial_check.extern_of_string (mk_id "sail_assert") "(bool, string) -> unit effect {escape}" in
+ let exit_vs = Initial_check.extern_of_string (mk_id "sail_exit") "unit -> unit effect {escape}" in
let ctx = { ctx with tc_env = snd (Type_error.check ctx.tc_env (Defs [assert_vs; exit_vs])) } in
let chunks, ctx = List.fold_left (fun (chunks, ctx) def -> let defs, ctx = compile_def ctx def in defs :: chunks, ctx) ([], ctx) defs in
let cdefs = List.concat (List.rev chunks) in
let cdefs, ctx = specialize_variants ctx [] cdefs in
let cdefs = sort_ctype_defs cdefs in
let cdefs = optimize ctx cdefs in
- (*
let cdefs = if !opt_trace then List.map (instrument_tracing ctx) cdefs else cdefs in
- *)
let docs = List.map (codegen_def ctx) cdefs in
let preamble = separate hardline
diff --git a/src/c_backend.mli b/src/c_backend.mli
index 170c5bd9..24f6e03b 100644
--- a/src/c_backend.mli
+++ b/src/c_backend.mli
@@ -53,7 +53,8 @@ open Type_check
(** Global compilation options *)
-val opt_ddump_flow_graphs : bool ref
+val opt_debug_flow_graphs : bool ref
+val opt_debug_function : string ref
val opt_trace : bool ref
val opt_static : bool ref
val opt_no_main : bool ref
@@ -63,17 +64,26 @@ val opt_no_main : bool ref
val optimize_primops : bool ref
val optimize_hoist_allocations : bool ref
val optimize_struct_updates : bool ref
+val optimize_alias : bool ref
+val optimize_experimental : bool ref
(** The compilation context. *)
type ctx
+(** Convert a typ to a IR ctyp *)
+val ctyp_of_typ : ctx -> Ast.typ -> ctyp
+
(** Create a context from a typechecking environment. This environment
should be the environment returned by typechecking the full AST. *)
val initial_ctx : Env.t -> ctx
+val compile_aexp : ctx -> Ast.typ Anf.aexp -> instr list * (clexp -> instr) * instr list
+
val compile_ast : ctx -> string list -> tannot Ast.defs -> unit
val bytecode_ast : ctx -> (cdef list -> cdef list) -> tannot Ast.defs -> cdef list
(** Rewriting steps for compiled ASTs *)
-val flatten_instrs : cdef -> cdef
+val flatten_instrs : instr list -> instr list
+
+val flatten_cdef : cdef -> cdef
diff --git a/src/cgen_backend.ml b/src/cgen_backend.ml
new file mode 100644
index 00000000..77029c9e
--- /dev/null
+++ b/src/cgen_backend.ml
@@ -0,0 +1,77 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast
+open Ast_util
+open PPrint
+
+let to_string doc =
+ let b = Buffer.create 120 in
+ ToBuffer.pretty 1. 120 b doc;
+ Buffer.contents b
+
+let do_mapdef_thing (MD_aux (MD_mapping (_, _, clauses), _)) =
+ print_endline ("Mapping has " ^ string_of_int (List.length clauses) ^ " clauses")
+
+let rec list_registers = function
+ | [] -> ()
+ | (DEF_reg_dec reg) :: defs ->
+ print_endline (to_string (Pretty_print_sail.doc_dec reg));
+ list_registers defs
+ | (DEF_mapdef mapdef) :: defs ->
+ do_mapdef_thing mapdef;
+ list_registers defs
+ | def :: defs ->
+ list_registers defs
+
+let output env (Defs defs) =
+ let xlenbits = mk_typ (Typ_id (mk_id "xlenbits")) in
+ print_endline (string_of_typ (Type_check.Env.expand_synonyms env xlenbits));
+ list_registers defs
diff --git a/src/constant_fold.ml b/src/constant_fold.ml
index d5fffbbe..acae4581 100644
--- a/src/constant_fold.ml
+++ b/src/constant_fold.ml
@@ -72,12 +72,13 @@ and exp_of_value =
| V_bool false -> mk_lit_exp L_false
| V_string str -> mk_lit_exp (L_string str)
| V_record ctors ->
- mk_exp (E_record (FES_aux (FES_Fexps (List.map fexp_of_ctor (StringMap.bindings ctors), false), no_annot)))
+ mk_exp (E_record (List.map fexp_of_ctor (StringMap.bindings ctors)))
| V_vector vs ->
mk_exp (E_vector (List.map exp_of_value vs))
| V_tuple vs ->
mk_exp (E_tuple (List.map exp_of_value vs))
| V_unit -> mk_lit_exp L_unit
+ | V_attempted_read str -> mk_exp (E_id (mk_id str))
| _ -> failwith "No expression for value"
(* We want to avoid evaluating things like print statements at compile
@@ -95,11 +96,13 @@ let safe_primops =
"print_bits";
"print_int";
"print_string";
+ "print_real";
"prerr_bits";
"prerr_int";
"prerr_string";
"read_ram";
"write_ram";
+ "get_time_ns";
"Elf_loader.elf_entry";
"Elf_loader.elf_tohost"
]
@@ -108,7 +111,7 @@ let rec is_constant (E_aux (e_aux, _)) =
match e_aux with
| E_lit _ -> true
| E_vector exps -> List.for_all is_constant exps
- | E_record (FES_aux (FES_Fexps (fexps, _), _)) -> List.for_all is_constant_fexp fexps
+ | E_record fexps -> List.for_all is_constant_fexp fexps
| E_cast (_, exp) -> is_constant exp
| E_tuple exps -> List.for_all is_constant exps
| _ -> false
diff --git a/src/constraint.ml b/src/constraint.ml
index d66705b6..7ead0cc8 100644
--- a/src/constraint.ml
+++ b/src/constraint.ml
@@ -49,86 +49,10 @@
(**************************************************************************)
module Big_int = Nat_big_num
+open Ast
+open Ast_util
open Util
-(* ===== Integer Constraints ===== *)
-
-type nexp_op = string
-
-type nexp =
- | NFun of (nexp_op * nexp list)
- | N2n of nexp
- | NConstant of Big_int.num
- | NVar of int
-
-let big_int_op : nexp_op -> (Big_int.num -> Big_int.num -> Big_int.num) option = function
- | "+" -> Some Big_int.add
- | "-" -> Some Big_int.sub
- | "*" -> Some Big_int.mul
- | _ -> None
-
-let rec arith constr =
- let constr' = match constr with
- | NFun (op, [x; y]) -> NFun (op, [arith x; arith y])
- | N2n c -> N2n (arith c)
- | c -> c
- in
- match constr' with
- | NFun (op, [NConstant x; NConstant y]) as c ->
- begin
- match big_int_op op with
- | Some op -> NConstant (op x y)
- | None -> c
- end
- | N2n (NConstant x) -> NConstant (Big_int.pow_int_positive 2 (Big_int.to_int x))
- | c -> c
-
-(* ===== Boolean Constraints ===== *)
-
-type constraint_bool_op = And | Or
-
-type constraint_compare_op = Gt | Lt | GtEq | LtEq | Eq | NEq
-
-let negate_comparison = function
- | Gt -> LtEq
- | Lt -> GtEq
- | GtEq -> Lt
- | LtEq -> Gt
- | Eq -> NEq
- | NEq -> Eq
-
-type 'a constraint_bool =
- | BFun of (constraint_bool_op * 'a constraint_bool * 'a constraint_bool)
- | Not of 'a constraint_bool
- | CFun of (constraint_compare_op * 'a * 'a)
- | Forall of (int list * 'a constraint_bool)
- | Boolean of bool
-
-let rec pairs (xs : 'a list) (ys : 'a list) : ('a * 'b) list =
- match xs with
- | [] -> []
- | (x :: xs) -> List.map (fun y -> (x, y)) ys @ pairs xs ys
-
-(* Get a set of variables from a constraint *)
-module IntSet = Set.Make(
- struct
- let compare = Pervasives.compare
- type t = int
- end)
-
-let rec nexp_vars : nexp -> IntSet.t = function
- | NConstant _ -> IntSet.empty
- | NVar v -> IntSet.singleton v
- | NFun (_, xs) -> List.fold_left IntSet.union IntSet.empty (List.map nexp_vars xs)
- | N2n x -> nexp_vars x
-
-let rec constraint_vars : nexp constraint_bool -> IntSet.t = function
- | BFun (_, x, y) -> IntSet.union (constraint_vars x) (constraint_vars y)
- | Not x -> constraint_vars x
- | CFun (_, x, y) -> IntSet.union (nexp_vars x) (nexp_vars y)
- | Forall (vars, x) -> IntSet.diff (constraint_vars x) (IntSet.of_list vars)
- | Boolean _ -> IntSet.empty
-
(* SMTLIB v2.0 format is based on S-expressions so we have a
lightweight representation of those here. *)
type sexpr = List of (sexpr list) | Atom of string
@@ -139,47 +63,85 @@ let rec pp_sexpr : sexpr -> string = function
| List xs -> "(" ^ string_of_list " " pp_sexpr xs ^ ")"
| Atom x -> x
-let var_decs constr =
- constraint_vars constr
- |> IntSet.elements
- |> List.map (fun var -> sfun "declare-const" [Atom ("v" ^ string_of_int var); Atom "Int"])
- |> string_of_list "\n" pp_sexpr
-
-let cop_sexpr op x y =
- match op with
- | Gt -> sfun ">" [x; y]
- | Lt -> sfun "<" [x; y]
- | GtEq -> sfun ">=" [x; y]
- | LtEq -> sfun "<=" [x; y]
- | Eq -> sfun "=" [x; y]
- | NEq -> sfun "not" [sfun "=" [x; y]]
-
-let rec sexpr_of_nexp = function
- | NFun (op, xs) -> sfun op (List.map sexpr_of_nexp xs)
- | N2n x -> sfun "^" [Atom "2"; sexpr_of_nexp x]
- | NConstant c -> Atom (Big_int.to_string c) (* CHECK: do we do negative constants right? *)
- | NVar var -> Atom ("v" ^ string_of_int var)
+(** Each non-Type/Order kind in Sail mapes to a type in the SMT solver *)
+let smt_type l = function
+ | K_int -> Atom "Int"
+ | K_bool -> Atom "Bool"
+ | _ -> raise (Reporting.err_unreachable l __POS__ "Tried to pass Type or Order kinded variable to SMT solver")
+
+let to_smt l vars constr =
+ (* Numbering all SMT variables v0, ... vn, rather than generating
+ names based on their Sail names (e.g. using zencode) ensures that
+ alpha-equivalent constraints generate the same SMT problem, which
+ is important for the SMT memoisation to work properly. *)
+ let var_map = ref KBindings.empty in
+ let vnum = ref (-1) in
+ let smt_var v =
+ match KBindings.find_opt v !var_map with
+ | Some n -> Atom ("v" ^ string_of_int n)
+ | None ->
+ let n = !vnum + 1 in
+ var_map := KBindings.add v n !var_map;
+ vnum := n;
+ Atom ("v" ^ string_of_int n)
+ in
-let rec sexpr_of_constraint = function
- | BFun (And, x, y) -> sfun "and" [sexpr_of_constraint x; sexpr_of_constraint y]
- | BFun (Or, x, y) -> sfun "or" [sexpr_of_constraint x; sexpr_of_constraint y]
- | Not x -> sfun "not" [sexpr_of_constraint x]
- | CFun (op, x, y) -> cop_sexpr op (sexpr_of_nexp (arith x)) (sexpr_of_nexp (arith y))
- | Forall (vars, x) ->
- sfun "forall" [List (List.map (fun v -> List [Atom ("v" ^ string_of_int v); Atom "Int"]) vars); sexpr_of_constraint x]
- | Boolean true -> Atom "true"
- | Boolean false -> Atom "false"
+ (* var_decs outputs the list of variables to be used by the SMT
+ solver in SMTLIB v2.0 format. It takes a kind_aux KBindings, as
+ returned by Type_check.get_typ_vars *)
+ let var_decs l (vars : kind_aux KBindings.t) : string =
+ vars
+ |> KBindings.bindings
+ |> List.map (fun (v, k) -> sfun "declare-const" [smt_var v; smt_type l k])
+ |> string_of_list "\n" pp_sexpr
+ in
+ let rec smt_nexp (Nexp_aux (aux, l) : nexp) : sexpr =
+ match aux with
+ | Nexp_id id -> Atom (Util.zencode_string (string_of_id id))
+ | Nexp_var v -> smt_var v
+ | Nexp_constant c -> Atom (Big_int.to_string c)
+ | Nexp_app (id, nexps) -> sfun (string_of_id id) (List.map smt_nexp nexps)
+ | Nexp_times (nexp1, nexp2) -> sfun "*" [smt_nexp nexp1; smt_nexp nexp2]
+ | Nexp_sum (nexp1, nexp2) -> sfun "+" [smt_nexp nexp1; smt_nexp nexp2]
+ | Nexp_minus (nexp1, nexp2) -> sfun "-" [smt_nexp nexp1; smt_nexp nexp2]
+ | Nexp_exp (Nexp_aux (Nexp_constant c, _)) when Big_int.greater c Big_int.zero ->
+ Atom (Big_int.to_string (Big_int.pow_int_positive 2 (Big_int.to_int c)))
+ | Nexp_exp nexp -> sfun "^" [Atom "2"; smt_nexp nexp]
+ | Nexp_neg nexp -> sfun "-" [smt_nexp nexp]
+ in
+ let rec smt_constraint (NC_aux (aux, l) : n_constraint) : sexpr =
+ match aux with
+ | NC_equal (nexp1, nexp2) -> sfun "=" [smt_nexp nexp1; smt_nexp nexp2]
+ | NC_bounded_le (nexp1, nexp2) -> sfun "<=" [smt_nexp nexp1; smt_nexp nexp2]
+ | NC_bounded_ge (nexp1, nexp2) -> sfun ">=" [smt_nexp nexp1; smt_nexp nexp2]
+ | NC_not_equal (nexp1, nexp2) -> sfun "not" [sfun "=" [smt_nexp nexp1; smt_nexp nexp2]]
+ | NC_set (v, ints) ->
+ sfun "or" (List.map (fun i -> sfun "=" [smt_var v; Atom (Big_int.to_string i)]) ints)
+ | NC_or (nc1, nc2) -> sfun "or" [smt_constraint nc1; smt_constraint nc2]
+ | NC_and (nc1, nc2) -> sfun "and" [smt_constraint nc1; smt_constraint nc2]
+ | NC_app (id, args) ->
+ sfun (string_of_id id) (List.map smt_typ_arg args)
+ | NC_true -> Atom "true"
+ | NC_false -> Atom "false"
+ | NC_var v -> smt_var v
+ and smt_typ_arg (A_aux (aux, l) : typ_arg) : sexpr =
+ match aux with
+ | A_nexp nexp -> smt_nexp nexp
+ | A_bool nc -> smt_constraint nc
+ | _ ->
+ raise (Reporting.err_unreachable l __POS__ "Tried to pass Type or Order kind to SMT function")
+ in
+ var_decs l vars, smt_constraint constr
-let smtlib_of_constraints ?get_model:(get_model=false) constr : string =
+let smtlib_of_constraints ?get_model:(get_model=false) l vars constr : string =
+ let variables, problem = to_smt l vars constr in
"(push)\n"
- ^ var_decs constr ^ "\n"
- ^ pp_sexpr (sfun "define-fun" [Atom "constraint"; List []; Atom "Bool"; sexpr_of_constraint constr])
+ ^ variables ^ "\n"
+ ^ pp_sexpr (sfun "define-fun" [Atom "constraint"; List []; Atom "Bool"; problem])
^ "\n(assert constraint)\n(check-sat)"
^ (if get_model then "\n(get-model)" else "")
^ "\n(pop)"
-type t = nexp constraint_bool
-
type smt_result = Unknown | Sat | Unsat
module DigestMap = Map.Make(Digest)
@@ -219,9 +181,9 @@ let save_digests () =
DigestMap.iter output !known_problems;
close_out out_chan
-let rec call_z3 constraints : smt_result =
+let call_z3' l vars constraints : smt_result =
let problems = [constraints] in
- let z3_file = smtlib_of_constraints constraints in
+ let z3_file = smtlib_of_constraints l vars constraints in
(* prerr_endline (Printf.sprintf "SMTLIB2 constraints are: \n%s%!" z3_file); *)
@@ -261,9 +223,14 @@ let rec call_z3 constraints : smt_result =
else (known_problems := DigestMap.add digest Unknown !known_problems; Unknown)
end
-let rec solve_z3 constraints var =
- let problems = [constraints] in
- let z3_file = smtlib_of_constraints ~get_model:true constraints in
+let call_z3 l vars constraints =
+ let t = Profile.start_z3 () in
+ let result = call_z3' l vars constraints in
+ Profile.finish_z3 t;
+ result
+
+let rec solve_z3 l vars constraints var =
+ let z3_file = smtlib_of_constraints ~get_model:true l vars constraints in
(* prerr_endline (Printf.sprintf "SMTLIB2 constraints are: \n%s%!" z3_file); *)
@@ -283,62 +250,13 @@ let rec solve_z3 constraints var =
let z3_output = String.concat " " (input_all z3_chan) in
let _ = Unix.close_process_in z3_chan in
Sys.remove input_file;
- let regexp = {|(define-fun v|} ^ string_of_int var ^ {| () Int[ ]+\([0-9]+\))|} in
+ let regexp = {|(define-fun v|} ^ Util.zencode_string (string_of_kid var) ^ {| () Int[ ]+\([0-9]+\))|} in
try
let _ = Str.search_forward (Str.regexp regexp) z3_output 0 in
let result = Big_int.of_string (Str.matched_group 1 z3_output) in
- begin match call_z3 (BFun (And, constraints, CFun (NEq, NConstant result, NVar var))) with
+ begin match call_z3 l vars (nc_and constraints (nc_neq (nconstant result) (nvar var))) with
| Unsat -> Some result
| _ -> None
end
with
Not_found -> None
-
-let string_of constr = smtlib_of_constraints constr
-
-(* ===== Abstract API for building constraints ===== *)
-
-(* These functions are exported from constraint.mli, and ensure that
- the internal representation of constraints remains opaque. *)
-
-let implies (x : t) (y : t) : t =
- BFun (Or, Not x, y)
-
-let conj (x : t) (y : t) : t =
- BFun (And, x, y)
-
-let disj (x : t) (y : t) : t =
- BFun (Or, x, y)
-
-let forall (vars : int list) (x : t) : t =
- if vars = [] then x else Forall (vars, x)
-
-let negate (x : t) : t = Not x
-
-let literal (b : bool) : t = Boolean b
-
-let lt x y : t = CFun (Lt, x, y)
-
-let lteq x y : t = CFun (LtEq, x, y)
-
-let gt x y : t = CFun (Gt, x, y)
-
-let gteq x y : t = CFun (GtEq, x, y)
-
-let eq x y : t = CFun (Eq, x, y)
-
-let neq x y : t = CFun (NEq, x, y)
-
-let pow2 x : nexp = N2n x
-
-let add x y : nexp = NFun ("+", [x; y])
-
-let sub x y : nexp = NFun ("-", [x; y])
-
-let mult x y : nexp = NFun ("*", [x; y])
-
-let app f xs : nexp = NFun (f, xs)
-
-let constant (x : Big_int.num) : nexp = NConstant x
-
-let variable (v : int) : nexp = NVar v
diff --git a/src/constraint.mli b/src/constraint.mli
index df9c8b3a..51088245 100644
--- a/src/constraint.mli
+++ b/src/constraint.mli
@@ -49,40 +49,14 @@
(**************************************************************************)
module Big_int = Nat_big_num
-
-type nexp
-type t
+open Ast
+open Ast_util
type smt_result = Unknown | Sat | Unsat
val load_digests : unit -> unit
val save_digests : unit -> unit
-val call_z3 : t -> smt_result
-
-val solve_z3 : t -> int -> Big_int.num option
-
-val string_of : t -> string
-
-val implies : t -> t -> t
-val conj : t -> t -> t
-val disj : t -> t -> t
-val negate : t -> t
-val literal : bool -> t
-val forall : int list -> t -> t
-
-val lt : nexp -> nexp -> t
-val lteq : nexp -> nexp -> t
-val gt : nexp -> nexp -> t
-val gteq : nexp -> nexp -> t
-val eq : nexp -> nexp -> t
-val neq : nexp -> nexp -> t
-
-val pow2 : nexp -> nexp
-val add : nexp -> nexp -> nexp
-val sub : nexp -> nexp -> nexp
-val mult : nexp -> nexp -> nexp
-val app : string -> nexp list -> nexp
+val call_z3 : l -> kind_aux KBindings.t -> n_constraint -> smt_result
-val constant : Big_int.num -> nexp
-val variable : int -> nexp
+val solve_z3 : l -> kind_aux KBindings.t -> n_constraint -> kid -> Big_int.num option
diff --git a/src/extra_pervasives.ml b/src/extra_pervasives.ml
index a7808a95..8001c647 100644
--- a/src/extra_pervasives.ml
+++ b/src/extra_pervasives.ml
@@ -49,4 +49,4 @@
(**************************************************************************)
let unreachable l pos msg =
- raise (Reporting_basic.err_unreachable l pos msg)
+ raise (Reporting.err_unreachable l pos msg)
diff --git a/src/gen_lib/sail2_string.lem b/src/gen_lib/sail2_string.lem
index de7588dc..33a665a0 100644
--- a/src/gen_lib/sail2_string.lem
+++ b/src/gen_lib/sail2_string.lem
@@ -64,10 +64,6 @@ let rec n_leading_spaces s =
| _ -> 0
end
else
- (* match len with
- * (\* | 0 -> 0 *\)
- * (\* | 1 -> *\)
- * | len -> *)
(* Isabelle generation for pattern matching on characters
is currently broken, so use an if-expression *)
if nth s 0 = #' '
diff --git a/src/initial_check.ml b/src/initial_check.ml
index 36c60f2e..7de74a93 100644
--- a/src/initial_check.ml
+++ b/src/initial_check.ml
@@ -51,1035 +51,752 @@
open Ast
open Util
open Ast_util
+open Printf
module Big_int = Nat_big_num
+module P = Parse_ast
+
(* See mli file for details on what these flags do *)
let opt_undefined_gen = ref false
let opt_fast_undefined = ref false
let opt_magic_hash = ref false
let opt_enum_casts = ref false
-module Envmap = Finite_map.Fmap_map(String)
-module Nameset' = Set.Make(String)
-module Nameset = struct
- include Nameset'
- let pp ppf nameset =
- Format.fprintf ppf "{@[%a@]}"
- (Pp.lst ",@ " Pp.pp_str)
- (Nameset'.elements nameset)
-end
-
-type kind = { mutable k : k_aux }
-and k_aux =
- | K_Typ
- | K_Nat
- | K_Ord
- | K_Efct
- | K_Val
- | K_Lam of kind list * kind
- | K_infer
-
-let rec kind_to_string kind = match kind.k with
- | K_Nat -> "Nat"
- | K_Typ -> "Type"
- | K_Ord -> "Order"
- | K_Efct -> "Effect"
- | K_infer -> "Infer"
- | K_Val -> "Val"
- | K_Lam (kinds,kind) -> "Lam [" ^ string_of_list ", " kind_to_string kinds ^ "] -> " ^ (kind_to_string kind)
-
-(*Envs is a tuple of used names (currently unused), map from id to kind, default order for vector types and literal vectors *)
-type envs = Nameset.t * kind Envmap.t * order
-type 'a envs_out = 'a * envs
-
-let id_to_string (Id_aux(id,l)) =
- match id with | Id(x) | DeIid(x) -> x
-
-let var_to_string (Kid_aux(Var v,l)) = v
-
-let typquant_to_quantkinds k_env typquant =
- match typquant with
- | TypQ_aux(tq,_) ->
- (match tq with
- | TypQ_no_forall -> []
- | TypQ_tq(qlist) ->
- List.fold_right
- (fun (QI_aux(qi,_)) rst ->
- match qi with
- | QI_const _ -> rst
- | QI_id(ki) -> begin
- match ki with
- | KOpt_aux(KOpt_none(v),l) | KOpt_aux(KOpt_kind(_,v),l) ->
- (match Envmap.apply k_env (var_to_string v) with
- | Some(typ) -> typ::rst
- | None -> raise (Reporting_basic.err_unreachable l __POS__ "Envmap didn't get an entry during typschm processing"))
- end)
- qlist
- [])
-
-let typ_error l msg opt_id opt_var opt_kind =
- raise (Reporting_basic.err_typ
- l
- (msg ^
- (match opt_id, opt_var, opt_kind with
- | Some(id),None,Some(kind) -> (id_to_string id) ^ " of " ^ (kind_to_string kind)
- | Some(id),None,None -> ": " ^ (id_to_string id)
- | None,Some(v),Some(kind) -> (var_to_string v) ^ " of " ^ (kind_to_string kind)
- | None,Some(v),None -> ": " ^ (var_to_string v)
- | None,None,Some(kind) -> " " ^ (kind_to_string kind)
- | _ -> "")))
+type ctx = {
+ kinds : kind_aux KBindings.t;
+ type_constructors : (kind_aux list) Bindings.t;
+ scattereds : ctx Bindings.t;
+ }
let string_of_parse_id_aux = function
- | Parse_ast.Id v -> v
- | Parse_ast.DeIid v -> v
+ | P.Id v -> v
+ | P.DeIid v -> v
-let string_of_parse_id (Parse_ast.Id_aux(id, l)) = string_of_parse_id_aux id
+let string_of_parse_id (P.Id_aux (id, l)) = string_of_parse_id_aux id
let string_contains str char =
try (ignore (String.index str char); true) with
| Not_found -> false
-let to_ast_id (Parse_ast.Id_aux(id, l)) =
- if string_contains (string_of_parse_id_aux id) '#' && not (!opt_magic_hash)
- then typ_error l "Identifier contains hash character" None None None
- else Id_aux ((match id with
- | Parse_ast.Id(x) -> Id(x)
- | Parse_ast.DeIid(x) -> DeIid(x)),
- l)
-
-let to_ast_var (Parse_ast.Kid_aux(Parse_ast.Var v,l)) = Kid_aux(Var v,l)
+let to_ast_var (P.Kid_aux (P.Var v, l)) = Kid_aux (Var v, l)
-let to_ast_base_kind (Parse_ast.BK_aux(k,l')) =
+let to_ast_kind (P.K_aux (k, l)) =
match k with
- | Parse_ast.BK_type -> BK_aux(BK_type,l'), { k = K_Typ}
- | Parse_ast.BK_int -> BK_aux(BK_int,l'), { k = K_Nat }
- | Parse_ast.BK_order -> BK_aux(BK_order,l'), { k = K_Ord }
-
-let to_ast_kind (k_env : kind Envmap.t) (Parse_ast.K_aux(Parse_ast.K_kind(klst),l)) : (Ast.kind * kind) =
- match klst with
- | [] -> raise (Reporting_basic.err_unreachable l __POS__ "Kind with empty kindlist encountered")
- | [k] -> let k_ast,k_typ = to_ast_base_kind k in
- K_aux(K_kind([k_ast]),l), k_typ
- | ks -> let k_pairs = List.map to_ast_base_kind ks in
- let reverse_typs = List.rev (List.map snd k_pairs) in
- let ret,args = List.hd reverse_typs, List.rev (List.tl reverse_typs) in
- match ret.k with
- | K_Typ -> K_aux(K_kind(List.map fst k_pairs), l), { k = K_Lam(args,ret) }
- | _ -> typ_error l "Type constructor must have an -> kind ending in Type" None None None
-
-let rec to_ast_typ (k_env : kind Envmap.t) (def_ord : order) (t: Parse_ast.atyp) : Ast.typ =
- (* let _ = Printf.eprintf "to_ast_typ\n" in*)
- match t with
- | Parse_ast.ATyp_aux(t,l) ->
- Typ_aux( (match t with
- | Parse_ast.ATyp_id(id) -> Typ_id (to_ast_id id)
- | Parse_ast.ATyp_var(v) ->
- let v = to_ast_var v in
- let mk = Envmap.apply k_env (var_to_string v) in
- (match mk with
- | Some(k) -> (match k.k with
- | K_Typ -> Typ_var v
- | K_infer -> k.k <- K_Typ; Typ_var v
- | _ -> typ_error l "Required a variable with kind Type, encountered " None (Some v) (Some k))
- | None -> typ_error l "Encountered an unbound variable" None (Some v) None)
- | Parse_ast.ATyp_fn(arg,ret,efct) ->
- begin match arg with
- | Parse_ast.ATyp_aux (Parse_ast.ATyp_tup args, _) ->
- Typ_fn (List.map (to_ast_typ k_env def_ord) args,
- (to_ast_typ k_env def_ord ret),
- (to_ast_effects k_env efct))
- | _ -> Typ_fn ([to_ast_typ k_env def_ord arg],
- (to_ast_typ k_env def_ord ret),
- (to_ast_effects k_env efct))
- end
- | Parse_ast.ATyp_bidir (typ1, typ2) -> Typ_bidir ( (to_ast_typ k_env def_ord typ1),
- (to_ast_typ k_env def_ord typ2))
- | Parse_ast.ATyp_tup(typs) -> Typ_tup( List.map (to_ast_typ k_env def_ord) typs)
- | Parse_ast.ATyp_app(Parse_ast.Id_aux(Parse_ast.Id "vector_sugar_tb",il), [ b; r; ord ; ti]) ->
- let make_r bot top =
- match bot,top with
- | Parse_ast.ATyp_aux(Parse_ast.ATyp_constant b,_),Parse_ast.ATyp_aux(Parse_ast.ATyp_constant t,l) ->
- Parse_ast.ATyp_aux(Parse_ast.ATyp_constant (Big_int.add (Big_int.sub t b) (Big_int.of_int 1)),l)
- | bot,(Parse_ast.ATyp_aux(_,l) as top) ->
- Parse_ast.ATyp_aux((Parse_ast.ATyp_sum
- ((Parse_ast.ATyp_aux
- (Parse_ast.ATyp_sum (top,
- Parse_ast.ATyp_aux(Parse_ast.ATyp_constant (Big_int.of_int 1),Parse_ast.Unknown)),
- Parse_ast.Unknown)),
- (Parse_ast.ATyp_aux ((Parse_ast.ATyp_neg bot),Parse_ast.Unknown)))), l) in
- let base = to_ast_nexp k_env b in
- let rise = match def_ord with
- | Ord_aux(Ord_inc,dl) -> to_ast_nexp k_env (make_r b r)
- | Ord_aux(Ord_dec,dl) -> to_ast_nexp k_env (make_r r b)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "Default order not inc or dec") in
- Typ_app(Id_aux(Id "vector",il),
- [Typ_arg_aux (Typ_arg_nexp base,Parse_ast.Unknown);
- Typ_arg_aux (Typ_arg_nexp rise,Parse_ast.Unknown);
- Typ_arg_aux (Typ_arg_order def_ord,Parse_ast.Unknown);
- Typ_arg_aux (Typ_arg_typ (to_ast_typ k_env def_ord ti), Parse_ast.Unknown);])
- | Parse_ast.ATyp_app(Parse_ast.Id_aux(Parse_ast.Id "vector_sugar_r",il), [b;r;ord;ti]) ->
- let make_sub_one t =
- match t with
- | Parse_ast.ATyp_aux(Parse_ast.ATyp_constant t,_) -> Parse_ast.ATyp_aux(Parse_ast.ATyp_constant (Big_int.sub t (Big_int.of_int 1)),l)
- | t -> (Parse_ast.ATyp_aux
- (Parse_ast.ATyp_sum (t, Parse_ast.ATyp_aux(Parse_ast.ATyp_constant (Big_int.negate (Big_int.of_int 1)),Parse_ast.Unknown)),
- Parse_ast.Unknown)) in
- let (base,rise) = match def_ord with
- | Ord_aux(Ord_inc,dl) -> (to_ast_nexp k_env b), (to_ast_nexp k_env r)
- | Ord_aux(Ord_dec,dl) -> (to_ast_nexp k_env (make_sub_one r)), (to_ast_nexp k_env r)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "Default order not inc or dec") in
- Typ_app(Id_aux(Id "vector",il),
- [Typ_arg_aux (Typ_arg_nexp base,Parse_ast.Unknown);
- Typ_arg_aux (Typ_arg_nexp rise,Parse_ast.Unknown);
- Typ_arg_aux (Typ_arg_order def_ord,Parse_ast.Unknown);
- Typ_arg_aux (Typ_arg_typ (to_ast_typ k_env def_ord ti), Parse_ast.Unknown);])
- | Parse_ast.ATyp_app (Parse_ast.Id_aux (Parse_ast.Id "int", il), [n]) ->
- Typ_app(Id_aux(Id "atom", il), [Typ_arg_aux (Typ_arg_nexp (to_ast_nexp k_env n), Parse_ast.Unknown)])
- | Parse_ast.ATyp_app(pid,typs) ->
- let id = to_ast_id pid in
- let k = Envmap.apply k_env (id_to_string id) in
- (match k with
- | Some({k = K_Lam(args,t)}) ->
- if ((List.length args) = (List.length typs))
- then
- Typ_app(id,(List.map2 (fun k a -> (to_ast_typ_arg k_env def_ord k a)) args typs))
- else typ_error l "Type constructor given incorrect number of arguments" (Some id) None None
- | None -> typ_error l "Required a type constructor, encountered an unbound identifier" (Some id) None None
- | _ -> typ_error l "Required a type constructor, encountered a base kind variable" (Some id) None None)
- | Parse_ast.ATyp_exist (kids, nc, atyp) ->
- let kids = List.map to_ast_var kids in
- let k_env = List.fold_left Envmap.insert k_env (List.map (fun kid -> (var_to_string kid, {k=K_Nat})) kids) in
- let exist_typ = to_ast_typ k_env def_ord atyp in
- Typ_exist (kids, to_ast_nexp_constraint k_env nc, exist_typ)
- | _ -> typ_error l "Required an item of kind Type, encountered an illegal form for this kind" None None None
- ), l)
-
-and to_ast_nexp (k_env : kind Envmap.t) (n: Parse_ast.atyp) : Ast.nexp =
- match n with
- | Parse_ast.ATyp_aux(t,l) ->
- (match t with
- | Parse_ast.ATyp_id i -> Nexp_aux (Nexp_id (to_ast_id i), l)
- | Parse_ast.ATyp_var v -> Nexp_aux (Nexp_var (to_ast_var v), l)
- | Parse_ast.ATyp_constant i -> Nexp_aux (Nexp_constant i, l)
- | Parse_ast.ATyp_sum (t1, t2) ->
- let n1 = to_ast_nexp k_env t1 in
- let n2 = to_ast_nexp k_env t2 in
- Nexp_aux (Nexp_sum (n1, n2), l)
- | Parse_ast.ATyp_exp t1 -> Nexp_aux(Nexp_exp(to_ast_nexp k_env t1),l)
- | Parse_ast.ATyp_neg t1 -> Nexp_aux(Nexp_neg(to_ast_nexp k_env t1),l)
- | Parse_ast.ATyp_times (t1, t2) ->
- let n1 = to_ast_nexp k_env t1 in
- let n2 = to_ast_nexp k_env t2 in
- Nexp_aux (Nexp_times (n1, n2), l)
- | Parse_ast.ATyp_minus (t1, t2) ->
- let n1 = to_ast_nexp k_env t1 in
- let n2 = to_ast_nexp k_env t2 in
- Nexp_aux (Nexp_minus (n1, n2), l)
- | Parse_ast.ATyp_app (id, ts) ->
- let nexps = List.map (to_ast_nexp k_env) ts in
- Nexp_aux (Nexp_app (to_ast_id id, nexps), l)
- | _ -> typ_error l "Required an item of kind Nat, encountered an illegal form for this kind" None None None)
-
-and to_ast_order (k_env : kind Envmap.t) (def_ord : order) (o: Parse_ast.atyp) : Ast.order =
- match o with
- | Parse_ast.ATyp_aux(t,l) ->
- (match t with
- | Parse_ast.ATyp_var(v) ->
- let v = to_ast_var v in
- let mk = Envmap.apply k_env (var_to_string v) in
- (match mk with
- | Some(k) -> (match k.k with
- | K_Ord -> Ord_aux(Ord_var v, l)
- | K_infer -> k.k <- K_Ord; Ord_aux(Ord_var v,l)
- | _ -> typ_error l "Required a variable with kind Order, encountered " None (Some v) (Some k))
- | None -> typ_error l "Encountered an unbound variable" None (Some v) None)
- | Parse_ast.ATyp_inc -> Ord_aux(Ord_inc,l)
- | Parse_ast.ATyp_dec -> Ord_aux(Ord_dec,l)
- | Parse_ast.ATyp_default_ord -> def_ord
- | _ -> typ_error l "Required an item of kind Order, encountered an illegal form for this kind" None None None
- )
-
-and to_ast_effects (k_env : kind Envmap.t) (e : Parse_ast.atyp) : Ast.effect =
- match e with
- | Parse_ast.ATyp_aux(t,l) ->
- Effect_aux( (match t with
- | Parse_ast.ATyp_var(v) ->
- let v = to_ast_var v in
- let mk = Envmap.apply k_env (var_to_string v) in
- (match mk with
- | Some k -> typ_error l "Required a variable with kind Effect, encountered " None (Some v) (Some k)
- | None -> typ_error l "Encountered an unbound variable" None (Some v) None)
- | Parse_ast.ATyp_set(effects) ->
- Effect_set( List.map
- (fun efct -> match efct with
- | Parse_ast.BE_aux(e,l) ->
- BE_aux((match e with
- | Parse_ast.BE_barr -> BE_barr
- | Parse_ast.BE_rreg -> BE_rreg
- | Parse_ast.BE_wreg -> BE_wreg
- | Parse_ast.BE_rmem -> BE_rmem
- | Parse_ast.BE_rmemt -> BE_rmemt
- | Parse_ast.BE_wmem -> BE_wmem
- | Parse_ast.BE_wmv -> BE_wmv
- | Parse_ast.BE_wmvt -> BE_wmvt
- | Parse_ast.BE_eamem -> BE_eamem
- | Parse_ast.BE_exmem -> BE_exmem
- | Parse_ast.BE_depend -> BE_depend
- | Parse_ast.BE_undef -> BE_undef
- | Parse_ast.BE_unspec -> BE_unspec
- | Parse_ast.BE_nondet -> BE_nondet
- | Parse_ast.BE_escape -> BE_escape
- | Parse_ast.BE_config -> BE_config),l))
- effects)
- | _ -> typ_error l "Required an item of kind Effects, encountered an illegal form for this kind" None None None
- ), l)
-
-and to_ast_typ_arg (k_env : kind Envmap.t) (def_ord : order) (kind : kind) (arg : Parse_ast.atyp) : Ast.typ_arg =
- let l = (match arg with Parse_ast.ATyp_aux(_,l) -> l) in
- Typ_arg_aux (
- (match kind.k with
- | K_Typ -> Typ_arg_typ (to_ast_typ k_env def_ord arg)
- | K_Nat -> Typ_arg_nexp (to_ast_nexp k_env arg)
- | K_Ord -> Typ_arg_order (to_ast_order k_env def_ord arg)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ ("To_ast_typ_arg received Lam kind or infer kind: " ^ kind_to_string kind))),
- l)
+ | P.K_type -> K_aux (K_type, l)
+ | P.K_int -> K_aux (K_int, l)
+ | P.K_order -> K_aux (K_order, l)
+ | P.K_bool -> K_aux (K_bool, l)
+
+let to_ast_id (P.Id_aux(id, l)) =
+ if string_contains (string_of_parse_id_aux id) '#' && not (!opt_magic_hash) then
+ raise (Reporting.err_general l "Identifier contains hash character and -dmagic_hash is unset")
+ else
+ Id_aux ((match id with
+ | P.Id x -> Id x
+ | P.DeIid x -> DeIid x),
+ l)
+
+let to_ast_var (P.Kid_aux (P.Var v, l)) = Kid_aux (Var v, l)
+
+let to_ast_effects = function
+ | P.ATyp_aux (P.ATyp_set effects, l) ->
+ let to_effect (P.BE_aux (e, l)) =
+ BE_aux ((match e with
+ | P.BE_barr -> BE_barr
+ | P.BE_rreg -> BE_rreg
+ | P.BE_wreg -> BE_wreg
+ | P.BE_rmem -> BE_rmem
+ | P.BE_rmemt -> BE_rmemt
+ | P.BE_wmem -> BE_wmem
+ | P.BE_wmv -> BE_wmv
+ | P.BE_wmvt -> BE_wmvt
+ | P.BE_eamem -> BE_eamem
+ | P.BE_exmem -> BE_exmem
+ | P.BE_depend -> BE_depend
+ | P.BE_undef -> BE_undef
+ | P.BE_unspec -> BE_unspec
+ | P.BE_nondet -> BE_nondet
+ | P.BE_escape -> BE_escape
+ | P.BE_config -> BE_config),
+ l)
+ in
+ Effect_aux (Effect_set (List.map to_effect effects), l)
+ | P.ATyp_aux (_, l) ->
+ raise (Reporting.err_typ l "Invalid effect set")
+
+(* Used for error messages involving lists of kinds *)
+let format_kind_aux_list = function
+ | [kind] -> string_of_kind_aux kind
+ | kinds -> "(" ^ Util.string_of_list ", " string_of_kind_aux kinds ^ ")"
+
+let to_ast_kopt ctx (P.KOpt_aux (aux, l)) =
+ let aux, ctx = match aux with
+ | P.KOpt_none v ->
+ let v = to_ast_var v in
+ KOpt_kind (K_aux (K_int, gen_loc l), v), { ctx with kinds = KBindings.add v K_int ctx.kinds }
+ | P.KOpt_kind (k, v) ->
+ let v = to_ast_var v in
+ let k = to_ast_kind k in
+ KOpt_kind (k, v), { ctx with kinds = KBindings.add v (unaux_kind k) ctx.kinds }
+ in
+ KOpt_aux (aux, l), ctx
+
+let rec to_ast_typ ctx (P.ATyp_aux (aux, l)) =
+ let aux = match aux with
+ | P.ATyp_id id -> Typ_id (to_ast_id id)
+ | P.ATyp_var v -> Typ_var (to_ast_var v)
+ | P.ATyp_fn (from_typ, to_typ, effects) ->
+ let from_typs = match from_typ with
+ | P.ATyp_aux (P.ATyp_tup typs, _) ->
+ List.map (to_ast_typ ctx) typs
+ | _ -> [to_ast_typ ctx from_typ]
+ in
+ Typ_fn (from_typs, to_ast_typ ctx to_typ, to_ast_effects effects)
+ | P.ATyp_bidir (typ1, typ2) -> Typ_bidir (to_ast_typ ctx typ1, to_ast_typ ctx typ2)
+ | P.ATyp_tup typs -> Typ_tup (List.map (to_ast_typ ctx) typs)
+ | P.ATyp_app (P.Id_aux (P.Id "int", il), [n]) ->
+ Typ_app (Id_aux (Id "atom", il), [to_ast_typ_arg ctx n K_int])
+ | P.ATyp_app (P.Id_aux (P.Id "bool", il), [n]) ->
+ Typ_app (Id_aux (Id "atom_bool", il), [to_ast_typ_arg ctx n K_bool])
+ | P.ATyp_app (id, args) ->
+ let id = to_ast_id id in
+ begin match Bindings.find_opt id ctx.type_constructors with
+ | None -> raise (Reporting.err_typ l (sprintf "Could not find type constructor %s" (string_of_id id)))
+ | Some kinds when List.length args <> List.length kinds ->
+ raise (Reporting.err_typ l (sprintf "%s : %s -> Type expected %d arguments, given %d"
+ (string_of_id id) (format_kind_aux_list kinds)
+ (List.length kinds) (List.length args)))
+ | Some kinds ->
+ Typ_app (id, List.map2 (to_ast_typ_arg ctx) args kinds)
+ end
+ | P.ATyp_exist (kopts, nc, atyp) ->
+ let kopts, ctx =
+ List.fold_right (fun kopt (kopts, ctx) -> let kopt, ctx = to_ast_kopt ctx kopt in (kopt :: kopts, ctx)) kopts ([], ctx)
+ in
+ Typ_exist (kopts, to_ast_constraint ctx nc, to_ast_typ ctx atyp)
+ | P.ATyp_base (id, kind, nc) ->
+ raise (Reporting.err_unreachable l __POS__ "TODO")
+ | _ -> raise (Reporting.err_typ l "Invalid type")
+ in
+ Typ_aux (aux, l)
+
+and to_ast_typ_arg ctx (ATyp_aux (_, l) as atyp) = function
+ | K_type -> A_aux (A_typ (to_ast_typ ctx atyp), l)
+ | K_int -> A_aux (A_nexp (to_ast_nexp ctx atyp), l)
+ | K_order -> A_aux (A_order (to_ast_order ctx atyp), l)
+ | K_bool -> A_aux (A_bool (to_ast_constraint ctx atyp), l)
+
+and to_ast_nexp ctx (P.ATyp_aux (aux, l)) =
+ let aux = match aux with
+ | P.ATyp_id id -> Nexp_id (to_ast_id id)
+ | P.ATyp_var v -> Nexp_var (to_ast_var v)
+ | P.ATyp_lit (P.L_aux (P.L_num c, _)) -> Nexp_constant c
+ | P.ATyp_sum (t1, t2) -> Nexp_sum (to_ast_nexp ctx t1, to_ast_nexp ctx t2)
+ | P.ATyp_exp t1 -> Nexp_exp (to_ast_nexp ctx t1)
+ | P.ATyp_neg t1 -> Nexp_neg (to_ast_nexp ctx t1)
+ | P.ATyp_times (t1, t2) -> Nexp_times (to_ast_nexp ctx t1, to_ast_nexp ctx t2)
+ | P.ATyp_minus (t1, t2) -> Nexp_minus (to_ast_nexp ctx t1, to_ast_nexp ctx t2)
+ | P.ATyp_app (id, ts) -> Nexp_app (to_ast_id id, List.map (to_ast_nexp ctx) ts)
+ | _ -> raise (Reporting.err_typ l "Invalid numeric expression in type")
+ in
+ Nexp_aux (aux, l)
-and to_ast_nexp_constraint (k_env : kind Envmap.t) (c : Parse_ast.n_constraint) : n_constraint =
- match c with
- | Parse_ast.NC_aux(nc,l) ->
- NC_aux( (match nc with
- | Parse_ast.NC_equal(t1,t2) ->
- let n1 = to_ast_nexp k_env t1 in
- let n2 = to_ast_nexp k_env t2 in
- NC_equal(n1,n2)
- | Parse_ast.NC_not_equal(t1,t2) ->
- let n1 = to_ast_nexp k_env t1 in
- let n2 = to_ast_nexp k_env t2 in
- NC_not_equal(n1,n2)
- | Parse_ast.NC_bounded_ge(t1,t2) ->
- let n1 = to_ast_nexp k_env t1 in
- let n2 = to_ast_nexp k_env t2 in
- NC_bounded_ge(n1,n2)
- | Parse_ast.NC_bounded_le(t1,t2) ->
- let n1 = to_ast_nexp k_env t1 in
- let n2 = to_ast_nexp k_env t2 in
- NC_bounded_le(n1,n2)
- | Parse_ast.NC_set(id,bounds) ->
- NC_set(to_ast_var id, bounds)
- | Parse_ast.NC_or (nc1, nc2) ->
- NC_or (to_ast_nexp_constraint k_env nc1, to_ast_nexp_constraint k_env nc2)
- | Parse_ast.NC_and (nc1, nc2) ->
- NC_and (to_ast_nexp_constraint k_env nc1, to_ast_nexp_constraint k_env nc2)
- | Parse_ast.NC_app (id, typs) ->
- let nexps = List.map (to_ast_nexp k_env) typs in
- NC_app (to_ast_id id, nexps)
- | Parse_ast.NC_true -> NC_true
- | Parse_ast.NC_false -> NC_false
- ), l)
-
-(* Transforms a typquant while building first the kind environment of declared variables, and also the kind environment in context *)
-let to_ast_typquant (k_env: kind Envmap.t) (tq : Parse_ast.typquant) : typquant * kind Envmap.t * kind Envmap.t =
- let opt_kind_to_ast k_env local_names local_env (Parse_ast.KOpt_aux(ki,l)) =
- let v, key, kind, ktyp =
- match ki with
- | Parse_ast.KOpt_none(v) ->
- let v = to_ast_var v in
- let key = var_to_string v in
- let kind,ktyp = if (Envmap.in_dom key k_env) then None,(Envmap.apply k_env key) else None,(Some{ k = K_infer }) in
- v,key,kind, ktyp
- | Parse_ast.KOpt_kind(k,v) ->
- let v = to_ast_var v in
- let key = var_to_string v in
- let kind,ktyp = to_ast_kind k_env k in
- v,key,Some(kind),Some(ktyp)
- in
- if (Nameset.mem key local_names)
- then typ_error l "Encountered duplicate name in type scheme" None (Some v) None
- else
- let local_names = Nameset.add key local_names in
- let kopt,k_env,k_env_local = (match kind,ktyp with
- | Some(k),Some(kt) -> KOpt_kind(k,v), (Envmap.insert k_env (key,kt)), (Envmap.insert local_env (key,kt))
- | None, Some(kt) -> KOpt_none(v), (Envmap.insert k_env (key,kt)), (Envmap.insert local_env (key,kt))
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "Envmap in dom is true but apply gives None")) in
- KOpt_aux(kopt,l),k_env,local_names,k_env_local
+and to_ast_order ctx (P.ATyp_aux (aux, l)) =
+ match aux with
+ | ATyp_var v -> Ord_aux (Ord_var (to_ast_var v), l)
+ | ATyp_inc -> Ord_aux (Ord_inc, l)
+ | ATyp_dec -> Ord_aux (Ord_dec, l)
+ | _ -> raise (Reporting.err_typ l "Invalid order in type")
+
+and to_ast_constraint ctx (P.ATyp_aux (aux, l) as atyp) =
+ let aux = match aux with
+ | P.ATyp_app (Id_aux (DeIid op, _) as id, [t1; t2]) ->
+ begin match op with
+ | "==" -> NC_equal (to_ast_nexp ctx t1, to_ast_nexp ctx t2)
+ | "!=" -> NC_not_equal (to_ast_nexp ctx t1, to_ast_nexp ctx t2)
+ | ">=" -> NC_bounded_ge (to_ast_nexp ctx t1, to_ast_nexp ctx t2)
+ | "<=" -> NC_bounded_le (to_ast_nexp ctx t1, to_ast_nexp ctx t2)
+ | ">" -> NC_bounded_ge (to_ast_nexp ctx t1, nsum (to_ast_nexp ctx t2) (nint 1))
+ | "<" -> NC_bounded_le (nsum (to_ast_nexp ctx t1) (nint 1), to_ast_nexp ctx t2)
+ | "&" -> NC_and (to_ast_constraint ctx t1, to_ast_constraint ctx t2)
+ | "|" -> NC_or (to_ast_constraint ctx t1, to_ast_constraint ctx t2)
+ | _ ->
+ let id = to_ast_id id in
+ match Bindings.find_opt id ctx.type_constructors with
+ | None -> raise (Reporting.err_typ l (sprintf "Could not find type constructor %s" (string_of_id id)))
+ | Some kinds when List.length kinds <> 2 ->
+ raise (Reporting.err_typ l (sprintf "%s : %s -> Bool expected %d arguments, given 2"
+ (string_of_id id) (format_kind_aux_list kinds)
+ (List.length kinds)))
+ | Some kinds -> NC_app (id, List.map2 (to_ast_typ_arg ctx) [t1; t2] kinds)
+ end
+ | P.ATyp_app (id, args) ->
+ let id = to_ast_id id in
+ begin match Bindings.find_opt id ctx.type_constructors with
+ | None -> raise (Reporting.err_typ l (sprintf "Could not find type constructor %s" (string_of_id id)))
+ | Some kinds when List.length args <> List.length kinds ->
+ raise (Reporting.err_typ l (sprintf "%s : %s -> Bool expected %d arguments, given %d"
+ (string_of_id id) (format_kind_aux_list kinds)
+ (List.length kinds) (List.length args)))
+ | Some kinds -> NC_app (id, List.map2 (to_ast_typ_arg ctx) args kinds)
+ end
+ | P.ATyp_var v -> NC_var (to_ast_var v)
+ | P.ATyp_lit (P.L_aux (P.L_true, _)) -> NC_true
+ | P.ATyp_lit (P.L_aux (P.L_false, _)) -> NC_false
+ | P.ATyp_nset (id, bounds) -> NC_set (to_ast_var id, bounds)
+ | _ -> raise (Reporting.err_typ l "Invalid constraint")
in
- match tq with
- | Parse_ast.TypQ_aux(tqa,l) ->
- (match tqa with
- | Parse_ast.TypQ_no_forall -> TypQ_aux(TypQ_no_forall,l), k_env, Envmap.empty
- | Parse_ast.TypQ_tq(qlist) ->
- let rec to_ast_q_items k_env local_names local_env = function
- | [] -> [],k_env,local_env
- | q::qs -> (match q with
- | Parse_ast.QI_aux(qi,l) ->
- (match qi with
- | Parse_ast.QI_const(n_const) ->
- let c = QI_aux(QI_const(to_ast_nexp_constraint k_env n_const),l) in
- let qis,k_env,local_env = to_ast_q_items k_env local_names local_env qs in
- (c::qis),k_env,local_env
- | Parse_ast.QI_id(kid) ->
- let kid,k_env,local_names,local_env = opt_kind_to_ast k_env local_names local_env kid in
- let c = QI_aux(QI_id(kid),l) in
- let qis,k_env,local_env = to_ast_q_items k_env local_names local_env qs in
- (c::qis),k_env,local_env))
- in
- let lst,k_env,local_env = to_ast_q_items k_env Nameset.empty Envmap.empty qlist in
- TypQ_aux(TypQ_tq(lst),l), k_env, local_env)
-
-let to_ast_typschm (k_env:kind Envmap.t) (def_ord:order) (tschm:Parse_ast.typschm) :Ast.typschm * kind Envmap.t * kind Envmap.t =
- match tschm with
- | Parse_ast.TypSchm_aux(ts,l) ->
- (match ts with | Parse_ast.TypSchm_ts(tquant,t) ->
- let tq,k_env,local_env = to_ast_typquant k_env tquant in
- let typ = to_ast_typ k_env def_ord t in
- TypSchm_aux(TypSchm_ts(tq,typ),l),k_env,local_env)
-
-let to_ast_lit (Parse_ast.L_aux(lit,l)) : lit =
- L_aux(
- (match lit with
- | Parse_ast.L_unit -> L_unit
- | Parse_ast.L_zero -> L_zero
- | Parse_ast.L_one -> L_one
- | Parse_ast.L_true -> L_true
- | Parse_ast.L_false -> L_false
- | Parse_ast.L_undef -> L_undef
- | Parse_ast.L_num(i) -> L_num(i)
- | Parse_ast.L_hex(h) -> L_hex(h)
- | Parse_ast.L_bin(b) -> L_bin(b)
- | Parse_ast.L_real r -> L_real r
- | Parse_ast.L_string(s) -> L_string(s))
- ,l)
-
-let rec to_ast_typ_pat (Parse_ast.ATyp_aux (typ_aux, l)) =
- match typ_aux with
- | Parse_ast.ATyp_wild -> TP_aux (TP_wild, l)
- | Parse_ast.ATyp_var kid -> TP_aux (TP_var (to_ast_var kid), l)
- | Parse_ast.ATyp_app (Parse_ast.Id_aux (Parse_ast.Id "int", il), typs) ->
- TP_aux (TP_app (Id_aux (Id "atom", il), List.map to_ast_typ_pat typs), l)
- | Parse_ast.ATyp_app (f, typs) ->
- TP_aux (TP_app (to_ast_id f, List.map to_ast_typ_pat typs), l)
- | _ -> typ_error l "Unexpected type in type pattern" None None None
-
-let rec to_ast_pat (k_env : kind Envmap.t) (def_ord : order) (Parse_ast.P_aux(pat,l) : Parse_ast.pat) : unit pat =
- P_aux(
- (match pat with
- | Parse_ast.P_lit(lit) -> P_lit(to_ast_lit lit)
- | Parse_ast.P_wild -> P_wild
- | Parse_ast.P_or(pat1, pat2) ->
- P_or (to_ast_pat k_env def_ord pat1, to_ast_pat k_env def_ord pat2)
- | Parse_ast.P_var (pat, Parse_ast.ATyp_aux (Parse_ast.ATyp_id id, _)) ->
- P_as (to_ast_pat k_env def_ord pat, to_ast_id id)
- | Parse_ast.P_typ(typ,pat) -> P_typ(to_ast_typ k_env def_ord typ,to_ast_pat k_env def_ord pat)
- | Parse_ast.P_id(id) -> P_id(to_ast_id id)
- | Parse_ast.P_var (pat, typ) -> P_var (to_ast_pat k_env def_ord pat, to_ast_typ_pat typ)
- | Parse_ast.P_app(id, []) -> P_id (to_ast_id id)
- | Parse_ast.P_app(id, pats) ->
- if List.length pats == 1 && string_of_parse_id id = "~"
- then P_not (to_ast_pat k_env def_ord (List.hd pats))
- else P_app(to_ast_id id, List.map (to_ast_pat k_env def_ord) pats)
- | Parse_ast.P_record(fpats,_) ->
- P_record(List.map
- (fun (Parse_ast.FP_aux(Parse_ast.FP_Fpat(id,fp),l)) ->
- FP_aux(FP_Fpat(to_ast_id id, to_ast_pat k_env def_ord fp),(l,())))
- fpats, false)
- | Parse_ast.P_vector(pats) -> P_vector(List.map (to_ast_pat k_env def_ord) pats)
- | Parse_ast.P_vector_concat(pats) -> P_vector_concat(List.map (to_ast_pat k_env def_ord) pats)
- | Parse_ast.P_tup(pats) -> P_tup(List.map (to_ast_pat k_env def_ord) pats)
- | Parse_ast.P_list(pats) -> P_list(List.map (to_ast_pat k_env def_ord) pats)
- | Parse_ast.P_cons(pat1, pat2) -> P_cons (to_ast_pat k_env def_ord pat1, to_ast_pat k_env def_ord pat2)
- | Parse_ast.P_string_append pats -> P_string_append (List.map (to_ast_pat k_env def_ord) pats)
- ), (l,()))
+ NC_aux (aux, l)
+let to_ast_quant_item ctx (P.QI_aux (aux, l)) =
+ match aux with
+ | P.QI_const nc -> QI_aux (QI_const (to_ast_constraint ctx nc), l), ctx
+ | P.QI_id kopt ->
+ let kopt, ctx = to_ast_kopt ctx kopt in
+ QI_aux (QI_id kopt, l), ctx
-let rec to_ast_letbind (k_env : kind Envmap.t) (def_ord : order) (Parse_ast.LB_aux(lb,l) : Parse_ast.letbind) : unit letbind =
+let to_ast_typquant ctx (P.TypQ_aux (aux, l)) =
+ match aux with
+ | P.TypQ_no_forall -> TypQ_aux (TypQ_no_forall, l), ctx
+ | P.TypQ_tq quants ->
+ let quants, ctx =
+ List.fold_left (fun (qis, ctx) qi -> let qi', ctx = to_ast_quant_item ctx qi in qi' :: qis, ctx) ([], ctx) quants
+ in
+ TypQ_aux (TypQ_tq (List.rev quants), l), ctx
+
+let to_ast_typschm ctx (P.TypSchm_aux (P.TypSchm_ts (typq, typ), l)) =
+ let typq, ctx = to_ast_typquant ctx typq in
+ let typ = to_ast_typ ctx typ in
+ TypSchm_aux (TypSchm_ts (typq, typ), l), ctx
+
+let to_ast_lit (P.L_aux (lit, l)) =
+ L_aux ((match lit with
+ | P.L_unit -> L_unit
+ | P.L_zero -> L_zero
+ | P.L_one -> L_one
+ | P.L_true -> L_true
+ | P.L_false -> L_false
+ | P.L_undef -> L_undef
+ | P.L_num i -> L_num i
+ | P.L_hex h -> L_hex h
+ | P.L_bin b -> L_bin b
+ | P.L_real r -> L_real r
+ | P.L_string s -> L_string s)
+ ,l)
+
+let rec to_ast_typ_pat (P.ATyp_aux (aux, l)) =
+ match aux with
+ | P.ATyp_wild -> TP_aux (TP_wild, l)
+ | P.ATyp_var kid -> TP_aux (TP_var (to_ast_var kid), l)
+ | P.ATyp_app (P.Id_aux (P.Id "int", il), typs) ->
+ TP_aux (TP_app (Id_aux (Id "atom", il), List.map to_ast_typ_pat typs), l)
+ | P.ATyp_app (f, typs) ->
+ TP_aux (TP_app (to_ast_id f, List.map to_ast_typ_pat typs), l)
+ | _ -> raise (Reporting.err_typ l "Unexpected type in type pattern")
+
+let rec to_ast_pat ctx (P.P_aux (pat, l)) =
+ P_aux ((match pat with
+ | P.P_lit lit -> P_lit (to_ast_lit lit)
+ | P.P_wild -> P_wild
+ | P.P_or (pat1, pat2) ->
+ P_or (to_ast_pat ctx pat1, to_ast_pat ctx pat2)
+ | P.P_var (pat, P.ATyp_aux (P.ATyp_id id, _)) ->
+ P_as (to_ast_pat ctx pat, to_ast_id id)
+ | P.P_typ (typ, pat) -> P_typ (to_ast_typ ctx typ, to_ast_pat ctx pat)
+ | P.P_id id -> P_id (to_ast_id id)
+ | P.P_var (pat, typ) -> P_var (to_ast_pat ctx pat, to_ast_typ_pat typ)
+ | P.P_app (id, []) -> P_id (to_ast_id id)
+ | P.P_app (id, pats) ->
+ if List.length pats == 1 && string_of_parse_id id = "~"
+ then P_not (to_ast_pat ctx (List.hd pats))
+ else P_app (to_ast_id id, List.map (to_ast_pat ctx) pats)
+ | P.P_record(fpats,_) ->
+ P_record(List.map
+ (fun (P.FP_aux(P.FP_Fpat(id,fp),l)) ->
+ FP_aux(FP_Fpat(to_ast_id id, to_ast_pat ctx fp),(l,())))
+ fpats, false)
+ | P.P_vector(pats) -> P_vector(List.map (to_ast_pat ctx) pats)
+ | P.P_vector_concat(pats) -> P_vector_concat(List.map (to_ast_pat ctx) pats)
+ | P.P_tup(pats) -> P_tup(List.map (to_ast_pat ctx) pats)
+ | P.P_list(pats) -> P_list(List.map (to_ast_pat ctx) pats)
+ | P.P_cons(pat1, pat2) -> P_cons (to_ast_pat ctx pat1, to_ast_pat ctx pat2)
+ | P.P_string_append pats -> P_string_append (List.map (to_ast_pat ctx) pats)
+ ), (l,()))
+
+let rec to_ast_letbind ctx (P.LB_aux(lb,l) : P.letbind) : unit letbind =
LB_aux(
(match lb with
- | Parse_ast.LB_val(pat,exp) ->
- LB_val(to_ast_pat k_env def_ord pat, to_ast_exp k_env def_ord exp)
+ | P.LB_val(pat,exp) ->
+ LB_val(to_ast_pat ctx pat, to_ast_exp ctx exp)
), (l,()))
-and to_ast_exp (k_env : kind Envmap.t) (def_ord : order) (Parse_ast.E_aux(exp,l) : Parse_ast.exp) : unit exp =
+and to_ast_exp ctx (P.E_aux(exp,l) : P.exp) =
E_aux(
(match exp with
- | Parse_ast.E_block(exps) ->
- (match to_ast_fexps false k_env def_ord exps with
+ | P.E_block(exps) ->
+ (match to_ast_fexps false ctx exps with
| Some(fexps) -> E_record(fexps)
- | None -> E_block(List.map (to_ast_exp k_env def_ord) exps))
- | Parse_ast.E_nondet(exps) -> E_nondet(List.map (to_ast_exp k_env def_ord) exps)
- | Parse_ast.E_id(id) -> E_id(to_ast_id id)
- | Parse_ast.E_ref(id) -> E_ref(to_ast_id id)
- | Parse_ast.E_lit(lit) -> E_lit(to_ast_lit lit)
- | Parse_ast.E_cast(typ,exp) -> E_cast(to_ast_typ k_env def_ord typ, to_ast_exp k_env def_ord exp)
- | Parse_ast.E_app(f,args) ->
- (match List.map (to_ast_exp k_env def_ord) args with
+ | None -> E_block(List.map (to_ast_exp ctx) exps))
+ | P.E_nondet(exps) -> E_nondet(List.map (to_ast_exp ctx) exps)
+ | P.E_id(id) -> E_id(to_ast_id id)
+ | P.E_ref(id) -> E_ref(to_ast_id id)
+ | P.E_lit(lit) -> E_lit(to_ast_lit lit)
+ | P.E_cast(typ,exp) -> E_cast(to_ast_typ ctx typ, to_ast_exp ctx exp)
+ | P.E_app(f,args) ->
+ (match List.map (to_ast_exp ctx) args with
| [] -> E_app(to_ast_id f, [])
| exps -> E_app(to_ast_id f, exps))
- | Parse_ast.E_app_infix(left,op,right) ->
- E_app_infix(to_ast_exp k_env def_ord left, to_ast_id op, to_ast_exp k_env def_ord right)
- | Parse_ast.E_tuple(exps) -> E_tuple(List.map (to_ast_exp k_env def_ord) exps)
- | Parse_ast.E_if(e1,e2,e3) -> E_if(to_ast_exp k_env def_ord e1, to_ast_exp k_env def_ord e2, to_ast_exp k_env def_ord e3)
- | Parse_ast.E_for(id,e1,e2,e3,atyp,e4) ->
- E_for(to_ast_id id,to_ast_exp k_env def_ord e1, to_ast_exp k_env def_ord e2,
- to_ast_exp k_env def_ord e3,to_ast_order k_env def_ord atyp, to_ast_exp k_env def_ord e4)
- | Parse_ast.E_loop (Parse_ast.While, e1, e2) -> E_loop (While, to_ast_exp k_env def_ord e1, to_ast_exp k_env def_ord e2)
- | Parse_ast.E_loop (Parse_ast.Until, e1, e2) -> E_loop (Until, to_ast_exp k_env def_ord e1, to_ast_exp k_env def_ord e2)
- | Parse_ast.E_vector(exps) -> E_vector(List.map (to_ast_exp k_env def_ord) exps)
- | Parse_ast.E_vector_access(vexp,exp) -> E_vector_access(to_ast_exp k_env def_ord vexp, to_ast_exp k_env def_ord exp)
- | Parse_ast.E_vector_subrange(vex,exp1,exp2) ->
- E_vector_subrange(to_ast_exp k_env def_ord vex, to_ast_exp k_env def_ord exp1, to_ast_exp k_env def_ord exp2)
- | Parse_ast.E_vector_update(vex,exp1,exp2) ->
- E_vector_update(to_ast_exp k_env def_ord vex, to_ast_exp k_env def_ord exp1, to_ast_exp k_env def_ord exp2)
- | Parse_ast.E_vector_update_subrange(vex,e1,e2,e3) ->
- E_vector_update_subrange(to_ast_exp k_env def_ord vex, to_ast_exp k_env def_ord e1,
- to_ast_exp k_env def_ord e2, to_ast_exp k_env def_ord e3)
- | Parse_ast.E_vector_append(e1,e2) -> E_vector_append(to_ast_exp k_env def_ord e1,to_ast_exp k_env def_ord e2)
- | Parse_ast.E_list(exps) -> E_list(List.map (to_ast_exp k_env def_ord) exps)
- | Parse_ast.E_cons(e1,e2) -> E_cons(to_ast_exp k_env def_ord e1, to_ast_exp k_env def_ord e2)
- | Parse_ast.E_record fexps ->
- (match to_ast_fexps true k_env def_ord fexps with
+ | P.E_app_infix(left,op,right) ->
+ E_app_infix(to_ast_exp ctx left, to_ast_id op, to_ast_exp ctx right)
+ | P.E_tuple(exps) -> E_tuple(List.map (to_ast_exp ctx) exps)
+ | P.E_if(e1,e2,e3) -> E_if(to_ast_exp ctx e1, to_ast_exp ctx e2, to_ast_exp ctx e3)
+ | P.E_for(id,e1,e2,e3,atyp,e4) ->
+ E_for(to_ast_id id,to_ast_exp ctx e1, to_ast_exp ctx e2,
+ to_ast_exp ctx e3,to_ast_order ctx atyp, to_ast_exp ctx e4)
+ | P.E_loop (P.While, e1, e2) -> E_loop (While, to_ast_exp ctx e1, to_ast_exp ctx e2)
+ | P.E_loop (P.Until, e1, e2) -> E_loop (Until, to_ast_exp ctx e1, to_ast_exp ctx e2)
+ | P.E_vector(exps) -> E_vector(List.map (to_ast_exp ctx) exps)
+ | P.E_vector_access(vexp,exp) -> E_vector_access(to_ast_exp ctx vexp, to_ast_exp ctx exp)
+ | P.E_vector_subrange(vex,exp1,exp2) ->
+ E_vector_subrange(to_ast_exp ctx vex, to_ast_exp ctx exp1, to_ast_exp ctx exp2)
+ | P.E_vector_update(vex,exp1,exp2) ->
+ E_vector_update(to_ast_exp ctx vex, to_ast_exp ctx exp1, to_ast_exp ctx exp2)
+ | P.E_vector_update_subrange(vex,e1,e2,e3) ->
+ E_vector_update_subrange(to_ast_exp ctx vex, to_ast_exp ctx e1,
+ to_ast_exp ctx e2, to_ast_exp ctx e3)
+ | P.E_vector_append(e1,e2) -> E_vector_append(to_ast_exp ctx e1,to_ast_exp ctx e2)
+ | P.E_list(exps) -> E_list(List.map (to_ast_exp ctx) exps)
+ | P.E_cons(e1,e2) -> E_cons(to_ast_exp ctx e1, to_ast_exp ctx e2)
+ | P.E_record fexps ->
+ (match to_ast_fexps true ctx fexps with
| Some fexps -> E_record fexps
- | None -> raise (Reporting_basic.err_unreachable l __POS__ "to_ast_fexps with true returned none"))
- | Parse_ast.E_record_update(exp,fexps) ->
- (match to_ast_fexps true k_env def_ord fexps with
- | Some(fexps) -> E_record_update(to_ast_exp k_env def_ord exp, fexps)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "to_ast_fexps with true returned none"))
- | Parse_ast.E_field(exp,id) -> E_field(to_ast_exp k_env def_ord exp, to_ast_id id)
- | Parse_ast.E_case(exp,pexps) -> E_case(to_ast_exp k_env def_ord exp, List.map (to_ast_case k_env def_ord) pexps)
- | Parse_ast.E_try (exp, pexps) -> E_try (to_ast_exp k_env def_ord exp, List.map (to_ast_case k_env def_ord) pexps)
- | Parse_ast.E_let(leb,exp) -> E_let(to_ast_letbind k_env def_ord leb, to_ast_exp k_env def_ord exp)
- | Parse_ast.E_assign(lexp,exp) -> E_assign(to_ast_lexp k_env def_ord lexp, to_ast_exp k_env def_ord exp)
- | Parse_ast.E_var(lexp,exp1,exp2) -> E_var(to_ast_lexp k_env def_ord lexp, to_ast_exp k_env def_ord exp1, to_ast_exp k_env def_ord exp2)
- | Parse_ast.E_sizeof(nexp) -> E_sizeof(to_ast_nexp k_env nexp)
- | Parse_ast.E_constraint nc -> E_constraint (to_ast_nexp_constraint k_env nc)
- | Parse_ast.E_exit exp -> E_exit(to_ast_exp k_env def_ord exp)
- | Parse_ast.E_throw exp -> E_throw (to_ast_exp k_env def_ord exp)
- | Parse_ast.E_return exp -> E_return(to_ast_exp k_env def_ord exp)
- | Parse_ast.E_assert(cond,msg) -> E_assert(to_ast_exp k_env def_ord cond, to_ast_exp k_env def_ord msg)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "Unparsable construct in to_ast_exp")
+ | None -> raise (Reporting.err_unreachable l __POS__ "to_ast_fexps with true returned none"))
+ | P.E_record_update(exp,fexps) ->
+ (match to_ast_fexps true ctx fexps with
+ | Some(fexps) -> E_record_update(to_ast_exp ctx exp, fexps)
+ | _ -> raise (Reporting.err_unreachable l __POS__ "to_ast_fexps with true returned none"))
+ | P.E_field(exp,id) -> E_field(to_ast_exp ctx exp, to_ast_id id)
+ | P.E_case(exp,pexps) -> E_case(to_ast_exp ctx exp, List.map (to_ast_case ctx) pexps)
+ | P.E_try (exp, pexps) -> E_try (to_ast_exp ctx exp, List.map (to_ast_case ctx) pexps)
+ | P.E_let(leb,exp) -> E_let(to_ast_letbind ctx leb, to_ast_exp ctx exp)
+ | P.E_assign(lexp,exp) -> E_assign(to_ast_lexp ctx lexp, to_ast_exp ctx exp)
+ | P.E_var(lexp,exp1,exp2) -> E_var(to_ast_lexp ctx lexp, to_ast_exp ctx exp1, to_ast_exp ctx exp2)
+ | P.E_sizeof(nexp) -> E_sizeof(to_ast_nexp ctx nexp)
+ | P.E_constraint nc -> E_constraint (to_ast_constraint ctx nc)
+ | P.E_exit exp -> E_exit(to_ast_exp ctx exp)
+ | P.E_throw exp -> E_throw (to_ast_exp ctx exp)
+ | P.E_return exp -> E_return(to_ast_exp ctx exp)
+ | P.E_assert(cond,msg) -> E_assert(to_ast_exp ctx cond, to_ast_exp ctx msg)
+ | _ -> raise (Reporting.err_unreachable l __POS__ "Unparsable construct in to_ast_exp")
), (l,()))
-and to_ast_lexp (k_env : kind Envmap.t) (def_ord : order) (Parse_ast.E_aux(exp,l) : Parse_ast.exp) : unit lexp =
+and to_ast_lexp ctx (P.E_aux(exp,l) : P.exp) : unit lexp =
let lexp = match exp with
- | Parse_ast.E_id id -> LEXP_id (to_ast_id id)
- | Parse_ast.E_deref exp -> LEXP_deref (to_ast_exp k_env def_ord exp)
- | Parse_ast.E_cast (typ, Parse_ast.E_aux (Parse_ast.E_id id, l')) ->
- LEXP_cast (to_ast_typ k_env def_ord typ, to_ast_id id)
- | Parse_ast.E_tuple tups ->
- let ltups = List.map (to_ast_lexp k_env def_ord) tups in
+ | P.E_id id -> LEXP_id (to_ast_id id)
+ | P.E_deref exp -> LEXP_deref (to_ast_exp ctx exp)
+ | P.E_cast (typ, P.E_aux (P.E_id id, l')) ->
+ LEXP_cast (to_ast_typ ctx typ, to_ast_id id)
+ | P.E_tuple tups ->
+ let ltups = List.map (to_ast_lexp ctx) tups in
let is_ok_in_tup (LEXP_aux (le, (l, _))) =
match le with
| LEXP_id _ | LEXP_cast _ | LEXP_vector _ | LEXP_vector_concat _ | LEXP_field _ | LEXP_vector_range _ | LEXP_tup _ -> ()
| LEXP_memory _ | LEXP_deref _ ->
- typ_error l "only identifiers, fields, and vectors may be set in a tuple" None None None
+ raise (Reporting.err_typ l "only identifiers, fields, and vectors may be set in a tuple")
in
List.iter is_ok_in_tup ltups;
LEXP_tup ltups
- | Parse_ast.E_app ((Parse_ast.Id_aux (f, l') as f'), args) ->
+ | P.E_app ((P.Id_aux (f, l') as f'), args) ->
begin match f with
- | Parse_ast.Id(id) ->
- (match List.map (to_ast_exp k_env def_ord) args with
+ | P.Id(id) ->
+ (match List.map (to_ast_exp ctx) args with
| [E_aux (E_lit (L_aux (L_unit, _)), _)] -> LEXP_memory (to_ast_id f', [])
| [E_aux (E_tuple exps,_)] -> LEXP_memory (to_ast_id f', exps)
| args -> LEXP_memory(to_ast_id f', args))
- | _ -> typ_error l' "memory call on lefthand side of assignment must begin with an id" None None None
+ | _ -> raise (Reporting.err_typ l' "memory call on lefthand side of assignment must begin with an id")
end
- | Parse_ast.E_vector_append (exp1, exp2) ->
- LEXP_vector_concat (to_ast_lexp k_env def_ord exp1 :: to_ast_lexp_vector_concat k_env def_ord exp2)
- | Parse_ast.E_vector_access (vexp, exp) -> LEXP_vector (to_ast_lexp k_env def_ord vexp, to_ast_exp k_env def_ord exp)
- | Parse_ast.E_vector_subrange (vexp, exp1, exp2) ->
- LEXP_vector_range (to_ast_lexp k_env def_ord vexp, to_ast_exp k_env def_ord exp1, to_ast_exp k_env def_ord exp2)
- | Parse_ast.E_field (fexp, id) -> LEXP_field (to_ast_lexp k_env def_ord fexp, to_ast_id id)
- | _ -> typ_error l "Only identifiers, cast identifiers, vector accesses, vector slices, and fields can be on the lefthand side of an assignment" None None None
+ | P.E_vector_append (exp1, exp2) ->
+ LEXP_vector_concat (to_ast_lexp ctx exp1 :: to_ast_lexp_vector_concat ctx exp2)
+ | P.E_vector_access (vexp, exp) -> LEXP_vector (to_ast_lexp ctx vexp, to_ast_exp ctx exp)
+ | P.E_vector_subrange (vexp, exp1, exp2) ->
+ LEXP_vector_range (to_ast_lexp ctx vexp, to_ast_exp ctx exp1, to_ast_exp ctx exp2)
+ | P.E_field (fexp, id) -> LEXP_field (to_ast_lexp ctx fexp, to_ast_id id)
+ | _ -> raise (Reporting.err_typ l "Only identifiers, cast identifiers, vector accesses, vector slices, and fields can be on the lefthand side of an assignment")
in
LEXP_aux (lexp, (l, ()))
-and to_ast_lexp_vector_concat k_env def_ord (Parse_ast.E_aux (exp_aux, l) as exp) =
+and to_ast_lexp_vector_concat ctx (P.E_aux (exp_aux, l) as exp) =
match exp_aux with
- | Parse_ast.E_vector_append (exp1, exp2) ->
- to_ast_lexp k_env def_ord exp1 :: to_ast_lexp_vector_concat k_env def_ord exp2
- | _ -> [to_ast_lexp k_env def_ord exp]
+ | P.E_vector_append (exp1, exp2) ->
+ to_ast_lexp ctx exp1 :: to_ast_lexp_vector_concat ctx exp2
+ | _ -> [to_ast_lexp ctx exp]
-and to_ast_case (k_env : kind Envmap.t) (def_ord : order) (Parse_ast.Pat_aux(pex,l) : Parse_ast.pexp) : unit pexp =
+and to_ast_case ctx (P.Pat_aux(pex,l) : P.pexp) : unit pexp =
match pex with
- | Parse_ast.Pat_exp(pat,exp) -> Pat_aux(Pat_exp(to_ast_pat k_env def_ord pat, to_ast_exp k_env def_ord exp),(l,()))
- | Parse_ast.Pat_when(pat,guard,exp) ->
- Pat_aux (Pat_when (to_ast_pat k_env def_ord pat, to_ast_exp k_env def_ord guard, to_ast_exp k_env def_ord exp), (l, ()))
+ | P.Pat_exp(pat,exp) -> Pat_aux(Pat_exp(to_ast_pat ctx pat, to_ast_exp ctx exp),(l,()))
+ | P.Pat_when(pat,guard,exp) ->
+ Pat_aux (Pat_when (to_ast_pat ctx pat, to_ast_exp ctx guard, to_ast_exp ctx exp), (l, ()))
-and to_ast_fexps (fail_on_error:bool) (k_env:kind Envmap.t) (def_ord:order) (exps : Parse_ast.exp list) : unit fexps option =
+and to_ast_fexps (fail_on_error:bool) ctx (exps : P.exp list) : unit fexp list option =
match exps with
- | [] -> Some(FES_aux(FES_Fexps([],false), (Parse_ast.Unknown,())))
- | fexp::exps -> let maybe_fexp,maybe_error = to_ast_record_try k_env def_ord fexp in
+ | [] -> Some []
+ | fexp::exps -> let maybe_fexp,maybe_error = to_ast_record_try ctx fexp in
(match maybe_fexp,maybe_error with
| Some(fexp),None ->
- (match (to_ast_fexps fail_on_error k_env def_ord exps) with
- | Some(FES_aux(FES_Fexps(fexps,_),l)) -> Some(FES_aux(FES_Fexps(fexp::fexps,false),l))
+ (match (to_ast_fexps fail_on_error ctx exps) with
+ | Some(fexps) -> Some(fexp::fexps)
| _ -> None)
| None,Some(l,msg) ->
if fail_on_error
- then typ_error l msg None None None
+ then raise (Reporting.err_typ l msg)
else None
| _ -> None)
-and to_ast_record_try (k_env:kind Envmap.t) (def_ord:order) (Parse_ast.E_aux(exp,l):Parse_ast.exp): unit fexp option * (l * string) option =
+and to_ast_record_try ctx (P.E_aux(exp,l):P.exp): unit fexp option * (l * string) option =
match exp with
- | Parse_ast.E_app_infix(left,op,r) ->
+ | P.E_app_infix(left,op,r) ->
(match left, op with
- | Parse_ast.E_aux(Parse_ast.E_id(id),li), Parse_ast.Id_aux(Parse_ast.Id("="),leq) ->
- Some(FE_aux(FE_Fexp(to_ast_id id, to_ast_exp k_env def_ord r), (l,()))),None
- | Parse_ast.E_aux(_,li) , Parse_ast.Id_aux(Parse_ast.Id("="),leq) ->
+ | P.E_aux(P.E_id(id),li), P.Id_aux(P.Id("="),leq) ->
+ Some(FE_aux(FE_Fexp(to_ast_id id, to_ast_exp ctx r), (l,()))),None
+ | P.E_aux(_,li) , P.Id_aux(P.Id("="),leq) ->
None,Some(li,"Expected an identifier to begin this field assignment")
- | Parse_ast.E_aux(Parse_ast.E_id(id),li), Parse_ast.Id_aux(_,leq) ->
+ | P.E_aux(P.E_id(id),li), P.Id_aux(_,leq) ->
None,Some(leq,"Expected a field assignment to be identifier = expression")
- | Parse_ast.E_aux(_,li),Parse_ast.Id_aux(_,leq) ->
+ | P.E_aux(_,li),P.Id_aux(_,leq) ->
None,Some(l,"Expected a field assignment to be identifier = expression"))
| _ ->
- None,Some(l, "Expected a field assignment to be identifier = expression")
+ None,Some(l, "Expected a field assignment to be identifier = expression")
+
+type 'a ctx_out = 'a * ctx
-let to_ast_default (names, k_env, default_order) (default : Parse_ast.default_typing_spec) : default_spec envs_out =
+let to_ast_default ctx (default : P.default_typing_spec) : default_spec ctx_out =
match default with
- | Parse_ast.DT_aux(Parse_ast.DT_order(bk,o),l) ->
- let k,k_typ = to_ast_base_kind bk in
- (match (k,o) with
- | (BK_aux(BK_order, _), Parse_ast.ATyp_aux(Parse_ast.ATyp_inc,lo)) ->
- let default_order = Ord_aux(Ord_inc,lo) in
- DT_aux(DT_order default_order,l),(names,k_env,default_order)
- | (BK_aux(BK_order, _), Parse_ast.ATyp_aux(Parse_ast.ATyp_dec,lo)) ->
- let default_order = Ord_aux(Ord_dec,lo) in
- DT_aux(DT_order default_order,l),(names,k_env,default_order)
- | _ -> typ_error l "Inc and Dec must have kind Order" None None None)
-
-let to_ast_spec (names,k_env,default_order) (val_:Parse_ast.val_spec) : (unit val_spec) envs_out =
+ | P.DT_aux(P.DT_order(k,o),l) ->
+ let k = to_ast_kind k in
+ match (k,o) with
+ | K_aux(K_order, _), P.ATyp_aux(P.ATyp_inc,lo) ->
+ let default_order = Ord_aux(Ord_inc,lo) in
+ DT_aux(DT_order default_order,l),ctx
+ | K_aux(K_order, _), P.ATyp_aux(P.ATyp_dec,lo) ->
+ let default_order = Ord_aux(Ord_dec,lo) in
+ DT_aux(DT_order default_order,l),ctx
+ | _ -> raise (Reporting.err_typ l "Inc and Dec must have kind Order")
+
+let to_ast_spec ctx (val_:P.val_spec) : (unit val_spec) ctx_out =
match val_ with
- | Parse_ast.VS_aux(vs,l) ->
+ | P.VS_aux(vs,l) ->
(match vs with
- | Parse_ast.VS_val_spec(ts,id,ext,is_cast) ->
- let typsch,_,_ = to_ast_typschm k_env default_order ts in
- VS_aux(VS_val_spec(typsch,to_ast_id id,ext,is_cast),(l,())),(names,k_env,default_order))
+ | P.VS_val_spec(ts,id,ext,is_cast) ->
+ let typschm, _ = to_ast_typschm ctx ts in
+ VS_aux(VS_val_spec(typschm,to_ast_id id,ext,is_cast),(l,())),ctx)
-let to_ast_namescm (Parse_ast.Name_sect_aux(ns,l)) =
+let to_ast_namescm (P.Name_sect_aux(ns,l)) =
Name_sect_aux(
(match ns with
- | Parse_ast.Name_sect_none -> Name_sect_none
- | Parse_ast.Name_sect_some(s) -> Name_sect_some(s)
+ | P.Name_sect_none -> Name_sect_none
+ | P.Name_sect_some(s) -> Name_sect_some(s)
),l)
-let rec to_ast_range (Parse_ast.BF_aux(r,l)) = (* TODO add check that ranges are sensible for some definition of sensible *)
+let rec to_ast_range (P.BF_aux(r,l)) = (* TODO add check that ranges are sensible for some definition of sensible *)
BF_aux(
(match r with
- | Parse_ast.BF_single(i) -> BF_single(i)
- | Parse_ast.BF_range(i1,i2) -> BF_range(i1,i2)
- | Parse_ast.BF_concat(ir1,ir2) -> BF_concat( to_ast_range ir1, to_ast_range ir2)),
+ | P.BF_single(i) -> BF_single(i)
+ | P.BF_range(i1,i2) -> BF_range(i1,i2)
+ | P.BF_concat(ir1,ir2) -> BF_concat( to_ast_range ir1, to_ast_range ir2)),
l)
-let to_ast_type_union k_env default_order (Parse_ast.Tu_aux (Parse_ast.Tu_ty_id (atyp, id), l)) =
- let typ = to_ast_typ k_env default_order atyp in
+let to_ast_type_union ctx (P.Tu_aux (P.Tu_ty_id (atyp, id), l)) =
+ let typ = to_ast_typ ctx atyp in
Tu_aux (Tu_ty_id (typ, to_ast_id id), l)
-let to_ast_typedef (names,k_env,def_ord) (td:Parse_ast.type_def) : (unit type_def) envs_out =
- match td with
- | Parse_ast.TD_aux(td,l) ->
- (match td with
- | Parse_ast.TD_abbrev(id,name_scm_opt,typschm) ->
- let id = to_ast_id id in
- let key = id_to_string id in
- let typschm,k_env,_ = to_ast_typschm k_env def_ord typschm in
- let td_abrv = TD_aux(TD_abbrev(id,to_ast_namescm name_scm_opt,typschm),(l,())) in
- let typ = (match typschm with
- | TypSchm_aux(TypSchm_ts(tq,typ), _) ->
- begin match (typquant_to_quantkinds k_env tq) with
- | [] -> {k = K_Typ}
- | typs -> {k= K_Lam(typs,{k=K_Typ})}
- end) in
- td_abrv,(names,Envmap.insert k_env (key,typ),def_ord)
- | Parse_ast.TD_record(id,name_scm_opt,typq,fields,_) ->
- let id = to_ast_id id in
- let key = id_to_string id in
- let typq,k_env,_ = to_ast_typquant k_env typq in
- let fields = List.map (fun (atyp,id) -> (to_ast_typ k_env def_ord atyp),(to_ast_id id)) fields in (* Add check that all arms have unique names locally *)
- let td_rec = TD_aux(TD_record(id,to_ast_namescm name_scm_opt,typq,fields,false),(l,())) in
- let typ = (match (typquant_to_quantkinds k_env typq) with
- | [ ] -> {k = K_Typ}
- | typs -> {k = K_Lam(typs,{k=K_Typ})}) in
- td_rec, (names,Envmap.insert k_env (key,typ), def_ord)
- | Parse_ast.TD_variant(id,name_scm_opt,typq,arms,_) ->
- let id = to_ast_id id in
- let key = id_to_string id in
- let typq,k_env,_ = to_ast_typquant k_env typq in
- let arms = List.map (to_ast_type_union k_env def_ord) arms in (* Add check that all arms have unique names *)
- let td_var = TD_aux(TD_variant(id,to_ast_namescm name_scm_opt,typq,arms,false),(l,())) in
- let typ = (match (typquant_to_quantkinds k_env typq) with
- | [ ] -> {k = K_Typ}
- | typs -> {k = K_Lam(typs,{k=K_Typ})}) in
- td_var, (names,Envmap.insert k_env (key,typ), def_ord)
- | Parse_ast.TD_enum(id,name_scm_opt,enums,_) ->
- let id = to_ast_id id in
- let key = id_to_string id in
- let enums = List.map to_ast_id enums in
- let keys = List.map id_to_string enums in
- let td_enum = TD_aux(TD_enum(id,to_ast_namescm name_scm_opt,enums,false),(l,())) in (* Add check that all enums have unique names *)
- let k_env = List.fold_right (fun k k_env -> Envmap.insert k_env (k,{k=K_Nat})) keys (Envmap.insert k_env (key,{k=K_Typ})) in
- td_enum, (names,k_env,def_ord)
- | Parse_ast.TD_bitfield(id,typ,ranges) ->
- let id = to_ast_id id in
- let key = id_to_string id in
- let typ = to_ast_typ k_env def_ord typ in
- let ranges = List.map (fun (id, range) -> (to_ast_id id, to_ast_range range)) ranges in
- TD_aux(TD_bitfield(id,typ,ranges),(l,())), (names,Envmap.insert k_env (key, {k=K_Typ}),def_ord))
-
-let to_ast_kdef (names,k_env,def_ord) (td:Parse_ast.kind_def) : (unit kind_def) envs_out =
+let add_constructor id typq ctx =
+ let kinds = List.map (fun kopt -> unaux_kind (kopt_kind kopt)) (quant_kopts typq) in
+ { ctx with type_constructors = Bindings.add id kinds ctx.type_constructors }
+
+let to_ast_typedef ctx (P.TD_aux (aux, l) : P.type_def) : unit type_def ctx_out =
+ let aux, ctx = match aux with
+ | P.TD_abbrev (id, typq, kind, typ_arg) ->
+ let id = to_ast_id id in
+ let typq, typq_ctx = to_ast_typquant ctx typq in
+ let kind = to_ast_kind kind in
+ let typ_arg = to_ast_typ_arg typq_ctx typ_arg (unaux_kind kind) in
+ TD_abbrev (id, typq, typ_arg),
+ add_constructor id typq ctx
+
+ | P.TD_record (id, namescm_opt, typq, fields, _) ->
+ let id = to_ast_id id in
+ let typq, typq_ctx = to_ast_typquant ctx typq in
+ let fields = List.map (fun (atyp, id) -> to_ast_typ typq_ctx atyp, to_ast_id id) fields in
+ TD_record (id, to_ast_namescm namescm_opt, typq, fields, false),
+ add_constructor id typq ctx
+
+ | P.TD_variant (id, namescm_opt, typq, arms, _) ->
+ let id = to_ast_id id in
+ let typq, typq_ctx = to_ast_typquant ctx typq in
+ let arms = List.map (to_ast_type_union typq_ctx) arms in
+ TD_variant (id, to_ast_namescm namescm_opt, typq, arms, false),
+ add_constructor id typq ctx
+
+ | P.TD_enum (id, namescm_opt, enums, _) ->
+ let id = to_ast_id id in
+ let enums = List.map to_ast_id enums in
+ TD_enum (id, to_ast_namescm namescm_opt, enums, false),
+ { ctx with type_constructors = Bindings.add id [] ctx.type_constructors }
+
+ | P.TD_bitfield (id, typ, ranges) ->
+ let id = to_ast_id id in
+ let typ = to_ast_typ ctx typ in
+ let ranges = List.map (fun (id, range) -> (to_ast_id id, to_ast_range range)) ranges in
+ TD_bitfield (id, typ, ranges),
+ { ctx with type_constructors = Bindings.add id [] ctx.type_constructors }
+ in
+ TD_aux (aux, (l, ())), ctx
+
+let to_ast_kdef ctx (td:P.kind_def) : unit kind_def =
match td with
- | Parse_ast.KD_aux(td,l) ->
- (match td with
- | Parse_ast.KD_abbrev(kind,id,name_scm_opt,typschm) ->
- let id = to_ast_id id in
- let key = id_to_string id in
- let (kind,k) = to_ast_kind k_env kind in
- (match k.k with
- | K_Nat ->
- let kd_nabrv =
- (match typschm with
- | Parse_ast.TypSchm_aux(Parse_ast.TypSchm_ts(Parse_ast.TypQ_aux(tq,_),atyp),_) ->
- (match tq with
- | Parse_ast.TypQ_no_forall ->
- KD_aux(KD_nabbrev(kind,id,to_ast_namescm name_scm_opt, to_ast_nexp k_env atyp), (l,()))
- | _ -> typ_error l "Def with kind Nat cannot have universal quantification" None None None)) in
- kd_nabrv,(names,Envmap.insert k_env (key, k),def_ord)
- | _ -> assert false
- ))
-
-let to_ast_rec (Parse_ast.Rec_aux(r,l): Parse_ast.rec_opt) : rec_opt =
+ | P.KD_aux (P.KD_nabbrev (kind, id, name_scm_opt, atyp), l) ->
+ let id = to_ast_id id in
+ let kind = to_ast_kind kind in
+ KD_aux (KD_nabbrev (kind, id, to_ast_namescm name_scm_opt, to_ast_nexp ctx atyp), (l, ()))
+
+let to_ast_rec ctx (P.Rec_aux(r,l): P.rec_opt) : unit rec_opt =
Rec_aux((match r with
- | Parse_ast.Rec_nonrec -> Rec_nonrec
- | Parse_ast.Rec_rec -> Rec_rec
+ | P.Rec_nonrec -> Rec_nonrec
+ | P.Rec_rec -> Rec_rec
+ | P.Rec_measure (p,e) ->
+ Rec_measure (to_ast_pat ctx p, to_ast_exp ctx e)
),l)
-let to_ast_tannot_opt (k_env:kind Envmap.t) (def_ord:order) (Parse_ast.Typ_annot_opt_aux(tp,l)):tannot_opt * kind Envmap.t * kind Envmap.t=
+let to_ast_tannot_opt ctx (P.Typ_annot_opt_aux(tp,l)) : tannot_opt ctx_out =
match tp with
- | Parse_ast.Typ_annot_opt_none ->
- Typ_annot_opt_aux (Typ_annot_opt_none, l), k_env, Envmap.empty
- | Parse_ast.Typ_annot_opt_some(tq,typ) ->
- let typq,k_env,k_local = to_ast_typquant k_env tq in
- Typ_annot_opt_aux(Typ_annot_opt_some(typq,to_ast_typ k_env def_ord typ),l),k_env,k_local
+ | P.Typ_annot_opt_none ->
+ Typ_annot_opt_aux (Typ_annot_opt_none, l), ctx
+ | P.Typ_annot_opt_some(tq,typ) ->
+ let typq, ctx = to_ast_typquant ctx tq in
+ Typ_annot_opt_aux (Typ_annot_opt_some(typq,to_ast_typ ctx typ),l),ctx
-let to_ast_typschm_opt (k_env:kind Envmap.t) (def_ord:order) (Parse_ast.TypSchm_opt_aux(aux,l)) : tannot_opt * kind Envmap.t * kind Envmap.t =
+let to_ast_typschm_opt ctx (P.TypSchm_opt_aux(aux,l)) : tannot_opt ctx_out =
match aux with
- | Parse_ast.TypSchm_opt_none ->
- Typ_annot_opt_aux (Typ_annot_opt_none, l), k_env, Envmap.empty
- | Parse_ast.TypSchm_opt_some (Parse_ast.TypSchm_aux (Parse_ast.TypSchm_ts (tq, typ), l)) ->
- let typq, k_env, k_local = to_ast_typquant k_env tq in
- Typ_annot_opt_aux (Typ_annot_opt_some (typq, to_ast_typ k_env def_ord typ), l), k_env, k_local
-
+ | P.TypSchm_opt_none ->
+ Typ_annot_opt_aux (Typ_annot_opt_none, l), ctx
+ | P.TypSchm_opt_some (P.TypSchm_aux (P.TypSchm_ts (tq, typ), l)) ->
+ let typq, ctx = to_ast_typquant ctx tq in
+ Typ_annot_opt_aux (Typ_annot_opt_some (typq, to_ast_typ ctx typ), l), ctx
-let to_ast_effects_opt (k_env : kind Envmap.t) (Parse_ast.Effect_opt_aux(e,l)) : effect_opt =
+let to_ast_effects_opt (P.Effect_opt_aux(e,l)) : effect_opt =
match e with
- | Parse_ast.Effect_opt_pure -> Effect_opt_aux(Effect_opt_pure,l)
- | Parse_ast.Effect_opt_effect(typ) -> Effect_opt_aux(Effect_opt_effect(to_ast_effects k_env typ),l)
+ | P.Effect_opt_pure -> Effect_opt_aux(Effect_opt_pure,l)
+ | P.Effect_opt_effect(typ) -> Effect_opt_aux(Effect_opt_effect(to_ast_effects typ),l)
-let to_ast_funcl (names,k_env,def_ord) (Parse_ast.FCL_aux(fcl,l) : Parse_ast.funcl) : (unit funcl) =
- (*let _ = Printf.eprintf "to_ast_funcl\n" in*)
+let to_ast_funcl ctx (P.FCL_aux(fcl,l) : P.funcl) : (unit funcl) =
match fcl with
- | Parse_ast.FCL_Funcl(id,pexp) ->
- FCL_aux(FCL_Funcl(to_ast_id id, to_ast_case k_env def_ord pexp),(l,()))
+ | P.FCL_Funcl(id,pexp) ->
+ FCL_aux(FCL_Funcl(to_ast_id id, to_ast_case ctx pexp),(l,()))
-let to_ast_fundef (names,k_env,def_ord) (Parse_ast.FD_aux(fd,l):Parse_ast.fundef) : (unit fundef) envs_out =
+let to_ast_fundef ctx (P.FD_aux(fd,l):P.fundef) : unit fundef =
match fd with
- | Parse_ast.FD_function(rec_opt,tannot_opt,effects_opt,funcls) ->
- (*let _ = Printf.eprintf "to_ast_fundef\n" in*)
- let tannot_opt, k_env,_ = to_ast_tannot_opt k_env def_ord tannot_opt in
- FD_aux(FD_function(to_ast_rec rec_opt, tannot_opt, to_ast_effects_opt k_env effects_opt, List.map (to_ast_funcl (names, k_env, def_ord)) funcls), (l,())), (names,k_env,def_ord)
+ | P.FD_function(rec_opt,tannot_opt,effects_opt,funcls) ->
+ let tannot_opt, ctx = to_ast_tannot_opt ctx tannot_opt in
+ FD_aux(FD_function(to_ast_rec ctx rec_opt, tannot_opt, to_ast_effects_opt effects_opt, List.map (to_ast_funcl ctx) funcls), (l,()))
-let rec to_ast_mpat k_env def_ord (Parse_ast.MP_aux(mpat,l)) =
+let rec to_ast_mpat ctx (P.MP_aux(mpat,l)) =
MP_aux(
(match mpat with
- | Parse_ast.MP_lit(lit) -> MP_lit(to_ast_lit lit)
- | Parse_ast.MP_id(id) -> MP_id(to_ast_id id)
- | Parse_ast.MP_as (mpat, id) -> MP_as (to_ast_mpat k_env def_ord mpat, to_ast_id id)
- | Parse_ast.MP_app(id,mpats) ->
+ | P.MP_lit(lit) -> MP_lit(to_ast_lit lit)
+ | P.MP_id(id) -> MP_id(to_ast_id id)
+ | P.MP_as (mpat, id) -> MP_as (to_ast_mpat ctx mpat, to_ast_id id)
+ | P.MP_app(id,mpats) ->
if mpats = []
then MP_id (to_ast_id id)
- else MP_app(to_ast_id id, List.map (to_ast_mpat k_env def_ord) mpats)
- | Parse_ast.MP_record(mfpats,_) ->
+ else MP_app(to_ast_id id, List.map (to_ast_mpat ctx) mpats)
+ | P.MP_record(mfpats,_) ->
MP_record(List.map
- (fun (Parse_ast.MFP_aux(Parse_ast.MFP_mpat(id,mfp),l)) ->
- MFP_aux(MFP_mpat(to_ast_id id, to_ast_mpat k_env def_ord mfp),(l,())))
+ (fun (P.MFP_aux(P.MFP_mpat(id,mfp),l)) ->
+ MFP_aux(MFP_mpat(to_ast_id id, to_ast_mpat ctx mfp),(l,())))
mfpats, false)
- | Parse_ast.MP_vector(mpats) -> MP_vector(List.map (to_ast_mpat k_env def_ord) mpats)
- | Parse_ast.MP_vector_concat(mpats) -> MP_vector_concat(List.map (to_ast_mpat k_env def_ord) mpats)
- | Parse_ast.MP_tup(mpats) -> MP_tup(List.map (to_ast_mpat k_env def_ord) mpats)
- | Parse_ast.MP_list(mpats) -> MP_list(List.map (to_ast_mpat k_env def_ord) mpats)
- | Parse_ast.MP_cons(pat1, pat2) -> MP_cons (to_ast_mpat k_env def_ord pat1, to_ast_mpat k_env def_ord pat2)
- | Parse_ast.MP_string_append pats -> MP_string_append (List.map (to_ast_mpat k_env def_ord) pats)
- | Parse_ast.MP_typ (mpat, typ) -> MP_typ (to_ast_mpat k_env def_ord mpat, to_ast_typ k_env def_ord typ)
+ | P.MP_vector(mpats) -> MP_vector(List.map (to_ast_mpat ctx) mpats)
+ | P.MP_vector_concat(mpats) -> MP_vector_concat(List.map (to_ast_mpat ctx) mpats)
+ | P.MP_tup(mpats) -> MP_tup(List.map (to_ast_mpat ctx) mpats)
+ | P.MP_list(mpats) -> MP_list(List.map (to_ast_mpat ctx) mpats)
+ | P.MP_cons(pat1, pat2) -> MP_cons (to_ast_mpat ctx pat1, to_ast_mpat ctx pat2)
+ | P.MP_string_append pats -> MP_string_append (List.map (to_ast_mpat ctx) pats)
+ | P.MP_typ (mpat, typ) -> MP_typ (to_ast_mpat ctx mpat, to_ast_typ ctx typ)
), (l,()))
-
-let to_ast_mpexp (names,k_env,def_ord) (Parse_ast.MPat_aux(mpexp, l)) =
+let to_ast_mpexp ctx (P.MPat_aux(mpexp, l)) =
match mpexp with
- | Parse_ast.MPat_pat mpat -> MPat_aux (MPat_pat (to_ast_mpat k_env def_ord mpat), (l, ()))
- | Parse_ast.MPat_when (mpat, exp) -> MPat_aux (MPat_when (to_ast_mpat k_env def_ord mpat, to_ast_exp k_env def_ord exp), (l, ()))
+ | P.MPat_pat mpat -> MPat_aux (MPat_pat (to_ast_mpat ctx mpat), (l, ()))
+ | P.MPat_when (mpat, exp) -> MPat_aux (MPat_when (to_ast_mpat ctx mpat, to_ast_exp ctx exp), (l, ()))
-let to_ast_mapcl (names,k_env,def_ord) (Parse_ast.MCL_aux(mapcl, l)) =
+let to_ast_mapcl ctx (P.MCL_aux(mapcl, l)) =
match mapcl with
- | Parse_ast.MCL_bidir (mpexp1, mpexp2) -> MCL_aux (MCL_bidir (to_ast_mpexp (names,k_env,def_ord) mpexp1, to_ast_mpexp (names,k_env,def_ord) mpexp2), (l, ()))
- | Parse_ast.MCL_forwards (mpexp, exp) -> MCL_aux (MCL_forwards (to_ast_mpexp (names,k_env,def_ord) mpexp, to_ast_exp k_env def_ord exp), (l, ()))
- | Parse_ast.MCL_backwards (mpexp, exp) -> MCL_aux (MCL_backwards (to_ast_mpexp (names,k_env,def_ord) mpexp, to_ast_exp k_env def_ord exp), (l, ()))
+ | P.MCL_bidir (mpexp1, mpexp2) -> MCL_aux (MCL_bidir (to_ast_mpexp ctx mpexp1, to_ast_mpexp ctx mpexp2), (l, ()))
+ | P.MCL_forwards (mpexp, exp) -> MCL_aux (MCL_forwards (to_ast_mpexp ctx mpexp, to_ast_exp ctx exp), (l, ()))
+ | P.MCL_backwards (mpexp, exp) -> MCL_aux (MCL_backwards (to_ast_mpexp ctx mpexp, to_ast_exp ctx exp), (l, ()))
-let to_ast_mapdef (names,k_env,def_ord) (Parse_ast.MD_aux(md,l):Parse_ast.mapdef) : (unit mapdef) envs_out =
+let to_ast_mapdef ctx (P.MD_aux(md,l):P.mapdef) : unit mapdef =
match md with
- | Parse_ast.MD_mapping(id, typschm_opt, mapcls) ->
- let tannot_opt, k_env, _ = to_ast_typschm_opt k_env def_ord typschm_opt in
- MD_aux(MD_mapping(to_ast_id id, tannot_opt, List.map (to_ast_mapcl (names,k_env,def_ord)) mapcls), (l,())), (names,k_env,def_ord)
-
-type def_progress =
- No_def
- | Def_place_holder of id * Parse_ast.l
- | Finished of unit def
-
-type partial_def = ((unit def) * bool) ref * kind Envmap.t
-
-let rec def_in_progress (id : id) (partial_defs : (id * partial_def) list) : partial_def option =
- match partial_defs with
- | [] -> None
- | (n,pd)::defs ->
- (match n,id with
- | Id_aux(Id(n),_), Id_aux(Id(i),_) -> if (n = i) then Some(pd) else def_in_progress id defs
- | _,_ -> def_in_progress id defs)
-
-let to_ast_alias_spec k_env def_ord (Parse_ast.E_aux(e,le)) =
- AL_aux(
- (match e with
- | Parse_ast.E_field(Parse_ast.E_aux(Parse_ast.E_id id,li), field) ->
- AL_subreg(RI_aux(RI_id (to_ast_id id),(li,())),to_ast_id field)
- | Parse_ast.E_vector_access(Parse_ast.E_aux(Parse_ast.E_id id,li),range) ->
- AL_bit(RI_aux(RI_id (to_ast_id id),(li,())),to_ast_exp k_env def_ord range)
- | Parse_ast.E_vector_subrange(Parse_ast.E_aux(Parse_ast.E_id id,li),base,stop) ->
- AL_slice(RI_aux(RI_id (to_ast_id id),(li,())),to_ast_exp k_env def_ord base,to_ast_exp k_env def_ord stop)
- | Parse_ast.E_vector_append(Parse_ast.E_aux(Parse_ast.E_id first,lf),
- Parse_ast.E_aux(Parse_ast.E_id second,ls)) ->
- AL_concat(RI_aux(RI_id (to_ast_id first),(lf,())),
- RI_aux(RI_id (to_ast_id second),(ls,())))
- | _ -> raise (Reporting_basic.err_unreachable le __POS__ "Found an expression not supported by parser in to_ast_alias_spec")
- ), (le,()))
-
-let to_ast_dec (names,k_env,def_ord) (Parse_ast.DEC_aux(regdec,l)) =
- DEC_aux(
- (match regdec with
- | Parse_ast.DEC_reg(typ,id) ->
- DEC_reg(to_ast_typ k_env def_ord typ,to_ast_id id)
- | Parse_ast.DEC_config(id,typ,exp) ->
- DEC_config(to_ast_id id,to_ast_typ k_env def_ord typ,to_ast_exp k_env def_ord exp)
- | Parse_ast.DEC_alias(id,e) ->
- DEC_alias(to_ast_id id,to_ast_alias_spec k_env def_ord e)
- | Parse_ast.DEC_typ_alias(typ,id,e) ->
- DEC_typ_alias(to_ast_typ k_env def_ord typ,to_ast_id id,to_ast_alias_spec k_env def_ord e)
- ),(l,()))
+ | P.MD_mapping(id, typschm_opt, mapcls) ->
+ let tannot_opt, ctx = to_ast_typschm_opt ctx typschm_opt in
+ MD_aux(MD_mapping(to_ast_id id, tannot_opt, List.map (to_ast_mapcl ctx) mapcls), (l,()))
+
+let to_ast_alias_spec ctx (P.E_aux(e, l)) =
+ AL_aux((match e with
+ | P.E_field (P.E_aux (P.E_id id, li), field) ->
+ AL_subreg (RI_aux (RI_id (to_ast_id id), (li, ())), to_ast_id field)
+ | P.E_vector_access (P.E_aux (P.E_id id, li), range) ->
+ AL_bit (RI_aux (RI_id (to_ast_id id), (li, ())), to_ast_exp ctx range)
+ | P.E_vector_subrange(P.E_aux(P.E_id id,li),base,stop) ->
+ AL_slice (RI_aux (RI_id (to_ast_id id), (li,())), to_ast_exp ctx base, to_ast_exp ctx stop)
+ | P.E_vector_append (P.E_aux (P.E_id first, lf), P.E_aux (P.E_id second, ls)) ->
+ AL_concat (RI_aux (RI_id (to_ast_id first), (lf, ())),
+ RI_aux (RI_id (to_ast_id second), (ls, ())))
+ | _ -> raise (Reporting.err_unreachable l __POS__ "Found an expression not supported by parser in to_ast_alias_spec")
+ ), (l, ()))
+
+let to_ast_dec ctx (P.DEC_aux(regdec,l)) =
+ DEC_aux((match regdec with
+ | P.DEC_reg (typ, id) ->
+ DEC_reg (to_ast_typ ctx typ, to_ast_id id)
+ | P.DEC_config (id, typ, exp) ->
+ DEC_config (to_ast_id id, to_ast_typ ctx typ, to_ast_exp ctx exp)
+ | P.DEC_alias (id,e) ->
+ DEC_alias (to_ast_id id, to_ast_alias_spec ctx e)
+ | P.DEC_typ_alias (typ,id,e) ->
+ DEC_typ_alias (to_ast_typ ctx typ, to_ast_id id, to_ast_alias_spec ctx e)
+ ),(l,()))
+
+let to_ast_scattered ctx (P.SD_aux (aux, l)) =
+ let aux, ctx = match aux with
+ | P.SD_function (rec_opt, tannot_opt, effect_opt, id) ->
+ let tannot_opt, _ = to_ast_tannot_opt ctx tannot_opt in
+ let effect_opt = to_ast_effects_opt effect_opt in
+ SD_function (to_ast_rec ctx rec_opt, tannot_opt, effect_opt, to_ast_id id), ctx
+ | P.SD_funcl funcl ->
+ SD_funcl (to_ast_funcl ctx funcl), ctx
+ | P.SD_variant (id, namescm_opt, typq) ->
+ let id = to_ast_id id in
+ let typq, typq_ctx = to_ast_typquant ctx typq in
+ SD_variant (id, to_ast_namescm namescm_opt, typq),
+ add_constructor id typq { ctx with scattereds = Bindings.add id typq_ctx ctx.scattereds }
+ | P.SD_unioncl (id, tu) ->
+ let id = to_ast_id id in
+ begin match Bindings.find_opt id ctx.scattereds with
+ | Some typq_ctx ->
+ let tu = to_ast_type_union typq_ctx tu in
+ SD_unioncl (id, tu), ctx
+ | None -> raise (Reporting.err_typ l ("No scattered union declaration found for " ^ string_of_id id))
+ end
+ | P.SD_end id -> SD_end (to_ast_id id), ctx
+ | P.SD_mapping (id, tannot_opt) ->
+ let id = to_ast_id id in
+ let tannot_opt, _ = to_ast_tannot_opt ctx tannot_opt in
+ SD_mapping (id, tannot_opt), ctx
+ | P.SD_mapcl (id, mapcl) ->
+ let id = to_ast_id id in
+ let mapcl = to_ast_mapcl ctx mapcl in
+ SD_mapcl (id, mapcl), ctx
+ in
+ SD_aux (aux, (l, ())), ctx
let to_ast_prec = function
- | Parse_ast.Infix -> Infix
- | Parse_ast.InfixL -> InfixL
- | Parse_ast.InfixR -> InfixR
+ | P.Infix -> Infix
+ | P.InfixL -> InfixL
+ | P.InfixR -> InfixR
-let to_ast_def (names, k_env, def_ord) partial_defs def : def_progress envs_out * (id * partial_def) list =
- let envs = (names,k_env,def_ord) in
+let to_ast_def ctx def : unit def ctx_out =
match def with
- | Parse_ast.DEF_overload(id,ids) ->
- ((Finished(DEF_overload(to_ast_id id, List.map to_ast_id ids))),envs),partial_defs
- | Parse_ast.DEF_fixity (prec, n, op) ->
- ((Finished(DEF_fixity (to_ast_prec prec, n, to_ast_id op)),envs),partial_defs)
- | Parse_ast.DEF_kind(k_def) ->
- let kd,envs = to_ast_kdef envs k_def in
- ((Finished(DEF_kind(kd))),envs),partial_defs
- | Parse_ast.DEF_type(t_def) ->
- let td,envs = to_ast_typedef envs t_def in
- ((Finished(DEF_type(td))),envs),partial_defs
- | Parse_ast.DEF_fundef(f_def) ->
- let fd,envs = to_ast_fundef envs f_def in
- ((Finished(DEF_fundef(fd))),envs),partial_defs
- | Parse_ast.DEF_mapdef(m_def) ->
- let md, envs = to_ast_mapdef envs m_def in
- ((Finished(DEF_mapdef(md))),envs),partial_defs
- | Parse_ast.DEF_val(lbind) ->
- let lb = to_ast_letbind k_env def_ord lbind in
- ((Finished(DEF_val(lb))),envs),partial_defs
- | Parse_ast.DEF_spec(val_spec) ->
- let vs,envs = to_ast_spec envs val_spec in
- ((Finished(DEF_spec(vs))),envs),partial_defs
- | Parse_ast.DEF_default(typ_spec) ->
- let default,envs = to_ast_default envs typ_spec in
- ((Finished(DEF_default(default))),envs),partial_defs
- | Parse_ast.DEF_reg_dec(dec) ->
- let d = to_ast_dec envs dec in
- ((Finished(DEF_reg_dec(d))),envs),partial_defs
- | Parse_ast.DEF_constraint (id, kids, nc) ->
- let id = to_ast_id id in
- let kids = List.map to_ast_var kids in
- let nc = to_ast_nexp_constraint k_env nc in
- ((Finished (DEF_constraint (id, kids, nc))), envs), partial_defs
- | Parse_ast.DEF_pragma (_, _, l) ->
- typ_error l "Encountered preprocessor directive in initial check" None None None
- | Parse_ast.DEF_internal_mutrec _ ->
+ | P.DEF_overload (id, ids) ->
+ DEF_overload (to_ast_id id, List.map to_ast_id ids), ctx
+ | P.DEF_fixity (prec, n, op) ->
+ DEF_fixity (to_ast_prec prec, n, to_ast_id op), ctx
+ | P.DEF_kind k_def ->
+ let kd = to_ast_kdef ctx k_def in
+ DEF_kind kd, ctx
+ | P.DEF_type(t_def) ->
+ let td, ctx = to_ast_typedef ctx t_def in
+ DEF_type td, ctx
+ | P.DEF_fundef(f_def) ->
+ let fd = to_ast_fundef ctx f_def in
+ DEF_fundef fd, ctx
+ | P.DEF_mapdef(m_def) ->
+ let md = to_ast_mapdef ctx m_def in
+ DEF_mapdef md, ctx
+ | P.DEF_val(lbind) ->
+ let lb = to_ast_letbind ctx lbind in
+ DEF_val lb, ctx
+ | P.DEF_spec(val_spec) ->
+ let vs,ctx = to_ast_spec ctx val_spec in
+ DEF_spec vs, ctx
+ | P.DEF_default(typ_spec) ->
+ let default,ctx = to_ast_default ctx typ_spec in
+ DEF_default default, ctx
+ | P.DEF_reg_dec dec ->
+ let d = to_ast_dec ctx dec in
+ DEF_reg_dec d, ctx
+ | P.DEF_pragma (pragma, arg, l) ->
+ DEF_pragma (pragma, arg, l), ctx
+ | P.DEF_internal_mutrec _ ->
(* Should never occur because of remove_mutrec *)
- typ_error Parse_ast.Unknown "Internal mutual block found when processing scattered defs" None None None
- | Parse_ast.DEF_scattered(Parse_ast.SD_aux(sd,l)) ->
- (match sd with
- | Parse_ast.SD_scattered_function(rec_opt, tannot_opt, effects_opt, id) ->
- let rec_opt = to_ast_rec rec_opt in
- let unit,k_env',k_local = to_ast_tannot_opt k_env def_ord tannot_opt in
- let effects_opt = to_ast_effects_opt k_env' effects_opt in
- let id = to_ast_id id in
- (match (def_in_progress id partial_defs) with
- | None -> let partial_def = ref ((DEF_fundef(FD_aux(FD_function(rec_opt,unit,effects_opt,[]),(l,())))),false) in
- (No_def,envs),((id,(partial_def,k_local))::partial_defs)
- | Some(d,k) -> typ_error l "Scattered function definition header name already in use by scattered definition" (Some id) None None)
- | Parse_ast.SD_scattered_mapping (id, tannot_opt) ->
- let id = to_ast_id id in
- let unit, k_env ,k_local = to_ast_tannot_opt k_env def_ord tannot_opt in
- (match (def_in_progress id partial_defs) with
- | None -> let partial_def = ref ((DEF_mapdef(MD_aux(MD_mapping(id, unit, []), (l, ())))), false) in
- (No_def,envs),((id,(partial_def,k_local))::partial_defs)
- | Some(d,k) -> typ_error l "Scattered mapping definition header name already in use by scattered definition" (Some id) None None)
-
- | Parse_ast.SD_scattered_mapcl (id, mapcl) ->
- let id = to_ast_id id in
- (match (def_in_progress id partial_defs) with
- | None -> typ_error l "Scattered mapping definition clause does not match any existing mapping definition headers" (Some id) None None
- | Some (d, k) ->
- (match !d with
- | DEF_mapdef(MD_aux(MD_mapping(_,tannot_opt, mcls),ml)),false ->
- let (MCL_aux (mapcl_aux, _)) = to_ast_mapcl (names,k_env,def_ord) mapcl in
- d := DEF_mapdef(MD_aux(MD_mapping(id, tannot_opt, mcls @ [MCL_aux (mapcl_aux, (l, ()))]), ml)), false;
- (No_def,envs),partial_defs
- | _, true -> typ_error l "Scattered mapping definition clause extends ended definition" (Some id) None None
- | _ -> typ_error l "Scattered mapping definition doesn't match existing definition header" (Some id) None None))
-
- | Parse_ast.SD_scattered_funcl(funcl) ->
- (match funcl with
- | Parse_ast.FCL_aux(Parse_ast.FCL_Funcl(id,_),_) ->
- let id = to_ast_id id in
- (match (def_in_progress id partial_defs) with
- | None -> typ_error l "Scattered function definition clause does not match any existing function definition headers" (Some id) None None
- | Some(d,k) ->
- (* let _ = Printf.eprintf "SD_scattered_funcl processing\n" in
- let _ = Envmap.iter (fun v' k -> P rintf.eprintf "%s -> %s\n" v' (kind_to_string k)) k in
- let _ = Envmap.iter (fun v' k -> Prin tf.eprintf "%s -> %s\n" v' (kind_to_string k) ) (Envmap.union k k_env) in *)
- (match !d with
- | DEF_fundef(FD_aux(FD_function(r,t,e,fcls),fl)),false ->
- let (FCL_aux (funcl_aux, _)) = to_ast_funcl (names,Envmap.union k k_env,def_ord) funcl in
- d:= DEF_fundef(FD_aux(FD_function(r,t,e,fcls@[FCL_aux (funcl_aux, (l, ()))]),fl)),false;
- (No_def,envs),partial_defs
- | _,true -> typ_error l "Scattered function definition clauses extends ended definition" (Some id) None None
- | _ -> typ_error l "Scattered function definition clause matches an existing scattered type definition header" (Some id) None None)))
- | Parse_ast.SD_scattered_variant(id,naming_scheme_opt,typquant) ->
- let id = to_ast_id id in
- let name = to_ast_namescm naming_scheme_opt in
- let typq, k_env',_ = to_ast_typquant k_env typquant in
- let kind = (match (typquant_to_quantkinds k_env' typq) with
- | [ ] -> {k = K_Typ}
- | typs -> {k = K_Lam(typs,{k=K_Typ})}) in
- (match (def_in_progress id partial_defs) with
- | None -> let partial_def = ref ((DEF_type(TD_aux(TD_variant(id,name,typq,[],false),(l,())))),false) in
- (Def_place_holder(id,l),(names,Envmap.insert k_env ((id_to_string id),kind),def_ord)),(id,(partial_def,k_env'))::partial_defs
- | Some(d,k) -> typ_error l "Scattered type definition header name already in use by scattered definition" (Some id) None None)
- | Parse_ast.SD_scattered_unioncl(id,tu) ->
- let id = to_ast_id id in
- (match (def_in_progress id partial_defs) with
- | None -> typ_error l "Scattered type definition clause does not match any existing type definition headers" (Some id) None None
- | Some(d,k) ->
- (match !d with
- | DEF_type(TD_aux(TD_variant(id,name,typq,arms,false),tl)), false ->
- d:= DEF_type(TD_aux(TD_variant(id,name,typq,arms@[to_ast_type_union k def_ord tu],false),tl)),false;
- (No_def,envs),partial_defs
- | _,true -> typ_error l "Scattered type definition clause extends ended definition" (Some id) None None
- | _ -> typ_error l "Scattered type definition clause matches an existing scattered function definition header" (Some id) None None))
- | Parse_ast.SD_scattered_end(id) ->
- let id = to_ast_id id in
- (match (def_in_progress id partial_defs) with
- | None -> typ_error l "Scattered definition end does not match any open scattered definitions" (Some id) None None
- | Some(d,k) ->
- (match !d with
- | (DEF_type(_) as def),false ->
- d:= (def,true);
- (No_def,envs),partial_defs
- | (DEF_fundef(_) as def),false ->
- d:= (def,true);
- ((Finished def), envs),partial_defs
- | (DEF_mapdef(_) as def),false ->
- d := (def,true);
- ((Finished def), envs),partial_defs
- | _, true ->
- typ_error l "Scattered definition ended multiple times" (Some id) None None
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "Something in partial_defs other than fundef and type"))))
-
-let rec to_ast_defs_helper envs partial_defs = function
- | [] -> ([],envs,partial_defs)
- | d::ds -> let ((d', envs), partial_defs) = to_ast_def envs partial_defs d in
- let (defs,envs,partial_defs) = to_ast_defs_helper envs partial_defs ds in
- (match d' with
- | Finished def -> (def::defs,envs, partial_defs)
- | No_def -> defs,envs,partial_defs
- | Def_place_holder(id,l) ->
- (match (def_in_progress id partial_defs) with
- | None ->
- raise
- (Reporting_basic.err_unreachable l __POS__ "Id stored in place holder not retrievable from partial defs")
- | Some(d,k) ->
- if (snd !d)
- then (fst !d) :: defs, envs, partial_defs
- else typ_error l "Scattered type definition never ended" (Some id) None None))
+ raise (Reporting.err_unreachable P.Unknown __POS__
+ "Internal mutual block found when processing scattered defs")
+ | P.DEF_scattered sdef ->
+ let sdef, ctx = to_ast_scattered ctx sdef in
+ DEF_scattered sdef, ctx
let rec remove_mutrec = function
| [] -> []
- | Parse_ast.DEF_internal_mutrec fundefs :: defs ->
- List.map (fun fdef -> Parse_ast.DEF_fundef fdef) fundefs @ remove_mutrec defs
+ | P.DEF_internal_mutrec fundefs :: defs ->
+ List.map (fun fdef -> P.DEF_fundef fdef) fundefs @ remove_mutrec defs
| def :: defs ->
def :: remove_mutrec defs
-let to_ast (default_names : Nameset.t) (kind_env : kind Envmap.t) (def_ord : order) (Parse_ast.Defs(defs)) =
+let to_ast ctx (P.Defs(defs)) =
let defs = remove_mutrec defs in
- let defs,(_,k_env,def_ord),partial_defs = to_ast_defs_helper (default_names,kind_env,def_ord) [] defs in
- List.iter
- (fun (id,(d,k)) ->
- (match !d with
- | (d,false) -> typ_error Parse_ast.Unknown "Scattered definition never ended" (Some id) None None
- | (_, true) -> ()))
- partial_defs;
- (Defs defs),k_env,def_ord
-
-let initial_kind_env =
- Envmap.from_list [
- ("bool", {k = K_Typ});
- ("nat", {k = K_Typ});
- ("int", {k = K_Typ});
- ("uint8", {k = K_Typ});
- ("uint16", {k= K_Typ});
- ("uint32", {k=K_Typ});
- ("uint64", {k=K_Typ});
- ("unit", {k = K_Typ});
- ("bit", {k = K_Typ});
- ("string", {k = K_Typ});
- ("real", {k = K_Typ});
- ("list", {k = K_Lam( [{k = K_Typ}], {k = K_Typ})});
- ("reg", {k = K_Lam( [{k = K_Typ}], {k= K_Typ})});
- ("register", {k = K_Lam( [{k = K_Typ}], {k= K_Typ})});
- ("range", {k = K_Lam( [ {k = K_Nat}; {k= K_Nat}], {k = K_Typ}) });
- ("vector", {k = K_Lam( [{k = K_Nat}; {k= K_Ord} ; {k=K_Typ}], {k=K_Typ}) } );
- ("atom", {k = K_Lam( [ {k=K_Nat} ], {k=K_Typ})});
- ("option", { k = K_Lam( [{k=K_Typ}], {k=K_Typ}) });
- ("implicit", {k = K_Lam( [{k = K_Nat}], {k=K_Typ})} );
- ("itself", {k = K_Lam( [ {k=K_Nat} ], {k=K_Typ})});
- ]
-
-let exp_of_string order str =
+ let defs, ctx =
+ List.fold_left (fun (defs, ctx) def -> let def, ctx = to_ast_def ctx def in (def :: defs, ctx)) ([], ctx) defs
+ in
+ Defs (List.rev defs), ctx
+
+let initial_ctx = {
+ type_constructors =
+ List.fold_left (fun m (k, v) -> Bindings.add (mk_id k) v m) Bindings.empty
+ [ ("bool", []);
+ ("nat", []);
+ ("int", []);
+ ("unit", []);
+ ("bit", []);
+ ("string", []);
+ ("real", []);
+ ("list", [K_type]);
+ ("register", [K_type]);
+ ("range", [K_int; K_int]);
+ ("vector", [K_int; K_order; K_type]);
+ ("atom", [K_int]);
+ ("implicit", [K_int]);
+ ("itself", [K_int]);
+ ("not", [K_bool]);
+ ];
+ kinds = KBindings.empty;
+ scattereds = Bindings.empty;
+ }
+
+let exp_of_string str =
let exp = Parser.exp_eof Lexer.token (Lexing.from_string str) in
- to_ast_exp initial_kind_env order exp
+ to_ast_exp initial_ctx exp
-let typschm_of_string order str =
+let typschm_of_string str =
let typschm = Parser.typschm_eof Lexer.token (Lexing.from_string str) in
- let (typschm, _, _) = to_ast_typschm initial_kind_env order typschm in
+ let typschm, _ = to_ast_typschm initial_ctx typschm in
typschm
-let extern_of_string order id str = mk_val_spec (VS_val_spec (typschm_of_string order str, id, [("_", string_of_id id)], false))
-let val_spec_of_string order id str = mk_val_spec (VS_val_spec (typschm_of_string order str, id, [], false))
+let typ_of_string str =
+ let typ = Parser.typ_eof Lexer.token (Lexing.from_string str) in
+ let typ = to_ast_typ initial_ctx typ in
+ typ
+
+let extern_of_string id str = mk_val_spec (VS_val_spec (typschm_of_string str, id, [("_", string_of_id id)], false))
+let val_spec_of_string id str = mk_val_spec (VS_val_spec (typschm_of_string str, id, [], false))
let val_spec_ids (Defs defs) =
let val_spec_id (VS_aux (vs_aux, _)) =
@@ -1102,8 +819,8 @@ let quant_item_typ = function
| QI_aux (QI_id kopt, _) when is_typ_kopt kopt -> [mk_typ (Typ_var (kopt_kid kopt))]
| _ -> []
let quant_item_arg = function
- | QI_aux (QI_id kopt, _) when is_nat_kopt kopt -> [mk_typ_arg (Typ_arg_nexp (nvar (kopt_kid kopt)))]
- | QI_aux (QI_id kopt, _) when is_typ_kopt kopt -> [mk_typ_arg (Typ_arg_typ (mk_typ (Typ_var (kopt_kid kopt))))]
+ | QI_aux (QI_id kopt, _) when is_nat_kopt kopt -> [mk_typ_arg (A_nexp (nvar (kopt_kid kopt)))]
+ | QI_aux (QI_id kopt, _) when is_typ_kopt kopt -> [mk_typ_arg (A_typ (mk_typ (Typ_var (kopt_kid kopt))))]
| _ -> []
let undefined_typschm id typq =
let qis = quant_items typq in
@@ -1118,7 +835,7 @@ let have_undefined_builtins = ref false
let generate_undefineds vs_ids (Defs defs) =
let gen_vs id str =
- if (IdSet.mem id vs_ids) then [] else [extern_of_string dec_ord id str]
+ if (IdSet.mem id vs_ids) then [] else [extern_of_string id str]
in
let undefined_builtins =
if !have_undefined_builtins then
@@ -1153,7 +870,7 @@ let generate_undefineds vs_ids (Defs defs) =
in
let undefined_td = function
| TD_enum (id, _, ids, _) when not (IdSet.mem (prepend_id "undefined_" id) vs_ids) ->
- let typschm = typschm_of_string dec_ord ("unit -> " ^ string_of_id id ^ " effect {undef}") in
+ let typschm = typschm_of_string ("unit -> " ^ string_of_id id ^ " effect {undef}") in
[mk_val_spec (VS_val_spec (typschm, prepend_id "undefined_" id, [], false));
mk_fundef [mk_funcl (prepend_id "undefined_" id)
(mk_pat (P_lit (mk_lit L_unit)))
@@ -1167,7 +884,7 @@ let generate_undefineds vs_ids (Defs defs) =
[mk_val_spec (VS_val_spec (undefined_typschm id typq, prepend_id "undefined_" id, [], false));
mk_fundef [mk_funcl (prepend_id "undefined_" id)
pat
- (mk_exp (E_record (mk_fexps (List.map (fun (_, id) -> mk_fexp id (mk_lit_exp L_undef)) fields))))]]
+ (mk_exp (E_record (List.map (fun (_, id) -> mk_fexp id (mk_lit_exp L_undef)) fields)))]]
| TD_variant (id, _, typq, tus, _) when not (IdSet.mem (prepend_id "undefined_" id) vs_ids) ->
let pat = p_tup (quant_items typq |> List.map quant_item_param |> List.concat |> List.map (fun id -> mk_pat (P_id id))) in
let body =
@@ -1181,7 +898,7 @@ let generate_undefineds vs_ids (Defs defs) =
| Tu_aux (Tu_ty_id (typ, id), _) -> (id, [typ])
in
let record_arg_typs m (_,typs) =
- let m' =
+ let m' =
List.fold_left (fun m typ ->
TypMap.add typ (1 + try TypMap.find typ m with Not_found -> 0) m) TypMap.empty typs in
TypMap.merge (fun _ x y -> match x,y with Some m, Some n -> Some (max m n)
@@ -1237,7 +954,7 @@ let generate_initialize_registers vs_ids (Defs defs) =
let initialize_registers =
if IdSet.mem (mk_id "initialize_registers") vs_ids || regs = [] then []
else
- [val_spec_of_string dec_ord (mk_id "initialize_registers") "unit -> unit effect {undef, wreg}";
+ [val_spec_of_string (mk_id "initialize_registers") "unit -> unit effect {undef, wreg}";
mk_fundef [mk_funcl (mk_id "initialize_registers")
(mk_pat (P_lit (mk_lit L_unit)))
(mk_exp (E_block (List.map (fun (typ, id) -> mk_exp (E_assign (mk_lexp (LEXP_cast (typ, id)), mk_lit_exp L_undef))) regs)))]]
@@ -1274,7 +991,7 @@ let generate_enum_functions vs_ids (Defs defs) =
if IdSet.mem name vs_ids then []
else
[ enum_val_spec name
- [mk_qi_id BK_int kid; mk_qi_nc (range_constraint kid)]
+ [mk_qi_id K_int kid; mk_qi_nc (range_constraint kid)]
(function_typ [atom_typ (nvar kid)] (mk_typ (Typ_id id)) no_effect);
mk_fundef [funcl] ]
in
@@ -1282,7 +999,7 @@ let generate_enum_functions vs_ids (Defs defs) =
(* Create a function that converts from an enum to a number. *)
let from_enum =
let kid = mk_kid "e" in
- let to_typ = mk_typ (Typ_exist ([kid], range_constraint kid, atom_typ (nvar kid))) in
+ let to_typ = mk_typ (Typ_exist ([mk_kopt K_int kid], range_constraint kid, atom_typ (nvar kid))) in
let name = prepend_id "num_of_" id in
let pexp n id = mk_pexp (Pat_exp (mk_pat (P_id id), mk_lit_exp (L_num (Big_int.of_int n)))) in
let funcl =
@@ -1302,11 +1019,11 @@ let generate_enum_functions vs_ids (Defs defs) =
in
Defs (gen_enums defs)
-let incremental_k_env = ref initial_kind_env
+let incremental_ctx = ref initial_ctx
let process_ast order defs =
- let ast, k_env, _= to_ast Nameset.empty !incremental_k_env order defs in
- incremental_k_env := k_env;
+ let ast, ctx = to_ast !incremental_ctx defs in
+ incremental_ctx := ctx;
let vs_ids = val_spec_ids ast in
if not !opt_undefined_gen then
generate_enum_functions vs_ids ast
@@ -1318,4 +1035,4 @@ let process_ast order defs =
let ast_of_def_string order str =
let def = Parser.def_eof Lexer.token (Lexing.from_string str) in
- process_ast order (Parse_ast.Defs [def])
+ process_ast order (P.Defs [def])
diff --git a/src/initial_check.mli b/src/initial_check.mli
index e6b29216..25187e4c 100644
--- a/src/initial_check.mli
+++ b/src/initial_check.mli
@@ -87,7 +87,8 @@ val process_ast : order -> Parse_ast.defs -> unit defs
val val_spec_ids : 'a defs -> IdSet.t
-val extern_of_string : order -> id -> string -> unit def
-val val_spec_of_string : order -> id -> string -> unit def
+val extern_of_string : id -> string -> unit def
+val val_spec_of_string : id -> string -> unit def
-val exp_of_string : order -> string -> unit exp
+val exp_of_string : string -> unit exp
+val typ_of_string : string -> typ
diff --git a/src/interpreter.ml b/src/interpreter.ml
index 83f8b14e..74333122 100644
--- a/src/interpreter.ml
+++ b/src/interpreter.ml
@@ -495,13 +495,13 @@ let rec step (E_aux (e_aux, annot) as orig_exp) =
| _ -> fail ("Couldn't find id " ^ string_of_id id)
end
- | E_record (FES_aux (FES_Fexps (fexps, flag), fes_annot)) ->
+ | E_record fexps ->
let evaluated, unevaluated = Util.take_drop is_value_fexp fexps in
begin
match unevaluated with
| FE_aux (FE_Fexp (id, exp), fe_annot) :: fexps ->
step exp >>= fun exp' ->
- wrap (E_record (FES_aux (FES_Fexps (evaluated @ FE_aux (FE_Fexp (id, exp'), fe_annot) :: fexps, flag), fes_annot)))
+ wrap (E_record (evaluated @ FE_aux (FE_Fexp (id, exp'), fe_annot) :: fexps))
| [] ->
List.map value_of_fexp fexps
|> List.fold_left (fun record (field, v) -> StringMap.add field v record) StringMap.empty
@@ -512,13 +512,13 @@ let rec step (E_aux (e_aux, annot) as orig_exp) =
| E_record_update (exp, fexps) when not (is_value exp) ->
step exp >>= fun exp' -> wrap (E_record_update (exp', fexps))
- | E_record_update (record, FES_aux (FES_Fexps (fexps, flag), fes_annot)) ->
+ | E_record_update (record, fexps) ->
let evaluated, unevaluated = Util.take_drop is_value_fexp fexps in
begin
match unevaluated with
| FE_aux (FE_Fexp (id, exp), fe_annot) :: fexps ->
step exp >>= fun exp' ->
- wrap (E_record_update (record, FES_aux (FES_Fexps (evaluated @ FE_aux (FE_Fexp (id, exp'), fe_annot) :: fexps, flag), fes_annot)))
+ wrap (E_record_update (record, evaluated @ FE_aux (FE_Fexp (id, exp'), fe_annot) :: fexps))
| [] ->
List.map value_of_fexp fexps
|> List.fold_left (fun record (field, v) -> StringMap.add field v record) (coerce_record (value_of_exp record))
@@ -539,7 +539,7 @@ let rec step (E_aux (e_aux, annot) as orig_exp) =
begin try
let open Type_check in
let lexp_exp = infer_exp (env_of_annot annot) (exp_of_lexp (strip_lexp lexp)) in
- let exp' = E_aux (E_record_update (lexp_exp, FES_aux (FES_Fexps ([FE_aux (FE_Fexp (id, exp), ul)], false), ul)), ul) in
+ let exp' = E_aux (E_record_update (lexp_exp, [FE_aux (FE_Fexp (id, exp), ul)]), ul) in
wrap (E_assign (lexp, exp'))
with Failure s -> fail ("Failure: " ^ s)
end
@@ -699,13 +699,13 @@ and pattern_match env (P_aux (p_aux, (l, _)) as pat) value =
recursive call that has an empty_tannot we must not use the
annotation in the whole vector_concat pattern. *)
let open Type_check in
- begin match destruct_vector (pat_env_of pat) (pat_typ_of pat) with
+ begin match destruct_vector (env_of_pat pat) (typ_of_pat pat) with
| Some (Nexp_aux (Nexp_constant n, _), _, _) ->
let init, rest = Util.take (Big_int.to_int n) (coerce_gv value), Util.drop (Big_int.to_int n) (coerce_gv value) in
let init_match, init_bind = pattern_match env pat (V_vector init) in
let rest_match, rest_bind = pattern_match env (P_aux (P_vector_concat pats, (l, empty_tannot))) (V_vector rest) in
init_match && rest_match, Bindings.merge combine init_bind rest_bind
- | _ -> failwith ("Bad vector annotation " ^ string_of_typ (Type_check.pat_typ_of pat))
+ | _ -> failwith ("Bad vector annotation " ^ string_of_typ (Type_check.typ_of_pat pat))
end
| P_tup [pat] -> pattern_match env pat value
| P_tup pats | P_list pats ->
@@ -888,7 +888,7 @@ let rec eval_frame' = function
let eval_frame frame =
try eval_frame' frame with
| Type_check.Type_error (l, err) ->
- raise (Reporting_basic.err_typ l (Type_error.string_of_type_error err))
+ raise (Reporting.err_typ l (Type_error.string_of_type_error err))
let default_effect_interp state eff =
let lstate, gstate = state in
diff --git a/src/isail.ml b/src/isail.ml
index 863c4b1c..5c578220 100644
--- a/src/isail.ml
+++ b/src/isail.ml
@@ -57,6 +57,7 @@ open Pretty_print_sail
type mode =
| Evaluation of frame
+ | Bytecode of Value2.vl Bytecode_interpreter.gstate * Value2.vl Bytecode_interpreter.stack
| Normal
let current_mode = ref Normal
@@ -65,6 +66,7 @@ let prompt () =
match !current_mode with
| Normal -> "sail> "
| Evaluation _ -> "eval> "
+ | Bytecode _ -> "ir> "
let eval_clear = ref true
@@ -72,6 +74,7 @@ let mode_clear () =
match !current_mode with
| Normal -> ()
| Evaluation _ -> if !eval_clear then LNoise.clear_screen () else ()
+ | Bytecode _ -> () (* if !eval_clear then LNoise.clear_screen () else () *)
let rec user_input callback =
match LNoise.linenoise (prompt ()) with
@@ -80,7 +83,7 @@ let rec user_input callback =
mode_clear ();
begin
try callback v with
- | Reporting_basic.Fatal_error e -> Reporting_basic.report_error e
+ | Reporting.Fatal_error e -> Reporting.report_error e
end;
user_input callback
@@ -105,16 +108,35 @@ let vs_ids = ref (Initial_check.val_spec_ids !interactive_ast)
let interactive_state = ref (initial_state !interactive_ast !interactive_env Value.primops)
+let interactive_bytecode = ref []
+
+let sep = "-----------------------------------------------------" |> Util.blue |> Util.clear
+
let print_program () =
match !current_mode with
| Normal -> ()
| Evaluation (Step (out, _, _, stack)) ->
- let sep = "-----------------------------------------------------" |> Util.blue |> Util.clear in
List.map stack_string stack |> List.rev |> List.iter (fun code -> print_endline (Lazy.force code); print_endline sep);
print_endline (Lazy.force out)
| Evaluation (Done (_, v)) ->
print_endline (Value.string_of_value v |> Util.green |> Util.clear)
| Evaluation _ -> ()
+ | Bytecode (_, stack) ->
+ let open Bytecode_interpreter in
+ let open Bytecode_util in
+ let pc = stack.top.pc in
+ let instrs = stack.top.instrs in
+ for i = 0 to stack.top.pc - 1 do
+ print_endline (" " ^ Pretty_print_sail.to_string (pp_instr instrs.(i)))
+ done;
+ print_endline (">> " ^ Pretty_print_sail.to_string (pp_instr instrs.(stack.top.pc)));
+ for i = stack.top.pc + 1 to Array.length instrs - 1 do
+ print_endline (" " ^ Pretty_print_sail.to_string (pp_instr instrs.(i)))
+ done;
+ print_endline sep;
+ print_endline (Util.string_of_list ", "
+ (fun (id, vl) -> Printf.sprintf "%s = %s" (string_of_id id) (string_of_value vl))
+ (Bindings.bindings stack.top.locals))
let rec run () =
match !current_mode with
@@ -146,6 +168,7 @@ let rec run () =
end;
run ()
end
+ | Bytecode _ -> ()
let rec run_steps n =
print_endline ("step " ^ string_of_int n);
@@ -179,6 +202,7 @@ let rec run_steps n =
end;
run_steps (n - 1)
end
+ | Bytecode _ -> ()
let help = function
| ":t" | ":type" ->
@@ -250,6 +274,8 @@ let handle_input' input =
| Command (cmd, arg) ->
begin
match cmd with
+ | ":n" | ":normal" ->
+ current_mode := Normal
| ":t" | ":type" ->
let typq, typ = Type_check.Env.get_val_spec (mk_id arg) !interactive_env in
pretty_sail stdout (doc_binding (typq, typ));
@@ -258,10 +284,13 @@ let handle_input' input =
Value.output_close ();
exit 0
| ":i" | ":infer" ->
- let exp = Initial_check.exp_of_string dec_ord arg in
+ let exp = Initial_check.exp_of_string arg in
let exp = Type_check.infer_exp !interactive_env exp in
pretty_sail stdout (doc_typ (Type_check.typ_of exp));
print_newline ()
+ | ":canon" ->
+ let typ = Initial_check.typ_of_string arg in
+ print_endline (string_of_typ (Type_check.canonicalize !interactive_env typ))
| ":v" | ":verbose" ->
Type_check.opt_tc_debug := (!Type_check.opt_tc_debug + 1) mod 3;
print_endline ("Verbosity: " ^ string_of_int !Type_check.opt_tc_debug)
@@ -303,19 +332,26 @@ let handle_input' input =
interactive_env := env;
interactive_state := initial_state !interactive_ast !interactive_env Value.primops
| ":pretty" ->
- print_endline (Pretty_print_sail.to_string (Latex.latex_defs "sail_latex" !interactive_ast))
- | ":bytecode" ->
+ print_endline (Pretty_print_sail.to_string (Latex.defs !interactive_ast))
+ | ":compile" ->
let open PPrint in
let open C_backend in
let ast = Process_file.rewrite_ast_c !interactive_env !interactive_ast in
let ast, env = Specialize.specialize ast !interactive_env in
let ctx = initial_ctx env in
- let byte_ast = bytecode_ast ctx (List.map flatten_instrs) ast in
- let chan = open_out arg in
- Util.opt_colors := false;
- Pretty_print_sail.pretty_sail chan (separate_map hardline Bytecode_util.pp_cdef byte_ast);
- Util.opt_colors := true;
- close_out chan
+ interactive_bytecode := bytecode_ast ctx (List.map flatten_cdef) ast
+ | ":ir" ->
+ print_endline arg;
+ let open Bytecode in
+ let open Bytecode_util in
+ let open PPrint in
+ let is_cdef = function
+ | CDEF_fundef (id, _, _, _) when Id.compare id (mk_id arg) = 0 -> true
+ | CDEF_spec (id, _, _) when Id.compare id (mk_id arg) = 0 -> true
+ | _ -> false
+ in
+ let cdefs = List.filter is_cdef !interactive_bytecode in
+ print_endline (Pretty_print_sail.to_string (separate_map hardline pp_cdef cdefs))
| ":ast" ->
let chan = open_out arg in
Pretty_print_sail.pp_defs chan !interactive_ast;
@@ -363,72 +399,89 @@ let handle_input' input =
vs_ids := Initial_check.val_spec_ids !interactive_ast;
(* See initial_check.mli for an explanation of why we need this. *)
Initial_check.have_undefined_builtins := false
+ | ":exec" ->
+ let open Bytecode_interpreter in
+ let exp = Type_check.infer_exp !interactive_env (Initial_check.exp_of_string arg) in
+ let anf = Anf.anf exp in
+ let ctx = C_backend.initial_ctx !interactive_env in
+ let ctyp = C_backend.ctyp_of_typ ctx (Type_check.typ_of exp) in
+ let setup, call, cleanup = C_backend.compile_aexp ctx anf in
+ let instrs = C_backend.flatten_instrs (setup @ [call (CL_id (mk_id "interactive#", ctyp))] @ cleanup) in
+ current_mode := Bytecode (new_gstate !interactive_bytecode, new_stack instrs);
+ print_program ()
| _ -> unrecognised_command cmd
end
| Expression str ->
(* An expression in normal mode is type checked, then puts
us in evaluation mode. *)
- let exp = Type_check.infer_exp !interactive_env (Initial_check.exp_of_string Ast_util.dec_ord str) in
+ let exp = Type_check.infer_exp !interactive_env (Initial_check.exp_of_string str) in
current_mode := Evaluation (eval_frame (Step (lazy "", !interactive_state, return exp, [])));
print_program ()
| Empty -> ()
end
| Evaluation frame ->
- begin
- match input with
- | Command (cmd, arg) ->
- (* Evaluation mode commands *)
- begin
- match cmd with
- | ":r" | ":run" ->
- run ()
- | ":s" | ":step" ->
- run_steps (int_of_string arg)
- | ":n" | ":normal" ->
- current_mode := Normal
- | _ -> unrecognised_command cmd
- end
- | Expression str ->
- print_endline "Already evaluating expression"
- | Empty ->
- (* Empty input will evaluate one step, or switch back to
+ begin match input with
+ | Command (cmd, arg) ->
+ (* Evaluation mode commands *)
+ begin
+ match cmd with
+ | ":r" | ":run" ->
+ run ()
+ | ":s" | ":step" ->
+ run_steps (int_of_string arg)
+ | _ -> unrecognised_command cmd
+ end
+ | Expression str ->
+ print_endline "Already evaluating expression"
+ | Empty ->
+ (* Empty input will evaluate one step, or switch back to
normal mode when evaluation is completed. *)
- begin
- match frame with
- | Done (state, v) ->
+ begin match frame with
+ | Done (state, v) ->
+ interactive_state := state;
+ print_endline ("Result = " ^ Value.string_of_value v);
+ current_mode := Normal
+ | Step (out, state, _, stack) ->
+ begin
+ try
interactive_state := state;
- print_endline ("Result = " ^ Value.string_of_value v);
- current_mode := Normal
- | Step (out, state, _, stack) ->
- begin
- try
- interactive_state := state;
- current_mode := Evaluation (eval_frame frame);
- print_program ()
- with
- | Failure str -> print_endline str; current_mode := Normal
- end
- | Break frame ->
- print_endline "Breakpoint";
- current_mode := Evaluation frame
- | Effect_request (state, eff) ->
- begin
- try
- interactive_state := state;
- current_mode := Evaluation (Interpreter.default_effect_interp state eff);
- print_program ()
- with
- | Failure str -> print_endline str; current_mode := Normal
- end
- end
+ current_mode := Evaluation (eval_frame frame);
+ print_program ()
+ with
+ | Failure str -> print_endline str; current_mode := Normal
+ end
+ | Break frame ->
+ print_endline "Breakpoint";
+ current_mode := Evaluation frame
+ | Effect_request (state, eff) ->
+ begin
+ try
+ interactive_state := state;
+ current_mode := Evaluation (Interpreter.default_effect_interp state eff);
+ print_program ()
+ with
+ | Failure str -> print_endline str; current_mode := Normal
+ end
+ end
end
-
+ | Bytecode (gstate, stack) ->
+ begin match input with
+ | Command (cmd, arg) ->
+ ()
+ | Expression str ->
+ print_endline "Evaluating IR, cannot evaluate expression"
+ | Empty ->
+ let gstate, stack = Bytecode_interpreter.step (gstate, stack) in
+ current_mode := Bytecode (gstate, stack);
+ print_program ()
+ end
+
let handle_input input =
try handle_input' input with
| Type_check.Type_error (l, err) ->
print_endline (Type_error.string_of_type_error err)
- | Reporting_basic.Fatal_error err ->
- Reporting_basic.print_error err
+ | Reporting.Fatal_error err ->
+ Reporting.print_error err
| exn ->
print_endline (Printexc.to_string exn)
diff --git a/src/latex.ml b/src/latex.ml
index 39db43db..2f578f2c 100644
--- a/src/latex.ml
+++ b/src/latex.ml
@@ -51,51 +51,223 @@
open Ast
open Ast_util
open PPrint
+open Printf
-let opt_prefix_latex = ref "sail"
+module StringSet = Set.Make(String);;
+
+let opt_prefix = ref "sail"
+let opt_directory = ref "sail_latex"
+
+let rec unique_postfix n =
+ if n < 0 then
+ ""
+ else if n >= 26 then
+ String.make 1 (Char.chr (n mod 26 + 65)) ^ unique_postfix (n - 26)
+ else
+ String.make 1 (Char.chr (n mod 26 + 65))
+
+type latex_state =
+ { mutable noindent : bool;
+ mutable this : id option;
+ mutable norefs : StringSet.t;
+ mutable generated_names : string Bindings.t
+ }
+
+let reset_state state =
+ state.noindent <- false;
+ state.this <- None;
+ state.norefs <- StringSet.empty;
+ state.generated_names <- Bindings.empty
+
+let state =
+ { noindent = false;
+ this = None;
+ norefs = StringSet.empty;
+ generated_names = Bindings.empty
+ }
+
+let rec unique_postfix n =
+ if n < 0 then
+ ""
+ else if n >= 26 then
+ String.make 1 (Char.chr (n mod 26 + 65)) ^ unique_postfix (n - 26)
+ else
+ String.make 1 (Char.chr (n mod 26 + 65))
+
+type id_category =
+ | Function
+ | Val
+ | Overload
+ | FunclCtor of id * int
+ | FunclNum of int
+ | FunclApp of string
let replace_numbers str =
- str
- |> Str.global_replace (Str.regexp "0") "zero"
- |> Str.global_replace (Str.regexp "1") "one"
- |> Str.global_replace (Str.regexp "2") "two"
- |> Str.global_replace (Str.regexp "3") "three"
- |> Str.global_replace (Str.regexp "4") "four"
- |> Str.global_replace (Str.regexp "5") "five"
- |> Str.global_replace (Str.regexp "6") "six"
- |> Str.global_replace (Str.regexp "7") "seven"
- |> Str.global_replace (Str.regexp "8") "eight"
- |> Str.global_replace (Str.regexp "9") "nine"
-
-let namecode_string str =
- let str = Str.global_replace (Str.regexp "_") "" (Util.zencode_string str) in
- replace_numbers (String.sub str 1 (String.length str - 1))
-
-let namecode_id id = namecode_string (string_of_id id)
+ let replacements =
+ [ ("0", "Zero");
+ ("1", "One");
+ ("2", "Two");
+ ("3", "Three");
+ ("4", "Four");
+ ("5", "Five");
+ ("6", "Six");
+ ("7", "Seven");
+ ("8", "Eight");
+ ("9", "Nine") ]
+ in
+ List.fold_left (fun str (from, into) -> Str.global_replace (Str.regexp_string from) into str) str replacements
+
+let category_name = function
+ | Function -> "fn"
+ | Val -> "val"
+ | Overload -> "overload"
+ | FunclNum n -> "fcl" ^ unique_postfix n
+ | FunclCtor (id, n) ->
+ let str = replace_numbers (Util.zencode_string (string_of_id id)) in
+ "fcl" ^ String.sub str 1 (String.length str - 1) ^ unique_postfix n
+ | FunclApp str -> "fcl" ^ str
+
+let category_name_val = function
+ | Val -> ""
+ | cat -> category_name cat
+
+let category_name_simple = function
+ | Function -> "fn"
+ | Val -> "val"
+ | Overload -> "overload"
+ | FunclNum _ -> "fcl"
+ | FunclCtor (_, _) -> "fcl"
+ | FunclApp _ -> "fcl"
+
+(* Generate a unique latex identifier from a Sail identifier. We store
+ a mapping from identifiers to strings in state so we always return
+ the same latex id for a sail id. *)
+let latex_id id =
+ if Bindings.mem id state.generated_names then
+ Bindings.find id state.generated_names
+ else
+ let str = string_of_id id in
+ let r = Str.regexp {|_\([a-zA-Z0-9]\)|} in
+ let str =
+ (* Convert to CamelCase. OCaml's regexp library is a bit arcane. *)
+ let str = ref str in
+ try
+ while true do
+ ignore (Str.search_forward r !str 0);
+ let replace = (Str.matched_group 0 !str).[1] |> Char.uppercase_ascii |> String.make 1 in
+ str := Str.replace_first r replace !str
+ done; ""
+ with Not_found -> !str
+ in
+ (* If we have any other weird symbols in the id, remove them using Util.zencode_string (removing the z prefix) *)
+ let str = Util.zencode_string str in
+ let str = String.sub str 1 (String.length str - 1) in
+ (* Latex only allows letters in identifiers, so replace all numbers *)
+ let str = replace_numbers str in
+
+ let generated = state.generated_names |> Bindings.bindings |> List.map snd |> StringSet.of_list in
+
+ (* The above makes maps different names to the same name, so we need
+ to keep track of what names we've generated an ensure that they
+ remain unique. *)
+ let rec unique n str =
+ if StringSet.mem (str ^ unique_postfix n) generated then
+ unique (n + 1) str
+ else
+ str ^ unique_postfix n
+ in
+ let str = unique (-1) str in
+ state.generated_names <- Bindings.add id str state.generated_names;
+ str
let refcode_string str =
- replace_numbers (Str.global_replace (Str.regexp "_") "zy" (Util.zencode_string str))
+ Str.global_replace (Str.regexp "_") "zy" (Util.zencode_string str)
let refcode_id id = refcode_string (string_of_id id)
+let inline_code str = sprintf "\\lstinline{%s}" str
+
+let text_code str =
+ str
+ |> Str.global_replace (Str.regexp_string "_") "\\_"
+ |> Str.global_replace (Str.regexp_string ">") "$<$"
+ |> Str.global_replace (Str.regexp_string "<") "$>$"
+
+let replace_this str =
+ match state.this with
+ | Some id ->
+ str
+ |> Str.global_replace (Str.regexp_string "NAME") (text_code (string_of_id id))
+ |> Str.global_replace (Str.regexp_string "THIS") (inline_code (string_of_id id))
+ | None -> str
+
+let latex_of_markdown str =
+ let open Omd in
+ let open Printf in
+
+ let rec format_elem = function
+ | Paragraph elems ->
+ let prepend = if state.noindent then (state.noindent <- false; "\\noindent ") else "" in
+ prepend ^ format elems ^ "\n\n"
+ | Text str -> Str.global_replace (Str.regexp_string "_") "\\_" str
+ | Emph elems -> sprintf "\\emph{%s}" (format elems)
+ | Bold elems -> sprintf "\\textbf{%s}" (format elems)
+ | Ref (r, "THIS", alt, _) ->
+ begin match state.this with
+ | Some id -> sprintf "\\hyperref[%s]{%s}" (refcode_string (string_of_id id)) (replace_this alt)
+ | None -> failwith "Cannot create link to THIS"
+ end
+ | Ref (r, name, alt, _) ->
+ (* special case for [id] (format as code) *)
+ let format_fn = if name = alt then inline_code else replace_this in
+ begin match r#get_ref name with
+ | None -> sprintf "\\hyperref[%s]{%s}" (refcode_string name) (format_fn alt)
+ | Some (link, _) -> sprintf "\\hyperref[%s]{%s}" (refcode_string link) (format_fn alt)
+ end
+ | Url (href, text, "") ->
+ sprintf "\\href{%s}{%s}" href (format text)
+ | Url (href, text, reference) ->
+ sprintf "%s\\footnote{%s~\\url{%s}}" (format text) reference href
+ | Code (_, code) ->
+ sprintf "\\lstinline`%s`" code
+ | Code_block (lang, code) ->
+ let lang = if lang = "" then "sail" else lang in
+ let uid = Digest.string str |> Digest.to_hex in
+ let chan = open_out (Filename.concat !opt_directory (sprintf "block%s.%s" uid lang)) in
+ output_string chan code;
+ close_out chan;
+ sprintf "\\lstinputlisting[language=%s]{%s/block%s.%s}" lang !opt_directory uid lang
+ | Ul list ->
+ "\\begin{itemize}\n\\item "
+ ^ Util.string_of_list "\n\\item " format list
+ ^ "\n\\end{itemize}"
+ | Br -> "\n"
+ | NL -> "\n"
+ | elem -> failwith ("Can't convert to latex: " ^ to_text [elem])
+
+ and format elems =
+ String.concat "" (List.map format_elem elems)
+ in
+
+ replace_this (format (of_string str))
+
let docstring = function
- | Parse_ast.Documented (str, _) -> string str
+ | Parse_ast.Documented (str, _) -> string (latex_of_markdown str)
| _ -> empty
let add_links str =
let r = Str.regexp {|\([a-zA-Z0-9_]+\)\([ ]*\)(|} in
let subst s =
- let module StringSet = Set.Make(String) in
let keywords = StringSet.of_list
[ "function"; "forall"; "if"; "then"; "else"; "exit"; "return"; "match"; "vector";
"assert"; "constraint"; "let"; "in"; "atom"; "range"; "throw"; "sizeof"; "foreach" ]
in
let fn = Str.matched_group 1 s in
let spacing = Str.matched_group 2 s in
- if StringSet.mem fn keywords then
+ if StringSet.mem fn keywords || StringSet.mem fn state.norefs then
fn ^ spacing ^ "("
else
- Printf.sprintf {|#\hyperref[%s]{%s}#%s(|} (refcode_string fn) (Str.global_replace (Str.regexp "_") {|\_|} fn) spacing
+ Printf.sprintf "#\\hyperref[%s]{%s}#%s(" (refcode_string fn) (Str.global_replace (Str.regexp "_") {|\_|} fn) spacing
in
Str.global_substitute r subst str
@@ -105,7 +277,7 @@ let latex_loc no_loc l =
begin
let using_color = !Util.opt_colors in
Util.opt_colors := false;
- let code = Util.split_on_char '\n' (Reporting_basic.loc_to_string l) in
+ let code = Util.split_on_char '\n' (Reporting.loc_to_string l) in
let doc = match code with
| _ :: _ :: code -> string (add_links (String.concat "\n" code))
| _ -> empty
@@ -116,30 +288,30 @@ let latex_loc no_loc l =
| _ -> docstring l ^^ no_loc
-module StringSet = Set.Make(String)
-
let commands = ref StringSet.empty
-let rec latex_command ?prefix:(prefix="") ?label:(label=None) dir cmd no_loc ((l, _) as annot) =
- let labelling = match label with
- | None -> ""
- | Some l -> Printf.sprintf "\\label{%s}" l
+let doc_spec_simple (VS_val_spec(ts,id,ext,is_cast)) =
+ Pretty_print_sail.doc_id id ^^ space
+ ^^ colon ^^ space
+ ^^ Pretty_print_sail.doc_typschm ~simple:true ts
+
+let rec latex_command cat id no_loc ((l, _) as annot) =
+ state.this <- Some id;
+ let labelling = match cat with
+ | Val -> sprintf "\\label{%s}" (refcode_id id)
+ | _ -> sprintf "\\label{%s%s}" (category_name cat) (refcode_id id)
in
- let cmd = !opt_prefix_latex ^ prefix ^ cmd in
- let lcmd = String.lowercase_ascii cmd in (* lowercase to avoid file names differing only by case *)
- if StringSet.mem lcmd !commands then
- latex_command ~label:label dir (cmd ^ "v") no_loc annot
- else
- begin
- commands := StringSet.add lcmd !commands;
- let oc = open_out (Filename.concat dir (cmd ^ ".tex")) in
- output_string oc (Pretty_print_sail.to_string (latex_loc no_loc l));
- close_out oc;
- string (Printf.sprintf "\\newcommand{\\%s}{%s " cmd labelling) ^^ (docstring l) ^^ string (Printf.sprintf "\\lstinputlisting[language=sail]{%s/%s.tex}}" dir cmd)
- end
+ (* To avoid problems with verbatim environments in commands, we have
+ to put the sail code for each command in a separate file. *)
+ let code_file = category_name cat ^ Util.file_encode_string (string_of_id id) ^ ".tex" in
+ let chan = open_out (Filename.concat !opt_directory code_file) in
+ let doc = if cat = Val then no_loc else latex_loc no_loc l in
+ output_string chan (Pretty_print_sail.to_string doc);
+ close_out chan;
-let latex_command_id ?prefix:(prefix="") dir id no_loc annot =
- latex_command ~prefix:prefix ~label:(Some (refcode_id id)) dir (namecode_id id) no_loc annot
+ ksprintf string "\\newcommand{\\sail%s%s}{\\phantomsection%s\\saildoc%s{" (category_name cat) (latex_id id) labelling (category_name_simple cat)
+ ^^ docstring l ^^ string "}{"
+ ^^ ksprintf string "\\lstinputlisting[language=sail]{%s}}}" (Filename.concat !opt_directory code_file)
let latex_label str id =
string (Printf.sprintf "\\label{%s:%s}" str (Util.zencode_string (string_of_id id)))
@@ -148,44 +320,134 @@ let counter = ref 0
let rec app_code (E_aux (exp, _)) =
match exp with
- | E_app (f, [exp]) -> namecode_id f ^ app_code exp
- | E_app (f, _) -> namecode_id f
- | E_id id -> namecode_id id
+ | E_app (f, [exp]) when Id.compare f (mk_id "Some") = 0 -> app_code exp
+ | E_app (f, [exp]) -> latex_id f ^ app_code exp
+ | E_app (f, _) -> latex_id f
+ | E_id id -> latex_id id
| _ -> ""
-let rec latex_funcls dir def =
- let next funcls = twice hardline ^^ latex_funcls dir def funcls in
- let funcl_command (FCL_Funcl (id, pexp)) =
- match pexp with
- | Pat_aux (Pat_exp (P_aux (P_app (ctor, _), _), _), _) -> namecode_id id ^ namecode_id ctor
- | Pat_aux (Pat_exp (_, exp), _) -> namecode_id id ^ app_code exp
- | _ -> (incr counter; namecode_id id ^ String.make 1 (Char.chr (!counter + 64)))
+let latex_funcls def =
+ let module StringMap = Map.Make(String) in
+ let counter = ref 0 in
+ let app_codes = ref StringMap.empty in
+ let ctors = ref Bindings.empty in
+
+ let rec latex_funcls' def =
+ let counter = ref (-1) in
+ let next funcls = twice hardline ^^ latex_funcls' def funcls in
+ let funcl_command (FCL_Funcl (id, pexp)) =
+ match pexp with
+ | Pat_aux (Pat_exp (P_aux (P_app (ctor, _), _), _), _) ->
+ let n = try Bindings.find ctor !ctors with Not_found -> -1 in
+ ctors := Bindings.add ctor (n + 1) !ctors;
+ FunclCtor (ctor, n), id
+ | Pat_aux (Pat_exp (_, exp), _) ->
+ let ac = app_code exp in
+ let n = try StringMap.find ac !app_codes with Not_found -> -1 in
+ app_codes := StringMap.add ac (n + 1) !app_codes;
+ FunclApp (ac ^ unique_postfix n), id
+ | _ -> incr counter; (FunclNum (!counter + 64), id)
+ in
+ function
+ | (FCL_aux (funcl_aux, annot) as funcl) :: funcls ->
+ let cat, id = funcl_command funcl_aux in
+ let first = latex_command cat id (Pretty_print_sail.doc_funcl funcl) annot in
+ first ^^ next funcls
+ | [] -> empty
+ in
+ latex_funcls' def
+
+let process_pragma l command =
+ let n = try String.index command ' ' with Not_found -> String.length command in
+ let cmd = Str.string_before command n in
+ let arg = String.trim (Str.string_after command n) in
+
+ match cmd with
+ | "noindent" ->
+ state.noindent <- true;
+ None
+
+ | "noref" ->
+ state.norefs <- StringSet.add arg state.norefs;
+ None
+
+ | "newcommand" ->
+ let n = try String.index arg ' ' with Not_found -> failwith "No command given" in
+ let name = Str.string_before arg n in
+ let body = String.trim (latex_of_markdown (Str.string_after arg n)) in
+ Some (ksprintf string "\\newcommand{\\%s}{%s}" name body)
+
+ | _ ->
+ Util.warn (Printf.sprintf "Bad latex pragma %s" (Reporting.loc_to_string l));
+ None
+
+let defs (Defs defs) =
+ reset_state state;
+
+ let valspecs = ref IdSet.empty in
+ let fundefs = ref IdSet.empty in
+
+ let latex_def def =
+ match def with
+ | DEF_overload (id, ids) -> None
+ (*
+ let doc =
+ string (Printf.sprintf "overload %s = {%s}" (string_of_id id) (Util.string_of_list ", " string_of_id ids))
+ in
+ Some (latex_command Overload id doc (id_loc id, None))
+ *)
+
+ | DEF_spec (VS_aux (VS_val_spec (_, id, _, _) as vs, annot)) as def ->
+ valspecs := IdSet.add id !valspecs;
+ Some (latex_command Val id (doc_spec_simple vs) annot)
+
+ | DEF_fundef (FD_aux (FD_function (_, _, _, [FCL_aux (FCL_Funcl (id, _), _)]), annot)) as def ->
+ fundefs := IdSet.add id !fundefs;
+ Some (latex_command Function id (Pretty_print_sail.doc_def def) annot)
+
+ | DEF_fundef (FD_aux (FD_function (_, _, _, funcls), annot)) as def ->
+ Some (latex_funcls def funcls)
+
+ | DEF_pragma ("latex", command, l) ->
+ process_pragma l command
+
+ | _ -> None
+ in
+
+ let rec process_defs = function
+ | [] -> empty
+ | def :: defs ->
+ let tex = match latex_def def with
+ | Some tex -> tex ^^ twice hardline
+ | None -> empty
+ in
+ tex ^^ process_defs defs
in
- function
- | (FCL_aux (funcl_aux, annot) as funcl) :: funcls ->
- let first = latex_command ~prefix:"fn" dir (funcl_command funcl_aux) (Pretty_print_sail.doc_funcl funcl) annot in
- first ^^ next funcls
- | [] -> empty
-
-let rec latex_defs dir (Defs defs) =
- let next defs = twice hardline ^^ latex_defs dir (Defs defs) in
- match defs with
- | DEF_overload (id, ids) :: defs ->
- let doc =
- string (Printf.sprintf "overload %s = {%s}" (string_of_id id) (Util.string_of_list ", " string_of_id ids))
- in
- latex_command_id dir id doc (Parse_ast.Unknown, None)
- ^^ next defs
- | (DEF_type (TD_aux (TD_abbrev (id, _, _), annot)) as def) :: defs ->
- latex_command_id dir id (Pretty_print_sail.doc_def def) annot ^^ next defs
- | (DEF_type (TD_aux (TD_record (id, _, _, _, _), annot)) as def) :: defs ->
- latex_command_id dir id (Pretty_print_sail.doc_def def) annot ^^ next defs
- | (DEF_type (TD_aux (TD_enum (id, _, _, _), annot)) as def) :: defs ->
- latex_command_id dir id (Pretty_print_sail.doc_def def) annot ^^ next defs
- | (DEF_spec (VS_aux (VS_val_spec (_, id, _, _), annot)) as def) :: defs ->
- latex_command_id dir id (Pretty_print_sail.doc_def def) annot ^^ next defs
- | (DEF_fundef (FD_aux (FD_function (_, _, _, [FCL_aux (FCL_Funcl (id, _), _)]), annot)) as def) :: defs ->
- latex_command_id dir ~prefix:"fn" id (Pretty_print_sail.doc_def def) annot ^^ next defs
- | (DEF_fundef (FD_aux (FD_function (_, _, _, funcls), annot)) as def) :: defs -> latex_funcls dir def funcls ^^ next defs
- | _ :: defs -> latex_defs dir (Defs defs)
- | [] -> empty
+
+ let tex = process_defs defs in
+
+ (* Rather than having latex functions that use mangled names, like
+ \sailfnmyFunction for a function my_function, we can write
+ \sailfn{my_function} by generating a latex macro that compares
+ identifiers then outputs the correct mangled command. *)
+ let id_command cat ids =
+ sprintf "\\newcommand{\\%s%s}[1]{\n " !opt_prefix (category_name cat)
+ ^ Util.string_of_list "%\n " (fun id -> sprintf "\\ifstrequal{#1}{%s}{\\sail%s%s}{}" (string_of_id id) (category_name cat) (latex_id id))
+ (IdSet.elements ids)
+ ^ "}"
+ |> string
+ in
+ let ref_command cat ids =
+ sprintf "\\newcommand{\\%sref%s}[2]{\n " !opt_prefix (category_name cat)
+ ^ Util.string_of_list "%\n " (fun id -> sprintf "\\ifstrequal{#1}{%s}{\\hyperref[%s%s]{#2}}{}" (string_of_id id) (category_name_val cat) (refcode_id id))
+ (IdSet.elements ids)
+ ^ "}"
+ |> string
+ in
+
+ tex
+ ^^ separate (twice hardline) [id_command Val !valspecs;
+ ref_command Val !valspecs;
+ id_command Function !fundefs;
+ ref_command Function !fundefs]
+ ^^ hardline
diff --git a/src/lem_interp/sail2_instr_kinds.lem b/src/lem_interp/sail2_instr_kinds.lem
index 3d238676..eadc85bf 100644
--- a/src/lem_interp/sail2_instr_kinds.lem
+++ b/src/lem_interp/sail2_instr_kinds.lem
@@ -155,6 +155,7 @@ type barrier_kind =
| Barrier_RISCV_rw_r
| Barrier_RISCV_r_w
| Barrier_RISCV_w_r
+ | Barrier_RISCV_tso
| Barrier_RISCV_i
(* X86 *)
| Barrier_x86_MFENCE
@@ -184,6 +185,7 @@ instance (Show barrier_kind)
| Barrier_RISCV_rw_r -> "Barrier_RISCV_rw_r"
| Barrier_RISCV_r_w -> "Barrier_RISCV_r_w"
| Barrier_RISCV_w_r -> "Barrier_RISCV_w_r"
+ | Barrier_RISCV_tso -> "Barrier_RISCV_tso"
| Barrier_RISCV_i -> "Barrier_RISCV_i"
| Barrier_x86_MFENCE -> "Barrier_x86_MFENCE"
end
@@ -300,7 +302,8 @@ instance (EnumerationType barrier_kind)
| Barrier_RISCV_rw_r -> 19
| Barrier_RISCV_r_w -> 20
| Barrier_RISCV_w_r -> 21
- | Barrier_RISCV_i -> 22
- | Barrier_x86_MFENCE -> 23
+ | Barrier_RISCV_tso -> 22
+ | Barrier_RISCV_i -> 23
+ | Barrier_x86_MFENCE -> 24
end
end
diff --git a/src/lexer.mll b/src/lexer.mll
index cbefa601..57580e7a 100644
--- a/src/lexer.mll
+++ b/src/lexer.mll
@@ -97,8 +97,7 @@ let operators = ref
(List.fold_left
(fun r (x, y) -> M.add x y r)
M.empty
- [ ("==", mk_operator Infix 4 "==");
- ("/", mk_operator InfixL 7 "/");
+ [ ("/", mk_operator InfixL 7 "/");
("%", mk_operator InfixL 7 "%");
])
@@ -141,11 +140,13 @@ let kw_table =
("ref", (fun _ -> Ref));
("Int", (fun x -> Int));
("Order", (fun x -> Order));
+ ("Bool", (fun x -> Bool));
("pure", (fun x -> Pure));
("register", (fun x -> Register));
("return", (fun x -> Return));
("scattered", (fun x -> Scattered));
("sizeof", (fun x -> Sizeof));
+ ("constant", (fun x -> Constant));
("constraint", (fun x -> Constraint));
("struct", (fun x -> Struct));
("then", (fun x -> Then));
@@ -163,7 +164,6 @@ let kw_table =
("do", (fun _ -> Do));
("mutual", (fun _ -> Mutual));
("bitfield", (fun _ -> Bitfield));
- ("tuple", (fun _ -> Tuple));
("where", (fun _ -> Where));
("barr", (fun x -> Barr));
@@ -225,9 +225,7 @@ rule token = parse
| "," { Comma }
| ".." { DotDot }
| "." { Dot }
- | "==" as op
- { try M.find op !operators
- with Not_found -> raise (LexError ("Operator fixity undeclared " ^ op, Lexing.lexeme_start_p lexbuf)) }
+ | "==" { EqEq(r"==") }
| "=" { (Eq(r"=")) }
| ">" { (Gt(r">")) }
| "-" { Minus }
@@ -329,12 +327,12 @@ and string pos b = parse
| ([^'"''\n''\\']* as i) { Buffer.add_string b i; string pos b lexbuf }
| escape_sequence as i { Buffer.add_string b i; string pos b lexbuf }
| '\\' '\n' ws { Lexing.new_line lexbuf; string pos b lexbuf }
- | '\\' { assert false (*raise (Reporting_basic.Fatal_error (Reporting_basic.Err_syntax (pos,
+ | '\\' { assert false (*raise (Reporting.Fatal_error (Reporting.Err_syntax (pos,
"illegal backslash escape in string"*) }
| '"' { let s = unescaped(Buffer.contents b) in
(*try Ulib.UTF8.validate s; s
with Ulib.UTF8.Malformed_code ->
- raise (Reporting_basic.Fatal_error (Reporting_basic.Err_syntax (pos,
+ raise (Reporting.Fatal_error (Reporting.Err_syntax (pos,
"String literal is not valid utf8"))) *) s }
- | eof { assert false (*raise (Reporting_basic.Fatal_error (Reporting_basic.Err_syntax (pos,
+ | eof { assert false (*raise (Reporting.Fatal_error (Reporting.Err_syntax (pos,
"String literal not terminated")))*) }
diff --git a/src/monomorphise.ml b/src/monomorphise.ml
index f7a481e6..4bb1876c 100644
--- a/src/monomorphise.ml
+++ b/src/monomorphise.ml
@@ -115,7 +115,7 @@ let rec subst_nc substs (NC_aux (nc,l) as n_constraint) =
| Nexp_aux (Nexp_constant i,_) ->
if List.exists (fun j -> Big_int.equal i j) is then re NC_true else re NC_false
| nexp ->
- raise (Reporting_basic.err_general l
+ raise (Reporting.err_general l
("Unable to substitute " ^ string_of_nexp nexp ^
" into set constraint " ^ string_of_n_constraint n_constraint))
| exception Not_found -> n_constraint
@@ -139,15 +139,15 @@ let subst_src_typ substs t =
| Typ_bidir (t1, t2) -> re (Typ_bidir (s_styp substs t1, s_styp substs t2))
| Typ_tup ts -> re (Typ_tup (List.map (s_styp substs) ts))
| Typ_app (id,tas) -> re (Typ_app (id,List.map (s_starg substs) tas))
- | Typ_exist (kids,nc,t) ->
- let substs = List.fold_left (fun sub v -> KBindings.remove v sub) substs kids in
- re (Typ_exist (kids,nc,s_styp substs t))
+ | Typ_exist (kopts,nc,t) ->
+ let substs = List.fold_left (fun sub kopt -> KBindings.remove (kopt_kid kopt) sub) substs kopts in
+ re (Typ_exist (kopts,nc,s_styp substs t))
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
- and s_starg substs (Typ_arg_aux (ta,l) as targ) =
+ and s_starg substs (A_aux (ta,l) as targ) =
match ta with
- | Typ_arg_nexp ne -> Typ_arg_aux (Typ_arg_nexp (subst_nexp substs ne),l)
- | Typ_arg_typ t -> Typ_arg_aux (Typ_arg_typ (s_styp substs t),l)
- | Typ_arg_order _ -> targ
+ | A_nexp ne -> A_aux (A_nexp (subst_nexp substs ne),l)
+ | A_typ t -> A_aux (A_typ (s_styp substs t),l)
+ | A_order _ -> targ
in s_styp substs t
let make_vector_lit sz i =
@@ -180,7 +180,7 @@ let rec is_value (E_aux (e,(l,annot))) =
let is_constructor id =
match destruct_tannot annot with
| None ->
- (Reporting_basic.print_err false true l "Monomorphisation"
+ (Reporting.print_err false true l "Monomorphisation"
("Missing type information for identifier " ^ string_of_id id);
false) (* Be conservative if we have no info *)
| Some (env,_,_) ->
@@ -281,7 +281,7 @@ let extract_set_nc l var nc =
| None, Some (is,nc2') -> Some (is, re (NC_and (nc1,nc2')))
| Some (is,nc1'), None -> Some (is, re (NC_and (nc1',nc2)))
| Some _, Some _ ->
- raise (Reporting_basic.err_general l ("Multiple set constraints for " ^ string_of_kid var)))
+ raise (Reporting.err_general l ("Multiple set constraints for " ^ string_of_kid var)))
| NC_or _ ->
(match aux_or nc_full with
| Some is -> Some (is, re NC_true)
@@ -290,7 +290,7 @@ let extract_set_nc l var nc =
in match aux nc with
| Some is -> is
| None ->
- raise (Reporting_basic.err_general l ("No set constraint for " ^ string_of_kid var ^
+ raise (Reporting.err_general l ("No set constraint for " ^ string_of_kid var ^
" in " ^ string_of_n_constraint nc))
let rec peel = function
@@ -315,9 +315,9 @@ let rec inst_src_type insts (Typ_aux (ty,l) as typ) =
| Typ_var _
-> insts,typ
| Typ_fn _ ->
- raise (Reporting_basic.err_general l "Function type in constructor")
+ raise (Reporting.err_general l "Function type in constructor")
| Typ_bidir _ ->
- raise (Reporting_basic.err_general l "Mapping type in constructor")
+ raise (Reporting.err_general l "Mapping type in constructor")
| Typ_tup ts ->
let insts,ts =
List.fold_right
@@ -330,23 +330,25 @@ let rec inst_src_type insts (Typ_aux (ty,l) as typ) =
(fun arg (insts,args) -> let insts,arg = inst_src_typ_arg insts arg in insts,arg::args)
args (insts,[])
in insts, Typ_aux (Typ_app (id,ts),l)
- | Typ_exist (kids, nc, t) -> begin
+ | Typ_exist (kopts, nc, t) -> begin
+ (* TODO handle non-integer existentials *)
+ let kids = List.map kopt_kid kopts in
let kid_insts, insts' = peel (kids,insts) in
let kids', t' = apply_kid_insts kid_insts t in
(* TODO: subst in nc *)
match kids' with
| [] -> insts', t'
- | _ -> insts', Typ_aux (Typ_exist (kids', nc, t'), l)
+ | _ -> insts', Typ_aux (Typ_exist (List.map (mk_kopt K_int) kids', nc, t'), l)
end
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and inst_src_typ_arg insts (Typ_arg_aux (ta,l) as tyarg) =
+and inst_src_typ_arg insts (A_aux (ta,l) as tyarg) =
match ta with
- | Typ_arg_nexp _
- | Typ_arg_order _
+ | A_nexp _
+ | A_order _
-> insts, tyarg
- | Typ_arg_typ typ ->
+ | A_typ typ ->
let insts', typ' = inst_src_type insts typ in
- insts', Typ_arg_aux (Typ_arg_typ typ',l)
+ insts', A_aux (A_typ typ',l)
let rec contains_exist (Typ_aux (ty,l)) =
match ty with
@@ -359,12 +361,12 @@ let rec contains_exist (Typ_aux (ty,l)) =
| Typ_app (_,args) -> List.exists contains_exist_arg args
| Typ_exist _ -> true
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and contains_exist_arg (Typ_arg_aux (arg,_)) =
+and contains_exist_arg (A_aux (arg,_)) =
match arg with
- | Typ_arg_nexp _
- | Typ_arg_order _
+ | A_nexp _
+ | A_order _
-> false
- | Typ_arg_typ typ -> contains_exist typ
+ | A_typ typ -> contains_exist typ
let rec size_nvars_nexp (Nexp_aux (ne,_)) =
match ne with
@@ -393,22 +395,24 @@ let split_src_type id ty (TypQ_aux (q,ql)) =
| Typ_var _
-> (KidSet.empty,[[],typ])
| Typ_fn _ ->
- raise (Reporting_basic.err_general l ("Function type in constructor " ^ i))
+ raise (Reporting.err_general l ("Function type in constructor " ^ i))
| Typ_bidir _ ->
- raise (Reporting_basic.err_general l ("Mapping type in constructor " ^ i))
+ raise (Reporting.err_general l ("Mapping type in constructor " ^ i))
| Typ_tup ts ->
let (vars,tys) = List.split (List.map size_nvars_ty ts) in
let insttys = List.map (fun x -> let (insts,tys) = List.split x in
List.concat insts, Typ_aux (Typ_tup tys,l)) (cross' tys) in
(kidset_bigunion vars, insttys)
| Typ_app (Id_aux (Id "vector",_),
- [Typ_arg_aux (Typ_arg_nexp sz,_);
- _;Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]) ->
+ [A_aux (A_nexp sz,_);
+ _;A_aux (A_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]) ->
(KidSet.of_list (size_nvars_nexp sz), [[],typ])
| Typ_app (_, tas) ->
(KidSet.empty,[[],typ]) (* We only support sizes for bitvectors mentioned explicitly, not any buried
inside another type *)
- | Typ_exist (kids, nc, t) ->
+ | Typ_exist (kopts, nc, t) ->
+ (* TODO handle non integer existentials *)
+ let kids = List.map kopt_kid kopts in
let (vars,tys) = size_nvars_ty t in
let find_insts k (insts,nc) =
let inst,nc' =
@@ -426,7 +430,7 @@ let split_src_type id ty (TypQ_aux (q,ql)) =
(* Typ_exist is not allowed an empty list of kids *)
match kids with
| [] -> ty
- | _ -> Typ_aux (Typ_exist (kids, nc', ty),l)
+ | _ -> Typ_aux (Typ_exist (List.map (mk_kopt K_int) kids, nc', ty),l)
in inst@inst0, ty
in
let tys = List.concat (List.map (fun instty -> List.map (ty_and_inst instty) insts) tys) in
@@ -450,10 +454,10 @@ let split_src_type id ty (TypQ_aux (q,ql)) =
| Typ_aux (Typ_tup _,_) -> Typ_aux (Typ_tup [ty],Unknown)
| _ -> ty) tys in
if contains_exist t then
- raise (Reporting_basic.err_general l
+ raise (Reporting.err_general l
"Only prenex types in unions are supported by monomorphisation")
else if List.length kids > 1 then
- raise (Reporting_basic.err_general l
+ raise (Reporting.err_general l
"Only single-variable existential types in unions are currently supported by monomorphisation")
else tys
end
@@ -465,7 +469,7 @@ let split_src_type id ty (TypQ_aux (q,ql)) =
| [] -> None
| sample::__ ->
let () = if List.length variants > size_set_limit then
- raise (Reporting_basic.err_general ql
+ raise (Reporting.err_general ql
(string_of_int (List.length variants) ^ "variants for constructor " ^ i ^
"bigger than limit " ^ string_of_int size_set_limit)) else ()
in
@@ -490,7 +494,7 @@ let reduce_nexp subst ne =
| Nexp_exp n -> Big_int.shift_left (eval n) 1
| Nexp_neg n -> Big_int.negate (eval n)
| _ ->
- raise (Reporting_basic.err_general Unknown ("Couldn't turn nexp " ^
+ raise (Reporting.err_general Unknown ("Couldn't turn nexp " ^
string_of_nexp nexp ^ " into concrete value"))
in eval ne
@@ -522,10 +526,12 @@ let refine_constructor refinements l env id args =
(* A constructor should always have a single argument. *)
| Typ_aux (Typ_fn ([constr_ty],_,_),_) -> begin
let arg_ty = typ_of_args args in
- match Type_check.destruct_exist env constr_ty with
+ match Type_check.destruct_exist (Type_check.Env.expand_synonyms env constr_ty) with
| None -> None
- | Some (kids,nc,constr_ty) ->
- let (bindings,_,_) = Type_check.unify l env constr_ty arg_ty in
+ | Some (kopts,nc,constr_ty) ->
+ (* TODO: Handle non-integer existentials *)
+ let kids = List.map kopt_kid kopts in
+ let bindings = Type_check.unify l env (tyvars_of_typ constr_ty) constr_ty arg_ty in
let find_kid kid = try Some (KBindings.find kid bindings) with Not_found -> None in
let bindings = List.map find_kid kids in
let matches_refinement (mapping,_,_) =
@@ -533,13 +539,13 @@ let refine_constructor refinements l env id args =
(fun v (_,w) ->
match v,w with
| _,None -> true
- | Some (U_nexp (Nexp_aux (Nexp_constant n, _))),Some m -> Big_int.equal n m
+ | Some (A_aux (A_nexp (Nexp_aux (Nexp_constant n, _)), _)),Some m -> Big_int.equal n m
| _,_ -> false) bindings mapping
in
match List.find matches_refinement irefinements with
| (_,new_id,_) -> Some (E_app (new_id,args))
| exception Not_found ->
- (Reporting_basic.print_err false true l "Monomorphisation"
+ (Reporting.print_err false true l "Monomorphisation"
("Unable to refine constructor " ^ string_of_id id);
None)
end
@@ -615,8 +621,8 @@ let nexp_subst_fns substs =
| E_vector_append (e1,e2) -> re (E_vector_append (s_exp e1,s_exp e2))
| E_list es -> re (E_list (List.map s_exp es))
| E_cons (e1,e2) -> re (E_cons (s_exp e1,s_exp e2))
- | E_record fes -> re (E_record (s_fexps fes))
- | E_record_update (e,fes) -> re (E_record_update (s_exp e, s_fexps fes))
+ | E_record fes -> re (E_record (List.map s_fexp fes))
+ | E_record_update (e,fes) -> re (E_record_update (s_exp e, List.map s_fexp fes))
| E_field (e,id) -> re (E_field (s_exp e,id))
| E_case (e,cases) -> re (E_case (s_exp e, List.map s_pexp cases))
| E_let (lb,e) -> re (E_let (s_letbind lb, s_exp e))
@@ -629,8 +635,6 @@ let nexp_subst_fns substs =
| E_internal_return e -> re (E_internal_return (s_exp e))
| E_throw e -> re (E_throw (s_exp e))
| E_try (e,cases) -> re (E_try (s_exp e, List.map s_pexp cases))
- and s_fexps (FES_aux (FES_Fexps (fes,flag), (l,annot))) =
- FES_aux (FES_Fexps (List.map s_fexp fes, flag), (l,s_tannot annot))
and s_fexp (FE_aux (FE_Fexp (id,e), (l,annot))) =
FE_aux (FE_Fexp (id,s_exp e),(l,s_tannot annot))
and s_pexp = function
@@ -701,42 +705,43 @@ let fabricate_nexp_exist env l typ kids nc typ' =
match kids,nc,Env.expand_synonyms env typ' with
| ([kid],NC_aux (NC_set (kid',i::_),_),
Typ_aux (Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid'',_)),_)]),_))
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid'',_)),_)]),_))
when Kid.compare kid kid' = 0 && Kid.compare kid kid'' = 0 ->
Nexp_aux (Nexp_constant i,Unknown)
| ([kid],NC_aux (NC_true,_),
Typ_aux (Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid'',_)),_)]),_))
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid'',_)),_)]),_))
when Kid.compare kid kid'' = 0 ->
nint 32
| ([kid],NC_aux (NC_set (kid',i::_),_),
Typ_aux (Typ_app (Id_aux (Id "range",_),
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid'',_)),_);
- Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid''',_)),_)]),_))
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid'',_)),_);
+ A_aux (A_nexp (Nexp_aux (Nexp_var kid''',_)),_)]),_))
when Kid.compare kid kid' = 0 && Kid.compare kid kid'' = 0 &&
Kid.compare kid kid''' = 0 ->
Nexp_aux (Nexp_constant i,Unknown)
| ([kid],NC_aux (NC_true,_),
Typ_aux (Typ_app (Id_aux (Id "range",_),
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid'',_)),_);
- Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid''',_)),_)]),_))
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid'',_)),_);
+ A_aux (A_nexp (Nexp_aux (Nexp_var kid''',_)),_)]),_))
when Kid.compare kid kid'' = 0 &&
Kid.compare kid kid''' = 0 ->
nint 32
- | _ -> raise (Reporting_basic.err_general l
+ | _ -> raise (Reporting.err_general l
("Undefined value at unsupported type " ^ string_of_typ typ))
let fabricate_nexp l tannot =
match destruct_tannot tannot with
| None -> nint 32
| Some (env,typ,_) ->
- match Type_check.destruct_exist env typ with
+ match Type_check.destruct_exist (Type_check.Env.expand_synonyms env typ) with
| None -> nint 32
- | Some (kids,nc,typ') -> fabricate_nexp_exist env l typ kids nc typ'
+ (* TODO: check this *)
+ | Some (kopts,nc,typ') -> fabricate_nexp_exist env l typ (List.map kopt_kid kopts) nc typ'
let atom_typ_kid kid = function
| Typ_aux (Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid',_)),_)]),_) ->
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid',_)),_)]),_) ->
Kid.compare kid kid' = 0
| _ -> false
@@ -747,24 +752,24 @@ let atom_typ_kid kid = function
let reduce_cast typ exp l annot =
let env = env_of_annot (l,annot) in
let typ' = Env.base_typ_of env typ in
- match exp, destruct_exist env typ' with
- | E_aux (E_lit (L_aux (L_num n,_)),_), Some ([kid],nc,typ'') when atom_typ_kid kid typ'' ->
- let nc_env = Env.add_typ_var l kid BK_int env in
- let nc_env = Env.add_constraint (nc_eq (nvar kid) (nconstant n)) nc_env in
+ match exp, destruct_exist (Env.expand_synonyms env typ') with
+ | E_aux (E_lit (L_aux (L_num n,_)),_), Some ([kopt],nc,typ'') when atom_typ_kid (kopt_kid kopt) typ'' ->
+ let nc_env = Env.add_typ_var l kopt env in
+ let nc_env = Env.add_constraint (nc_eq (nvar (kopt_kid kopt)) (nconstant n)) nc_env in
if prove nc_env nc
then exp
- else raise (Reporting_basic.err_unreachable l __POS__
+ else raise (Reporting.err_unreachable l __POS__
("Constant propagation error: literal " ^ Big_int.to_string n ^
" does not satisfy constraint " ^ string_of_n_constraint nc))
- | E_aux (E_lit (L_aux (L_undef,_)),_), Some ([kid],nc,typ'') when atom_typ_kid kid typ'' ->
- let nexp = fabricate_nexp_exist env Unknown typ [kid] nc typ'' in
- let newtyp = subst_src_typ (KBindings.singleton kid nexp) typ'' in
+ | E_aux (E_lit (L_aux (L_undef,_)),_), Some ([kopt],nc,typ'') when atom_typ_kid (kopt_kid kopt) typ'' ->
+ let nexp = fabricate_nexp_exist env Unknown typ [kopt_kid kopt] nc typ'' in
+ let newtyp = subst_src_typ (KBindings.singleton (kopt_kid kopt) nexp) typ'' in
E_aux (E_cast (newtyp, exp), (Generated l,replace_typ newtyp annot))
| E_aux (E_cast (_,
(E_aux (E_lit (L_aux (L_undef,_)),_) as exp)),_),
- Some ([kid],nc,typ'') when atom_typ_kid kid typ'' ->
- let nexp = fabricate_nexp_exist env Unknown typ [kid] nc typ'' in
- let newtyp = subst_src_typ (KBindings.singleton kid nexp) typ'' in
+ Some ([kopt],nc,typ'') when atom_typ_kid (kopt_kid kopt) typ'' ->
+ let nexp = fabricate_nexp_exist env Unknown typ [kopt_kid kopt] nc typ'' in
+ let newtyp = subst_src_typ (KBindings.singleton (kopt_kid kopt) nexp) typ'' in
E_aux (E_cast (newtyp, exp), (Generated l,replace_typ newtyp annot))
| _ -> E_aux (E_cast (typ,exp),(l,annot))
@@ -852,7 +857,7 @@ let try_app (l,ann) (id,args) =
E_aux (E_lit L_aux (L_num i,_), _);
E_aux (E_lit L_aux (L_num len,_), _)] ->
(match Env.base_typ_of (env_of_annot annot) (typ_of_annot annot) with
- | Typ_aux (Typ_app (_,[_;Typ_arg_aux (Typ_arg_order ord,_);_]),_) ->
+ | Typ_aux (Typ_app (_,[_;A_aux (A_order ord,_);_]),_) ->
(match slice_lit lit i len ord with
| Some lit' -> Some (E_aux (E_lit lit',(l,ann)))
| None -> None)
@@ -954,7 +959,7 @@ let referenced_vars exp =
{ (compute_exp_alg IdSet.empty IdSet.union) with
e_ref = (fun id -> IdSet.singleton id, E_ref id) } exp)
-let assigned_vars_in_fexps (FES_aux (FES_Fexps (fes,_), _)) =
+let assigned_vars_in_fexps fes =
List.fold_left
(fun vs (FE_aux (FE_Fexp (_,e),_)) -> IdSet.union vs (assigned_vars e))
IdSet.empty
@@ -1154,10 +1159,10 @@ let apply_pat_choices choices =
List.fold_left (fun e (id,e') ->
E_let (LB_aux (LB_val (P_aux (P_id id, dummyannot),e'),dummyannot),E_aux (e,dummyannot))) e subst
| Pat_aux (Pat_when _,(l,_)) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"Pattern acquired a guard after analysis!")
| exception Not_found ->
- raise (Reporting_basic.err_unreachable (exp_loc e) __POS__
+ raise (Reporting.err_unreachable (exp_loc e) __POS__
"Unable to find case I found earlier!"))
| exception Not_found -> E_case (e,cases)
in
@@ -1458,10 +1463,10 @@ let split_defs all_errors splits defs =
| E_internal_plet _
| E_internal_return _
| E_internal_value _
- -> raise (Reporting_basic.err_unreachable l __POS__
+ -> raise (Reporting.err_unreachable l __POS__
("Unexpected expression encountered in monomorphisation: " ^ string_of_exp exp))
- and const_prop_fexps ref_vars substs assigns (FES_aux (FES_Fexps (fes,flag), annot)) =
- FES_aux (FES_Fexps (List.map (const_prop_fexp ref_vars substs assigns) fes, flag), annot)
+ and const_prop_fexps ref_vars substs assigns fes =
+ List.map (const_prop_fexp ref_vars substs assigns) fes
and const_prop_fexp ref_vars substs assigns (FE_aux (FE_Fexp (id,e), annot)) =
FE_aux (FE_Fexp (id,fst (const_prop_exp ref_vars substs assigns e)),annot)
and const_prop_pexp ref_vars substs assigns = function
@@ -1528,7 +1533,7 @@ let split_defs all_errors splits defs =
and can_match_with_env ref_vars env (E_aux (e,(l,annot)) as exp0) cases (substs,ksubsts) assigns =
let rec findpat_generic check_pat description assigns = function
- | [] -> (Reporting_basic.print_err false true l "Monomorphisation"
+ | [] -> (Reporting.print_err false true l "Monomorphisation"
("Failed to find a case for " ^ description); None)
| [Pat_aux (Pat_exp (P_aux (P_wild,_),exp),_)] -> Some (exp,[],[])
| (Pat_aux (Pat_exp (P_aux (P_typ (_,p),_),exp),ann))::tl ->
@@ -1575,7 +1580,7 @@ let split_defs all_errors splits defs =
| P_aux (P_app (id',[]),_) ->
if Id.compare id id' = 0 then DoesMatch ([],[]) else DoesNotMatch
| P_aux (_,(l',_)) ->
- (Reporting_basic.print_err false true l' "Monomorphisation"
+ (Reporting.print_err false true l' "Monomorphisation"
"Unexpected kind of pattern for enumeration"; GiveUp)
in findpat_generic checkpat (string_of_id id) assigns cases
| _ -> None)
@@ -1598,11 +1603,11 @@ let split_defs all_errors splits defs =
DoesMatch ([id, E_aux (E_cast (typ,E_aux (e,(l,empty_tannot))),(l,empty_tannot))],
[kid,nexp])
| _ ->
- (Reporting_basic.print_err false true lit_l "Monomorphisation"
+ (Reporting.print_err false true lit_l "Monomorphisation"
"Unexpected kind of literal for var match"; GiveUp)
end
| P_aux (_,(l',_)) ->
- (Reporting_basic.print_err false true l' "Monomorphisation"
+ (Reporting.print_err false true l' "Monomorphisation"
"Unexpected kind of pattern for literal"; GiveUp)
in findpat_generic checkpat "literal" assigns cases
| E_vector es when List.for_all (function (E_aux (E_lit _,_)) -> true | _ -> false) es ->
@@ -1622,11 +1627,11 @@ let split_defs all_errors splits defs =
| _ -> DoesNotMatch) (DoesMatch ([],[])) matches in
(match final with
| GiveUp ->
- (Reporting_basic.print_err false true l "Monomorphisation"
+ (Reporting.print_err false true l "Monomorphisation"
"Unexpected kind of pattern for vector literal"; GiveUp)
| _ -> final)
| _ ->
- (Reporting_basic.print_err false true l "Monomorphisation"
+ (Reporting.print_err false true l "Monomorphisation"
"Unexpected kind of pattern for vector literal"; GiveUp)
in findpat_generic checkpat "vector literal" assigns cases
@@ -1644,7 +1649,7 @@ let split_defs all_errors splits defs =
DoesMatch ([id, E_aux (E_cast (typ,e_undef),(l,empty_tannot))],
KBindings.bindings ksubst)
| P_aux (_,(l',_)) ->
- (Reporting_basic.print_err false true l' "Monomorphisation"
+ (Reporting.print_err false true l' "Monomorphisation"
"Unexpected kind of pattern for literal"; GiveUp)
in findpat_generic checkpat "literal" assigns cases
| _ -> None
@@ -1670,7 +1675,7 @@ let split_defs all_errors splits defs =
let new_l = Generated l in
let renew_id (Id_aux (id,l)) = Id_aux (id,new_l) in
let cannot msg =
- let open Reporting_basic in
+ let open Reporting in
let error =
Err_general (pat_l,
("Cannot split type " ^ string_of_typ typ ^ " for variable " ^ v ^ ": " ^ msg))
@@ -1700,7 +1705,7 @@ let split_defs all_errors splits defs =
[L_zero; L_one]
| _ -> cannot ("don't know about type " ^ string_of_id id))
- | Typ_app (Id_aux (Id "vector",_), [Typ_arg_aux (Typ_arg_nexp len,_);_;Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]) ->
+ | Typ_app (Id_aux (Id "vector",_), [A_aux (A_nexp len,_);_;A_aux (A_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]) ->
(match len with
| Nexp_aux (Nexp_constant sz,_) ->
let lits = make_vectors (Big_int.to_int sz) in
@@ -1711,7 +1716,7 @@ let split_defs all_errors splits defs =
cannot ("length not constant, " ^ string_of_nexp len)
)
(* set constrained numbers *)
- | Typ_app (Id_aux (Id "atom",_), [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (value,_) as nexp),_)]) ->
+ | Typ_app (Id_aux (Id "atom",_), [A_aux (A_nexp (Nexp_aux (value,_) as nexp),_)]) ->
begin
let mk_lit kid i =
let lit = L_aux (L_num i,new_l) in
@@ -1726,7 +1731,7 @@ let split_defs all_errors splits defs =
let nc = List.fold_left nc_and nc_true ncs in
(match extract_set_nc l kvar nc with
| (is,_) -> List.map (mk_lit (Some kvar)) is
- | exception Reporting_basic.Fatal_error (Reporting_basic.Err_general (_,msg)) -> cannot msg)
+ | exception Reporting.Fatal_error (Reporting.Err_general (_,msg)) -> cannot msg)
| _ -> cannot ("unsupport atom nexp " ^ string_of_nexp nexp)
end
| _ -> cannot ("unsupported type " ^ string_of_typ typ)
@@ -1737,8 +1742,8 @@ let split_defs all_errors splits defs =
let map_locs ls (Defs defs) =
let rec match_l = function
- | Unknown
- | Int _ -> []
+ | Unknown -> []
+ | Unique (_, l) -> match_l l
| Generated l -> [] (* Could do match_l l, but only want to split user-written patterns *)
| Documented (_,l) -> match_l l
| Range (p,q) ->
@@ -1799,10 +1804,10 @@ let split_defs all_errors splits defs =
| P_not p ->
(* todo: not sure that I can't split - but can't figure out how at
* the moment *)
- raise (Reporting_basic.err_general l
+ raise (Reporting.err_general l
("Cannot split on 'not' pattern"))
| P_as (p',id) when id_match id <> None ->
- raise (Reporting_basic.err_general l
+ raise (Reporting.err_general l
("Cannot split " ^ string_of_id id ^ " on 'as' pattern"))
| P_as (p',id) ->
re (fun p -> P_as (p,id)) p'
@@ -1811,7 +1816,7 @@ let split_defs all_errors splits defs =
(match spl p' with
| None -> None
| Some ps ->
- let kids = equal_kids (pat_env_of p') kid in
+ let kids = equal_kids (env_of_pat p') kid in
Some (List.map (fun (p,sub,pchoices,ksub) ->
P_aux (P_var (p,tp),(l,annot)), sub, pchoices,
List.concat
@@ -1846,7 +1851,7 @@ let split_defs all_errors splits defs =
let kid_subst = match orig_typ with
| Typ_aux
(Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp
+ [A_aux (A_nexp
(Nexp_aux (Nexp_var var,_)),_)]),_) ->
[var,nconstant j]
| _ -> []
@@ -1907,7 +1912,7 @@ let split_defs all_errors splits defs =
match args with
| [P_aux (P_var (_, TP_aux (TP_var kid, _)),ann)] -> kid,ann
| _ ->
- raise (Reporting_basic.err_general l
+ raise (Reporting.err_general l
"Pattern match not currently supported by monomorphisation")
in
let map_inst (insts,id',_) =
@@ -1941,7 +1946,7 @@ let split_defs all_errors splits defs =
let overlap = List.exists (fun (v,_) -> List.mem v pvs) lvs in
let () =
if overlap then
- Reporting_basic.print_err false true l "Monomorphisation"
+ Reporting.print_err false true l "Monomorphisation"
"Splitting a singleton pattern is not possible"
in p
in
@@ -1949,7 +1954,7 @@ let split_defs all_errors splits defs =
let check_split_size lst l =
let size = List.length lst in
if size > size_set_limit then
- let open Reporting_basic in
+ let open Reporting in
let error =
Err_general (l, "Case split is too large (" ^ string_of_int size ^
" > limit " ^ string_of_int size_set_limit ^ ")")
@@ -1995,8 +2000,8 @@ let split_defs all_errors splits defs =
| E_vector_append (e1,e2) -> re (E_vector_append (map_exp e1,map_exp e2))
| E_list es -> re (E_list (List.map map_exp es))
| E_cons (e1,e2) -> re (E_cons (map_exp e1,map_exp e2))
- | E_record fes -> re (E_record (map_fexps fes))
- | E_record_update (e,fes) -> re (E_record_update (map_exp e, map_fexps fes))
+ | E_record fes -> re (E_record (List.map map_fexp fes))
+ | E_record_update (e,fes) -> re (E_record_update (map_exp e, List.map map_fexp fes))
| E_field (e,id) -> re (E_field (map_exp e,id))
| E_case (e,cases) -> re (E_case (map_exp e, List.concat (List.map map_pexp cases)))
| E_let (lb,e) -> re (E_let (map_letbind lb, map_exp e))
@@ -2009,8 +2014,6 @@ let split_defs all_errors splits defs =
| E_var (le,e1,e2) -> re (E_var (map_lexp le, map_exp e1, map_exp e2))
| E_internal_plet (p,e1,e2) -> re (E_internal_plet (check_single_pat p, map_exp e1, map_exp e2))
| E_internal_return e -> re (E_internal_return (map_exp e))
- and map_fexps (FES_aux (FES_Fexps (fes,flag), annot)) =
- FES_aux (FES_Fexps (List.map map_fexp fes, flag), annot)
and map_fexp (FE_aux (FE_Fexp (id,e), annot)) =
FE_aux (FE_Fexp (id,map_exp e),annot)
and map_pexp = function
@@ -2100,8 +2103,8 @@ let split_defs all_errors splits defs =
in
let map_scattered_def sd =
match sd with
- | SD_aux (SD_scattered_funcl fcl, annot) ->
- List.map (fun fcl' -> SD_aux (SD_scattered_funcl fcl', annot)) (map_funcl fcl)
+ | SD_aux (SD_funcl fcl, annot) ->
+ List.map (fun fcl' -> SD_aux (SD_funcl fcl', annot)) (map_funcl fcl)
| _ -> [sd]
in
let map_def d =
@@ -2113,6 +2116,7 @@ let split_defs all_errors splits defs =
| DEF_reg_dec _
| DEF_overload _
| DEF_fixity _
+ | DEF_pragma _
| DEF_internal_mutrec _
-> [d]
| DEF_fundef fd -> [DEF_fundef (map_fundef fd)]
@@ -2184,25 +2188,25 @@ let rec sizes_of_typ (Typ_aux (t,l)) =
| Typ_id _
| Typ_var _
-> KidSet.empty
- | Typ_fn _ -> raise (Reporting_basic.err_general l
+ | Typ_fn _ -> raise (Reporting.err_general l
"Function type on expression")
- | Typ_bidir _ -> raise (Reporting_basic.err_general l "Mapping type on expression")
+ | Typ_bidir _ -> raise (Reporting.err_general l "Mapping type on expression")
| Typ_tup typs -> kidset_bigunion (List.map sizes_of_typ typs)
- | Typ_exist (kids,_,typ) ->
- List.fold_left (fun s k -> KidSet.remove k s) (sizes_of_typ typ) kids
+ | Typ_exist (kopts,_,typ) ->
+ List.fold_left (fun s k -> KidSet.remove (kopt_kid k) s) (sizes_of_typ typ) kopts
| Typ_app (Id_aux (Id "vector",_),
- [Typ_arg_aux (Typ_arg_nexp size,_);
- _;Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]) ->
+ [A_aux (A_nexp size,_);
+ _;A_aux (A_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]) ->
KidSet.of_list (size_nvars_nexp size)
| Typ_app (_,tas) ->
kidset_bigunion (List.map sizes_of_typarg tas)
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and sizes_of_typarg (Typ_arg_aux (ta,_)) =
+and sizes_of_typarg (A_aux (ta,_)) =
match ta with
- Typ_arg_nexp _
- | Typ_arg_order _
+ A_nexp _
+ | A_order _
-> KidSet.empty
- | Typ_arg_typ typ -> sizes_of_typ typ
+ | A_typ typ -> sizes_of_typ typ
let sizes_of_annot (l, tannot) =
match destruct_tannot tannot with
@@ -2221,7 +2225,7 @@ let change_parameter_pat i = function
mk_id "==",
E_aux (E_lit lit,annot)), annot) in
P_aux (P_id var, (l,empty_tannot)), ([],[test])
- | P_aux (_,(l,_)) -> raise (Reporting_basic.err_unreachable l __POS__
+ | P_aux (_,(l,_)) -> raise (Reporting.err_unreachable l __POS__
"Expected variable pattern")
(* TODO: make more precise, preferably with a proper free variables function
@@ -2265,33 +2269,33 @@ let replace_with_the_value bound_nexps (E_aux (_,(l,_)) as exp) =
let mk_exp nexp l l' =
let nexp = replace_size nexp in
E_aux (E_cast (wrap (Typ_aux (Typ_app (Id_aux (Id "itself",Generated Unknown),
- [Typ_arg_aux (Typ_arg_nexp nexp,l')]),Generated Unknown)),
+ [A_aux (A_nexp nexp,l')]),Generated Unknown)),
E_aux (E_app (Id_aux (Id "make_the_value",Generated Unknown),[exp]),(Generated l,empty_tannot))),
(Generated l,empty_tannot))
in
match typ with
| Typ_aux (Typ_app (Id_aux (Id "range",_),
- [Typ_arg_aux (Typ_arg_nexp nexp,l');Typ_arg_aux (Typ_arg_nexp nexp',_)]),_)
+ [A_aux (A_nexp nexp,l');A_aux (A_nexp nexp',_)]),_)
when nexp_identical nexp nexp' ->
mk_exp nexp l l'
| Typ_aux (Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp nexp,l')]),_) ->
+ [A_aux (A_nexp nexp,l')]),_) ->
mk_exp nexp l l'
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ | _ -> raise (Reporting.err_unreachable l __POS__
"atom stopped being an atom?")
let replace_type env typ =
let Typ_aux (t,l) = Env.expand_synonyms env typ in
match t with
| Typ_app (Id_aux (Id "range",_),
- [Typ_arg_aux (Typ_arg_nexp nexp,l');Typ_arg_aux (Typ_arg_nexp _,_)]) ->
+ [A_aux (A_nexp nexp,l');A_aux (A_nexp _,_)]) ->
Typ_aux (Typ_app (Id_aux (Id "itself",Generated Unknown),
- [Typ_arg_aux (Typ_arg_nexp nexp,l')]),Generated l)
+ [A_aux (A_nexp nexp,l')]),Generated l)
| Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp nexp,l')]) ->
+ [A_aux (A_nexp nexp,l')]) ->
Typ_aux (Typ_app (Id_aux (Id "itself",Generated Unknown),
- [Typ_arg_aux (Typ_arg_nexp nexp,l')]),Generated l)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ [A_aux (A_nexp nexp,l')]),Generated l)
+ | _ -> raise (Reporting.err_unreachable l __POS__
"atom stopped being an atom?")
@@ -2305,18 +2309,18 @@ let rewrite_size_parameters env (Defs defs) =
let _, typ = Env.get_val_spec_orig id env in
let types = match typ with
| Typ_aux (Typ_fn (arg_typs,_,_),_) -> List.map (Env.expand_synonyms env) arg_typs
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "Function clause does not have a function type")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "Function clause does not have a function type")
in
let add_parameter (i,nmap) typ =
let nmap =
match Env.base_typ_of env typ with
Typ_aux (Typ_app(Id_aux (Id "range",_),
- [Typ_arg_aux (Typ_arg_nexp nexp,_);
- Typ_arg_aux (Typ_arg_nexp nexp',_)]),_)
+ [A_aux (A_nexp nexp,_);
+ A_aux (A_nexp nexp',_)]),_)
when Nexp.compare nexp nexp' = 0 && not (NexpMap.mem nexp nmap) ->
NexpMap.add nexp i nmap
| Typ_aux (Typ_app(Id_aux (Id "atom", _),
- [Typ_arg_aux (Typ_arg_nexp nexp,_)]), _)
+ [A_aux (A_nexp nexp,_)]), _)
when not (NexpMap.mem nexp nmap) ->
NexpMap.add nexp i nmap
| _ -> nmap
@@ -2325,7 +2329,7 @@ let rewrite_size_parameters env (Defs defs) =
let (_,nexp_map) = List.fold_left add_parameter (0,NexpMap.empty) types in
let nexp_list = NexpMap.bindings nexp_map in
(* let () =
- print_endline ("Type of pattern for " ^ string_of_id id ^": " ^string_of_typ (pat_typ_of pat));
+ print_endline ("Type of pattern for " ^ string_of_id id ^": " ^string_of_typ (typ_of_pat pat));
print_endline ("Types : " ^ String.concat ", " (List.map string_of_typ types));
print_endline ("Nexp map for " ^ string_of_id id);
List.iter (fun (nexp, i) -> print_endline (" " ^ string_of_nexp nexp ^ " -> " ^ string_of_int i)) nexp_list
@@ -2334,7 +2338,7 @@ in *)
match destruct_tannot tannot with
| Some (env,typ,_) ->
begin match Env.base_typ_of env typ with
- | Typ_aux (Typ_app (Id_aux (Id "vector",_), [Typ_arg_aux (Typ_arg_nexp size,_);_;_]),_)
+ | Typ_aux (Typ_app (Id_aux (Id "vector",_), [A_aux (A_nexp size,_);_;_]),_)
when not (is_nexp_constant size) ->
begin
match NexpMap.find size nexp_map with
@@ -2602,8 +2606,7 @@ let string_of_lx lx =
let rec simple_string_of_loc = function
| Parse_ast.Unknown -> "Unknown"
- | Parse_ast.Int (s,None) -> "Int(" ^ s ^ ",None)"
- | Parse_ast.Int (s,Some l) -> "Int(" ^ s ^ ",Some("^simple_string_of_loc l^"))"
+ | Parse_ast.Unique (n, l) -> "Unique(" ^ string_of_int n ^ ", " ^ simple_string_of_loc l ^ ")"
| Parse_ast.Generated l -> "Generated(" ^ simple_string_of_loc l ^ ")"
| Parse_ast.Range (lx1,lx2) -> "Range(" ^ string_of_lx lx1 ^ "->" ^ string_of_lx lx2 ^ ")"
| Parse_ast.Documented (_,l) -> "Documented(_," ^ simple_string_of_loc l ^ ")"
@@ -2628,7 +2631,7 @@ let string_of_callerkidset s =
let string_of_dep = function
| Have (args,extras) ->
"Have (" ^ string_of_argsplits args ^ ";" ^ string_of_extra_splits extras ^ ")"
- | Unknown (l,msg) -> "Unknown " ^ msg ^ " at " ^ Reporting_basic.loc_to_string l
+ | Unknown (l,msg) -> "Unknown " ^ msg ^ " at " ^ Reporting.loc_to_string l
(* If a callee uses a type variable as a size, does it need to be split in the
current function, or is it also a parameter? (Note that there may be multiple
@@ -2774,7 +2777,7 @@ let update_env_new_kids env deps typ_env_pre typ_env_post =
let kbound =
KBindings.merge (fun k x y ->
match x,y with
- | Some bk, None -> Some bk
+ | Some k, None -> Some k
| _ -> None)
(Env.get_typ_vars typ_env_post)
(Env.get_typ_vars typ_env_pre)
@@ -2849,14 +2852,16 @@ let rec deps_of_nc kid_deps (NC_aux (nc,l)) =
let deps_of_typ l kid_deps arg_deps typ =
deps_of_tyvars l kid_deps arg_deps (tyvars_of_typ typ)
-let deps_of_uvar l fn_id env arg_deps = function
- | U_nexp (Nexp_aux (Nexp_var kid,_))
+let deps_of_typ_arg l fn_id env arg_deps (A_aux (aux, _)) =
+ match aux with
+ | A_nexp (Nexp_aux (Nexp_var kid,_))
when List.exists (fun k -> Kid.compare kid k == 0) env.top_kids ->
Parents (CallerKidSet.singleton (fn_id,kid))
- | U_nexp nexp -> InFun (deps_of_nexp l env.kid_deps arg_deps nexp)
- | U_order _ -> InFun dempty
- | U_typ typ -> InFun (deps_of_typ l env.kid_deps arg_deps typ)
-
+ | A_nexp nexp -> InFun (deps_of_nexp l env.kid_deps arg_deps nexp)
+ | A_order _ -> InFun dempty
+ | A_typ typ -> InFun (deps_of_typ l env.kid_deps arg_deps typ)
+ | A_bool nc -> InFun (deps_of_nc env.kid_deps nc)
+
let mk_subrange_pattern vannot vstart vend =
let (len,ord,typ) = vector_typ_args_of (Env.base_typ_of (env_of_annot vannot) (typ_of_annot vannot)) in
match ord with
@@ -2871,7 +2876,7 @@ let mk_subrange_pattern vannot vstart vend =
let end_len = Big_int.pred (Big_int.sub len vend) in
(* Wrap pat in its type; in particular the type checker won't
manage P_wild in the middle of a P_vector_concat *)
- let pat = P_aux (P_typ (pat_typ_of pat, pat),(Generated (pat_loc pat),empty_tannot)) in
+ let pat = P_aux (P_typ (typ_of_pat pat, pat),(Generated (pat_loc pat),empty_tannot)) in
let pats = if Big_int.greater end_len Big_int.zero then
[pat;P_aux (P_typ (vector_typ (nconstant end_len) ord typ,
P_aux (P_wild,(dummyl,empty_tannot))),(dummyl,empty_tannot))]
@@ -2902,8 +2907,8 @@ let refine_dependency env (E_aux (e,(l,annot)) as exp) pexps =
with
| Some pats ->
if l = Parse_ast.Unknown then
- (Reporting_basic.print_error
- (Reporting_basic.Err_general
+ (Reporting.print_error
+ (Reporting.Err_general
(l, "No location for pattern match: " ^ string_of_exp exp));
None)
else
@@ -2941,8 +2946,8 @@ let simplify_size_nexp env typ_env (Nexp_aux (ne,l) as nexp) =
| kid -> Nexp_aux (Nexp_var kid,Generated l)
| exception Not_found -> nexp
-let simplify_size_uvar env typ_env = function
- | U_nexp nexp -> U_nexp (simplify_size_nexp env typ_env nexp)
+let simplify_size_typ_arg env typ_env = function
+ | A_aux (A_nexp nexp, l) -> A_aux (A_nexp (simplify_size_nexp env typ_env nexp), l)
| x -> x
(* Takes an environment of dependencies on vars, type vars, and flow control,
@@ -3034,10 +3039,10 @@ let rec analyse_exp fn_id env assigns (E_aux (e,(l,annot)) as exp) =
| _ -> Unknown (l, "Effects from function application")
in
let kid_inst = instantiation_of exp in
- let kid_inst = KBindings.map (simplify_size_uvar env typ_env) kid_inst in
+ let kid_inst = KBindings.map (simplify_size_typ_arg env typ_env) kid_inst in
(* Change kids in instantiation to the canonical ones from the type signature *)
let kid_inst = KBindings.fold (fun kid -> KBindings.add (orig_kid kid)) kid_inst KBindings.empty in
- let kid_deps = KBindings.map (deps_of_uvar l fn_id env deps) kid_inst in
+ let kid_deps = KBindings.map (deps_of_typ_arg l fn_id env deps) kid_inst in
let rdep,r' =
if Id.compare fn_id id == 0 then
let bad = Unknown (l,"Recursive call of " ^ string_of_id id) in
@@ -3087,11 +3092,11 @@ let rec analyse_exp fn_id env assigns (E_aux (e,(l,annot)) as exp) =
| E_vector_update_subrange (e1,e2,e3,e4) ->
let ds, assigns, r = non_det [e1;e2;e3;e4] in
(merge_deps ds, assigns, r)
- | E_record (FES_aux (FES_Fexps (fexps,_),_)) ->
+ | E_record fexps ->
let es = List.map (function (FE_aux (FE_Fexp (_,e),_)) -> e) fexps in
let ds, assigns, r = non_det es in
(merge_deps ds, assigns, r)
- | E_record_update (e,FES_aux (FES_Fexps (fexps,_),_)) ->
+ | E_record_update (e,fexps) ->
let es = List.map (function (FE_aux (FE_Fexp (_,e),_)) -> e) fexps in
let ds, assigns, r = non_det (e::es) in
(merge_deps ds, assigns, r)
@@ -3165,7 +3170,7 @@ let rec analyse_exp fn_id env assigns (E_aux (e,(l,annot)) as exp) =
| E_internal_plet _
| E_internal_return _
| E_internal_value _
- -> raise (Reporting_basic.err_unreachable l __POS__
+ -> raise (Reporting.err_unreachable l __POS__
("Unexpected expression encountered in monomorphisation: " ^ string_of_exp exp))
| E_var (lexp,e1,e2) ->
@@ -3184,13 +3189,13 @@ let rec analyse_exp fn_id env assigns (E_aux (e,(l,annot)) as exp) =
| Some (tenv,typ,_) ->
let typ = Env.base_typ_of tenv typ in
let env, tenv, typ =
- match destruct_exist tenv typ with
+ match destruct_exist (Env.expand_synonyms tenv typ) with
| None -> env, tenv, typ
- | Some (kids, nc, typ) ->
+ | Some (kopts, nc, typ) ->
{ env with kid_deps =
- List.fold_left (fun kds kid -> KBindings.add kid deps kds) env.kid_deps kids },
+ List.fold_left (fun kds kopt -> KBindings.add (kopt_kid kopt) deps kds) env.kid_deps kopts },
Env.add_constraint nc
- (List.fold_left (fun tenv kid -> Env.add_typ_var l kid BK_int tenv) tenv kids),
+ (List.fold_left (fun tenv kopt -> Env.add_typ_var l kopt tenv) tenv kopts),
typ
in
if is_bitvector_typ typ then
@@ -3269,7 +3274,7 @@ let initial_env fn_id fn_l (TypQ_aux (tq,_)) pat body set_assertions =
let env = env_of_annot annot in
let Typ_aux (typ,_) = Env.base_typ_of env (typ_of_annot annot) in
match typ with
- | Typ_app (Id_aux (Id "atom",_),[Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid,_)),_)]) ->
+ | Typ_app (Id_aux (Id "atom",_),[A_aux (A_nexp (Nexp_aux (Nexp_var kid,_)),_)]) ->
equal_kids env kid
| _ -> KidSet.empty
in
@@ -3291,7 +3296,7 @@ let initial_env fn_id fn_l (TypQ_aux (tq,_)) pat body set_assertions =
in
let eqn_instantiations = Type_check.instantiate_simple_equations qs in
let eqn_kid_deps = KBindings.map (function
- | U_nexp nexp -> Some (nexp_frees nexp)
+ | A_aux (A_nexp nexp, _) -> Some (nexp_frees nexp)
| _ -> None) eqn_instantiations
in
let arg i pat =
@@ -3360,7 +3365,7 @@ let initial_env fn_id fn_l (TypQ_aux (tq,_)) pat body set_assertions =
in aux pat
in
let quant = function
- | QI_aux (QI_id (KOpt_aux ((KOpt_none kid | KOpt_kind (_,kid)),_)),_) ->
+ | QI_aux (QI_id (KOpt_aux (KOpt_kind (_,kid),_)),_) ->
Some kid
| QI_aux (QI_const _,_) -> None
in
@@ -3373,7 +3378,7 @@ let initial_env fn_id fn_l (TypQ_aux (tq,_)) pat body set_assertions =
else
(* When there's no argument to case split on for a kid, we'll add a
case expression instead *)
- let env = pat_env_of pat in
+ let env = env_of_pat pat in
let split = default_split (mk_tannot env int_typ no_effect) (KidSet.singleton kid) in
let extra_splits = ExtraSplits.singleton (fn_id, fn_l)
(KBindings.singleton kid split) in
@@ -3500,7 +3505,7 @@ let print_result r =
let _ = print_endline (" kid_in_caller: " ^ string_of_callerkidset r.kid_in_caller) in
let _ = print_endline (" failures: \n " ^
(String.concat "\n "
- (List.map (fun (l,s) -> Reporting_basic.loc_to_string l ^ ":\n " ^
+ (List.map (fun (l,s) -> Reporting.loc_to_string l ^ ":\n " ^
String.concat "\n " (StringSet.elements s))
(Failures.bindings r.failures)))) in
()
@@ -3585,7 +3590,7 @@ let analyse_defs debug env (Defs defs) =
then (true,splits,extras) else
begin
Failures.iter (fun l msgs ->
- Reporting_basic.print_err false false l "Monomorphisation" (String.concat "\n" (StringSet.elements msgs)))
+ Reporting.print_err false false l "Monomorphisation" (String.concat "\n" (StringSet.elements msgs)))
fails;
(false, splits,extras)
end
@@ -3610,7 +3615,7 @@ let add_extra_splits extras (Defs defs) =
let loc = match Analysis.translate_loc l with
| Some l -> l
| None ->
- (Reporting_basic.print_err false false l "Monomorphisation"
+ (Reporting.print_err false false l "Monomorphisation"
"Internal error: bad location for added case";
("",0))
in
@@ -3663,6 +3668,11 @@ let is_constant_vec_typ env typ =
let rewrite_app env typ (id,args) =
let is_append = is_id env (Id "append") in
+ let is_zero_extend =
+ is_id env (Id "Extend") id || is_id env (Id "ZeroExtend") id ||
+ is_id env (Id "zero_extend") id || is_id env (Id "sail_zero_extend") id ||
+ is_id env (Id "mips_zero_extend") id
+ in
let try_cast_to_typ (E_aux (e,_) as exp) =
let (size,order,bittyp) = vector_typ_args_of (Env.base_typ_of env typ) in
match size with
@@ -3819,7 +3829,7 @@ let rewrite_app env typ (id,args) =
[vector1; start1; end1])
| _ -> E_app (id,args)
- else if is_id env (Id "Extend") id || is_id env (Id "ZeroExtend") id || is_id env (Id "zero_extend") id then
+ else if is_zero_extend then
let is_subrange = is_id env (Id "vector_subrange") in
let is_slice = is_id env (Id "slice") in
let is_zeros = is_id env (Id "Zeros") in
@@ -3841,11 +3851,16 @@ let rewrite_app env typ (id,args) =
-> E_app (mk_id "place_slice",
[vector1; start1; length1; length2])
- (* If we've already rewritten to slice_slice_concat, we can just drop the
- zero extension because it can do it *)
- | (E_aux (E_cast (_, (E_aux (E_app (Id_aux (Id "slice_slice_concat",_), args),_))),_))::
+ (* If we've already rewritten to slice_slice_concat or subrange_subrange_concat,
+ we can just drop the zero extension because those functions can do it
+ themselves *)
+ | (E_aux (E_cast (_, (E_aux (E_app (Id_aux ((Id "slice_slice_concat" | Id "subrange_subrange_concat"),_) as op, args),_))),_))::
+ ([] | [_;E_aux (E_id (Id_aux (Id "unsigned",_)),_)])
+ -> E_app (op, args)
+
+ | (E_aux (E_app (Id_aux ((Id "slice_slice_concat" | Id "subrange_subrange_concat"),_) as op, args),_))::
([] | [_;E_aux (E_id (Id_aux (Id "unsigned",_)),_)])
- -> E_app (mk_id "slice_slice_concat", args)
+ -> E_app (op, args)
| [E_aux (E_app (slice1, [vector1; start1; length1]),_)]
when is_slice slice1 && not (is_constant length1) ->
@@ -3948,15 +3963,15 @@ let make_bitvector_cast_fns cast_name env quant_kids src_typ target_typ =
P_aux (P_typ (src_typ, P_aux (P_tup ps,(Generated src_l, src_ann))),(Generated src_l, src_ann)),
E_aux (E_tuple es,(Generated tar_l, tar_ann))
| Typ_app (Id_aux (Id "vector",_),
- [Typ_arg_aux (Typ_arg_nexp size,_); _;
- Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]),
+ [A_aux (A_nexp size,_); _;
+ A_aux (A_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]),
Typ_app (Id_aux (Id "vector",_) as t_id,
- [Typ_arg_aux (Typ_arg_nexp size',l_size'); t_ord;
- Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_) as t_bit]) -> begin
+ [A_aux (A_nexp size',l_size'); t_ord;
+ A_aux (A_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_) as t_bit]) -> begin
match simplify_size_nexp env quant_kids size, simplify_size_nexp env quant_kids size' with
| Some size, Some size' when Nexp.compare size size' <> 0 ->
let var = fresh () in
- let tar_typ' = Typ_aux (Typ_app (t_id, [Typ_arg_aux (Typ_arg_nexp size',l_size');t_ord;t_bit]),
+ let tar_typ' = Typ_aux (Typ_app (t_id, [A_aux (A_nexp size',l_size');t_ord;t_bit]),
tar_l) in
let () = at_least_one := Some tar_typ' in
P_aux (P_id var,(Generated src_l,src_ann)),
@@ -4031,9 +4046,9 @@ let fill_in_type env typ =
let tyvars = tyvars_of_typ typ in
let subst = KidSet.fold (fun kid subst ->
match Env.get_typ_var kid env with
- | BK_type
- | BK_order -> subst
- | BK_int ->
+ | K_type
+ | K_order -> subst
+ | K_int ->
(match solve env (nvar kid) with
| None -> subst
| Some n -> KBindings.add kid (nconstant n) subst)) tyvars KBindings.empty in
@@ -4056,7 +4071,7 @@ let add_bitvector_casts (Defs defs) =
let matched_typ = Env.base_typ_of env (typ_of_annot ann') in
match e',matched_typ with
| E_sizeof (Nexp_aux (Nexp_var kid,_)), _
- | _, Typ_aux (Typ_app (Id_aux (Id "atom",_), [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid,_)),_)]),_) ->
+ | _, Typ_aux (Typ_app (Id_aux (Id "atom",_), [A_aux (A_nexp (Nexp_aux (Nexp_var kid,_)),_)]),_) ->
let map_case pexp =
let pat,guard,body,ann = destruct_pexp pexp in
let body = match pat, guard with
@@ -4134,7 +4149,7 @@ let add_bitvector_casts (Defs defs) =
match typ with
| Typ_aux (Typ_fn (_,ret,_),_) -> ret
| Typ_aux (_,l) as typ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
("Function clause must have function type: " ^ string_of_typ typ ^
" is not a function type"))
in
@@ -4180,16 +4195,16 @@ let replace_nexp_in_typ env typ orig new_nexp =
let fs, targs = List.split (List.map aux_targ targs) in
List.exists (fun x -> x) fs, Typ_aux (Typ_app (id, targs),l)
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
- and aux_targ (Typ_arg_aux (ta,l) as typ_arg) =
+ and aux_targ (A_aux (ta,l) as typ_arg) =
match ta with
- | Typ_arg_nexp nexp ->
+ | A_nexp nexp ->
if prove env (nc_eq nexp orig)
- then true, Typ_arg_aux (Typ_arg_nexp new_nexp,l)
+ then true, A_aux (A_nexp new_nexp,l)
else false, typ_arg
- | Typ_arg_typ typ ->
+ | A_typ typ ->
let f, typ = aux typ in
- f, Typ_arg_aux (Typ_arg_typ typ,l)
- | Typ_arg_order _ -> false, typ_arg
+ f, A_aux (A_typ typ,l)
+ | A_order _ -> false, typ_arg
in aux typ
let fresh_nexp_kid nexp =
@@ -4266,7 +4281,7 @@ let rewrite_toplevel_nexps (Defs defs) =
match nexp_map with
| [] -> None
| _ ->
- let new_vars = List.map (fun (kid,nexp) -> QI_aux (QI_id (KOpt_aux (KOpt_none kid,Generated Unknown)), Generated tq_l)) nexp_map in
+ let new_vars = List.map (fun (kid,nexp) -> QI_aux (QI_id (mk_kopt K_int kid), Generated tq_l)) nexp_map in
let new_constraints = List.map (fun (kid,nexp) -> QI_aux (QI_const (nc_eq (nvar kid) nexp), Generated tq_l)) nexp_map in
let tqs = TypQ_aux (TypQ_tq (qs @ new_vars @ new_constraints),tq_l) in
let vs =
@@ -4281,13 +4296,13 @@ let rewrite_toplevel_nexps (Defs defs) =
Typ_aux (Typ_exist (kids,(* TODO? *) nc, aux typ'),l)
| Typ_app (id,targs) -> Typ_aux (Typ_app (id,List.map aux_targ targs),l)
| _ -> typ_full
- and aux_targ (Typ_arg_aux (ta,l) as ta_full) =
+ and aux_targ (A_aux (ta,l) as ta_full) =
match ta with
- | Typ_arg_typ typ -> Typ_arg_aux (Typ_arg_typ (aux typ),l)
- | Typ_arg_order _ -> ta_full
- | Typ_arg_nexp nexp ->
+ | A_typ typ -> A_aux (A_typ (aux typ),l)
+ | A_order _ -> ta_full
+ | A_nexp nexp ->
match find_nexp env nexp_map nexp with
- | (kid,_) -> Typ_arg_aux (Typ_arg_nexp (nvar kid),l)
+ | (kid,_) -> A_aux (A_nexp (nvar kid),l)
| exception Not_found -> ta_full
in aux typ
in
@@ -4356,19 +4371,19 @@ let monomorphise opts splits defs =
let f,r,ex = Analysis.analyse_defs opts.debug_analysis env defs in
if f || opts.all_split_errors || opts.continue_anyway
then f, r, ex
- else raise (Reporting_basic.err_general Unknown "Unable to monomorphise program")
+ else raise (Reporting.err_general Unknown "Unable to monomorphise program")
else true, [], Analysis.ExtraSplits.empty in
let splits = new_splits @ (List.map (fun (loc,id) -> (loc,id,None)) splits) in
let ok_extras, defs, extra_splits = add_extra_splits extra_splits defs in
let splits = splits @ extra_splits in
let () = if ok_extras || opts.all_split_errors || opts.continue_anyway
then ()
- else raise (Reporting_basic.err_general Unknown "Unable to monomorphise program")
+ else raise (Reporting.err_general Unknown "Unable to monomorphise program")
in
let ok_split, defs = split_defs opts.all_split_errors splits defs in
let () = if (ok_analysis && ok_extras && ok_split) || opts.continue_anyway
then ()
- else raise (Reporting_basic.err_general Unknown "Unable to monomorphise program")
+ else raise (Reporting.err_general Unknown "Unable to monomorphise program")
in defs
let add_bitvector_casts = BitvectorSizeCasts.add_bitvector_casts
diff --git a/src/nl_flow.ml b/src/nl_flow.ml
new file mode 100644
index 00000000..e38e5fa5
--- /dev/null
+++ b/src/nl_flow.ml
@@ -0,0 +1,118 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast
+open Ast_util
+
+let opt_nl_flow = ref false
+
+let rec escapes (E_aux (aux, _)) =
+ match aux with
+ | E_throw _ -> true
+ | E_block [] -> false
+ | E_block exps -> escapes (List.hd (List.rev exps))
+ | _ -> false
+
+let is_bitvector_literal (L_aux (aux, _)) =
+ match aux with
+ | L_bin _ | L_hex _ -> true
+ | _ -> false
+
+let bitvector_unsigned (L_aux (aux, _)) =
+ let open Sail_lib in
+ match aux with
+ | L_bin str -> uint (List.map bin_char (Util.string_to_list str))
+ | L_hex str -> uint (bits_of_string str)
+ | _ -> assert false
+
+let rec pat_id (P_aux (aux, _)) =
+ match aux with
+ | P_id id -> Some id
+ | P_as (_, id) -> Some id
+ | P_var (pat, _) -> pat_id pat
+ | _ -> None
+
+let add_assert cond (E_aux (aux, (l, ())) as exp) =
+ let msg = mk_lit_exp (L_string "") in
+ let assertion = locate (fun _ -> gen_loc l) (mk_exp (E_assert (cond, msg))) in
+ match aux with
+ | E_block exps -> E_aux (E_block (assertion :: exps), (l, ()))
+ | _ -> E_aux (E_block (assertion :: [exp]), (l, ()))
+
+(* If we know that x != bitv, then after any let y = unsigned(x) we
+ will also know that y != unsigned(bitv) *)
+let modify_unsigned id value (E_aux (aux, annot) as exp) =
+ match aux with
+ | E_let (LB_aux (LB_val (pat, E_aux (E_app (f, [E_aux (E_id id', _)]), _)), _) as lb, exp')
+ when string_of_id f = "unsigned" && Id.compare id id' = 0 ->
+ begin match pat_id pat with
+ | None -> exp
+ | Some uid ->
+ E_aux (E_let (lb,
+ add_assert (mk_exp (E_app_infix (mk_exp (E_id uid), mk_id "!=", mk_lit_exp (L_num value)))) exp'),
+ annot)
+ end
+ | _ -> exp
+
+let analyze' exps =
+ match exps with
+ | E_aux (E_if (cond, then_exp, _), _) :: rest when escapes then_exp ->
+ begin match cond with
+ | E_aux (E_app_infix (E_aux (E_id id, _), op, E_aux (E_lit lit, _)), _)
+ | E_aux (E_app_infix (E_aux (E_lit lit, _), op, E_aux (E_id id, _)), _)
+ when string_of_id op = "==" && is_bitvector_literal lit ->
+ let value = bitvector_unsigned lit in
+ List.map (modify_unsigned id value) exps
+ | _ -> exps
+ end
+ | _ -> exps
+
+let analyze exps =
+ if !opt_nl_flow then analyze' exps else exps
diff --git a/src/nl_flow.mli b/src/nl_flow.mli
new file mode 100644
index 00000000..f2bf0035
--- /dev/null
+++ b/src/nl_flow.mli
@@ -0,0 +1,60 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast
+
+(** [opt_nl_flow] must be true for [analyze] to do anything. *)
+val opt_nl_flow : bool ref
+
+(** Analyze a basic block for flow typing properties that do not
+ follow the lexical structure of the code (and therefore the
+ syntax-directed typing rules), and insert assertions for discovered
+ constraints *)
+val analyze : unit exp list -> unit exp list
diff --git a/src/ocaml_backend.ml b/src/ocaml_backend.ml
index 2a1fae15..09be449d 100644
--- a/src/ocaml_backend.ml
+++ b/src/ocaml_backend.ml
@@ -103,10 +103,10 @@ let rec ocaml_string_typ (Typ_aux (typ_aux, l)) arg =
| Typ_id id when string_of_id id = "exception" -> string "Printexc.to_string" ^^ space ^^ arg
| Typ_id id -> ocaml_string_of id ^^ space ^^ arg
| Typ_app (id, []) -> ocaml_string_of id ^^ space ^^ arg
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id eid, _)), _)])
+ | Typ_app (id, [A_aux (A_typ (Typ_aux (Typ_id eid, _)), _)])
when string_of_id id = "list" && string_of_id eid = "bit" ->
string "string_of_bits" ^^ space ^^ arg
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ typ, _)]) when string_of_id id = "list" ->
+ | Typ_app (id, [A_aux (A_typ typ, _)]) when string_of_id id = "list" ->
let farg = gensym () in
separate space [string "string_of_list \", \""; parens (separate space [string "fun"; farg; string "->"; ocaml_string_typ typ farg]); arg]
| Typ_app (_, _) -> string "\"APP\""
@@ -121,7 +121,7 @@ let rec ocaml_string_typ (Typ_aux (typ_aux, l)) arg =
| Typ_bidir (t1, t2) -> string "\"BIDIR\""
| Typ_var kid -> string "\"VAR\""
| Typ_exist _ -> assert false
- | Typ_internal_unknown -> raise (Reporting_basic.err_unreachable l __POS__ "escaped Typ_internal_unknown")
+ | Typ_internal_unknown -> raise (Reporting.err_unreachable l __POS__ "escaped Typ_internal_unknown")
let ocaml_typ_id ctx = function
| id when Id.compare id (mk_id "string") = 0 -> string "string"
@@ -143,13 +143,13 @@ let rec ocaml_typ ctx (Typ_aux (typ_aux, l)) =
| Typ_app (id, typs) -> parens (separate_map (string ", ") (ocaml_typ_arg ctx) typs) ^^ space ^^ ocaml_typ_id ctx id
| Typ_tup typs -> parens (separate_map (string " * ") (ocaml_typ ctx) typs)
| Typ_fn (typs, typ, _) -> separate space [ocaml_typ ctx (Typ_aux (Typ_tup typs, l)); string "->"; ocaml_typ ctx typ]
- | Typ_bidir (t1, t2) -> raise (Reporting_basic.err_general l "Ocaml doesn't support bidir types")
+ | Typ_bidir (t1, t2) -> raise (Reporting.err_general l "Ocaml doesn't support bidir types")
| Typ_var kid -> zencode_kid kid
| Typ_exist _ -> assert false
- | Typ_internal_unknown -> raise (Reporting_basic.err_unreachable l __POS__ "escaped Typ_internal_unknown")
-and ocaml_typ_arg ctx (Typ_arg_aux (typ_arg_aux, _) as typ_arg) =
+ | Typ_internal_unknown -> raise (Reporting.err_unreachable l __POS__ "escaped Typ_internal_unknown")
+and ocaml_typ_arg ctx (A_aux (typ_arg_aux, _) as typ_arg) =
match typ_arg_aux with
- | Typ_arg_typ typ -> ocaml_typ ctx typ
+ | A_typ typ -> ocaml_typ ctx typ
| _ -> failwith ("OCaml: unexpected type argument " ^ string_of_typ_arg typ_arg)
let ocaml_typquant typq =
@@ -187,7 +187,7 @@ let rec ocaml_pat ctx (P_aux (pat_aux, _) as pat) =
match pat_aux with
| P_id id ->
begin
- match Env.lookup_id id (pat_env_of pat) with
+ match Env.lookup_id id (env_of_pat pat) with
| Local (_, _) | Unbound -> zencode ctx id
| Enum _ -> zencode_upper ctx id
| _ -> failwith ("Ocaml: Cannot pattern match on register: " ^ string_of_pat pat)
@@ -242,9 +242,9 @@ let rec ocaml_exp ctx (E_aux (exp_aux, _) as exp) =
| E_if (c, t, e) -> separate space [string "if"; ocaml_atomic_exp ctx c;
string "then"; ocaml_atomic_exp ctx t;
string "else"; ocaml_atomic_exp ctx e]
- | E_record (FES_aux (FES_Fexps (fexps, _), _)) ->
+ | E_record fexps ->
enclose lbrace rbrace (group (separate_map (semi ^^ break 1) (ocaml_fexp ctx) fexps))
- | E_record_update (exp, FES_aux (FES_Fexps (fexps, _), _)) ->
+ | E_record_update (exp, fexps) ->
enclose lbrace rbrace (separate space [ocaml_atomic_exp ctx exp;
string "with";
separate_map (semi ^^ space) (ocaml_fexp ctx) fexps])
@@ -359,10 +359,10 @@ and ocaml_assignment ctx (LEXP_aux (lexp_aux, _) as lexp) exp =
else ocaml_atomic_exp ctx exp
in
separate space [zencode ctx id; string ":="; traced_exp]
- | _ -> separate space [zencode ctx id; string ":="; ocaml_exp ctx exp]
+ | _ -> separate space [zencode ctx id; string ":="; parens (ocaml_exp ctx exp)]
end
| LEXP_deref ref_exp ->
- separate space [ocaml_atomic_exp ctx ref_exp; string ":="; ocaml_exp ctx exp]
+ separate space [ocaml_atomic_exp ctx ref_exp; string ":="; parens (ocaml_exp ctx exp)]
| _ -> string ("LEXP<" ^ string_of_lexp lexp ^ ">")
and ocaml_lexp ctx (LEXP_aux (lexp_aux, _) as lexp) =
match lexp_aux with
@@ -608,7 +608,7 @@ let ocaml_typedef ctx (TD_aux (td_aux, _)) =
^//^ (bar ^^ space ^^ ocaml_enum ctx ids))
^^ ocaml_def_end
^^ ocaml_string_of_enum ctx id ids
- | TD_abbrev (id, _, TypSchm_aux (TypSchm_ts (typq, typ), _)) ->
+ | TD_abbrev (id, typq, A_aux (A_typ typ, _)) ->
separate space [string "type"; ocaml_typquant typq; zencode ctx id; equals; ocaml_typ ctx typ]
^^ ocaml_def_end
^^ ocaml_string_of_abbrev ctx id typq typ
@@ -680,7 +680,7 @@ let ocaml_pp_generators ctx defs orig_types required =
if Bindings.mem id Type_check.Env.builtin_typs
then IdSet.add id required
else
- raise (Reporting_basic.err_unreachable (id_loc id) __POS__
+ raise (Reporting.err_unreachable (id_loc id) __POS__
("Required generator of unknown type " ^ string_of_id id))
and add_req_from_id required id =
if IdSet.mem id required then required
@@ -693,26 +693,26 @@ let ocaml_pp_generators ctx defs orig_types required =
| Typ_internal_unknown
| Typ_fn _
| Typ_bidir _
- -> raise (Reporting_basic.err_unreachable (typ_loc full_typ) __POS__
+ -> raise (Reporting.err_unreachable (typ_loc full_typ) __POS__
("Required generator for type that should not appear: " ^
string_of_typ full_typ))
| Typ_tup typs ->
List.fold_left add_req_from_typ required typs
| Typ_exist _ ->
- raise (Reporting_basic.err_todo (typ_loc full_typ)
+ raise (Reporting.err_todo (typ_loc full_typ)
("Generators for existential types not yet supported: " ^
string_of_typ full_typ))
| Typ_app (id,args) ->
List.fold_left add_req_from_typarg (add_req_from_id required id) args
- and add_req_from_typarg required (Typ_arg_aux (arg,_)) =
+ and add_req_from_typarg required (A_aux (arg,_)) =
match arg with
- | Typ_arg_typ typ -> add_req_from_typ required typ
- | Typ_arg_nexp _
- | Typ_arg_order _
+ | A_typ typ -> add_req_from_typ required typ
+ | A_nexp _
+ | A_order _
-> required
and add_req_from_td required (TD_aux (td,(l,_))) =
match td with
- | TD_abbrev (_, _, TypSchm_aux (TypSchm_ts (_,typ),_)) ->
+ | TD_abbrev (_, _, A_aux (A_typ typ, _)) ->
add_req_from_typ required typ
| TD_record (_, _, _, fields, _) ->
List.fold_left (fun req (typ,_) -> add_req_from_typ req typ) required fields
@@ -720,7 +720,7 @@ let ocaml_pp_generators ctx defs orig_types required =
List.fold_left (fun req (Tu_aux (Tu_ty_id (typ,_),_)) ->
add_req_from_typ req typ) required variants
| TD_enum _ -> required
- | TD_bitfield _ -> raise (Reporting_basic.err_todo l "Generators for bitfields not yet supported")
+ | TD_bitfield _ -> raise (Reporting.err_todo l "Generators for bitfields not yet supported")
in
let required = IdSet.fold (fun id req -> always_add_req_from_id req id) required required in
let type_name id = zencode_string (string_of_id id) in
@@ -729,10 +729,11 @@ let ocaml_pp_generators ctx defs orig_types required =
match Bindings.find id typemap with
| TD_aux (td,_) ->
(match td with
- | TD_abbrev (_,_,TypSchm_aux (TypSchm_ts (tqs,typ),_)) -> tqs
+ | TD_abbrev (_,tqs,A_aux (A_typ _, _)) -> tqs
| TD_record (_,_,tqs,_,_) -> tqs
| TD_variant (_,_,tqs,_,_) -> tqs
| TD_enum _ -> TypQ_aux (TypQ_no_forall,Unknown)
+ | TD_abbrev (_, _, _) -> assert false
| TD_bitfield _ -> assert false)
| exception Not_found ->
Bindings.find id Type_check.Env.builtin_typs
@@ -748,10 +749,10 @@ let ocaml_pp_generators ctx defs orig_types required =
let name = "gen_" ^ type_name id in
let make_tyarg kindedid =
if is_nat_kopt kindedid
- then mk_typ_arg (Typ_arg_nexp (nvar (kopt_kid kindedid)))
+ then mk_typ_arg (A_nexp (nvar (kopt_kid kindedid)))
else if is_order_kopt kindedid
- then mk_typ_arg (Typ_arg_order (mk_ord (Ord_var (kopt_kid kindedid))))
- else mk_typ_arg (Typ_arg_typ (mk_typ (Typ_var (kopt_kid kindedid))))
+ then mk_typ_arg (A_order (mk_ord (Ord_var (kopt_kid kindedid))))
+ else mk_typ_arg (A_typ (mk_typ (Typ_var (kopt_kid kindedid))))
in
let targs = List.map make_tyarg tquants in
let gen_tyvars_pp, out_typ = match gen_tyvars with
@@ -776,34 +777,34 @@ let ocaml_pp_generators ctx defs orig_types required =
let typ_str, args_pp = match typ with
| Typ_id id -> type_name id, [string "g"]
| Typ_app (id,args) -> type_name id, string "g"::List.map typearg args
- | _ -> raise (Reporting_basic.err_todo l
+ | _ -> raise (Reporting.err_todo l
("Unsupported type for generators: " ^ string_of_typ full_typ))
in
let args_pp = match args_pp with [] -> empty
| _ -> space ^^ separate space args_pp
in
string ("g.gen_" ^ typ_str) ^^ args_pp
- and typearg (Typ_arg_aux (arg,_)) =
+ and typearg (A_aux (arg,_)) =
match arg with
- | Typ_arg_nexp (Nexp_aux (nexp,l) as full_nexp) ->
+ | A_nexp (Nexp_aux (nexp,l) as full_nexp) ->
(match nexp with
| Nexp_constant c -> string (Big_int.to_string c) (* TODO: overflow *)
| Nexp_var v -> mk_arg v
- | _ -> raise (Reporting_basic.err_todo l
+ | _ -> raise (Reporting.err_todo l
("Unsupported nexp for generators: " ^ string_of_nexp full_nexp)))
- | Typ_arg_order (Ord_aux (ord,_)) ->
+ | A_order (Ord_aux (ord,_)) ->
(match ord with
| Ord_var v -> mk_arg v
| Ord_inc -> string "true"
| Ord_dec -> string "false")
- | Typ_arg_typ typ -> parens (string "fun g -> " ^^ gen_type typ)
+ | A_typ typ -> parens (string "fun g -> " ^^ gen_type typ)
in
let make_subgen (Typ_aux (typ,l) as full_typ) =
let typ_str, args_pp =
match typ with
| Typ_id id -> type_name id, []
| Typ_app (id,args) -> type_name id, List.map typearg args
- | _ -> raise (Reporting_basic.err_todo l
+ | _ -> raise (Reporting.err_todo l
("Unsupported type for generators: " ^ string_of_typ full_typ))
in
let args_pp = match args_pp with [] -> empty
@@ -836,6 +837,9 @@ let ocaml_pp_generators ctx defs orig_types required =
separate space [bar; dquotes (string (string_of_id id)); string "->";
zencode_upper ctx id]
in
+ let rand_field (typ,id) =
+ zencode ctx id ^^ space ^^ equals ^^ space ^^ make_subgen typ
+ in
let make_args tqs =
string "g" ^^
match quant_kopts tqs with
@@ -847,7 +851,7 @@ let ocaml_pp_generators ctx defs orig_types required =
let tqs, body, constructors, builders =
let TD_aux (td,(l,_)) = Bindings.find id typemap in
match td with
- | TD_abbrev (_,_,TypSchm_aux (TypSchm_ts (tqs,typ),_)) ->
+ | TD_abbrev (_,tqs,A_aux (A_typ typ, _)) ->
tqs, gen_type typ, None, None
| TD_variant (_,_,tqs,variants,_) ->
tqs,
@@ -865,8 +869,10 @@ let ocaml_pp_generators ctx defs orig_types required =
string "]",
Some (separate_map (string ";" ^^ break 1) enum_constructor variants),
Some (separate_map (break 1) build_enum_constructor variants)
+ | TD_record (_,_,tqs,fields,_) ->
+ tqs, braces (separate_map (string ";" ^^ break 1) rand_field fields), None, None
| _ ->
- raise (Reporting_basic.err_todo l "Generators for records and bitfields not yet supported")
+ raise (Reporting.err_todo l "Generators for bitfields not yet supported")
in
let name = type_name id in
let constructors_pp = match constructors with
@@ -939,7 +945,7 @@ let ocaml_main spec sail_dir =
@ [ " zinitializze_registers ();";
if !opt_trace_ocaml then " Sail_lib.opt_trace := true;" else " ();";
" Printexc.record_backtrace true;";
- " try zmain () with _ -> prerr_endline(\"Exiting due to uncaught exception\")\n";])
+ " try zmain () with exn -> prerr_endline(\"Exiting due to uncaught exception:\\n\" ^ Printexc.to_string exn)\n";])
|> String.concat "\n"
let ocaml_pp_defs f defs generator_types =
@@ -978,7 +984,7 @@ let ocaml_compile spec defs generator_types =
let tags_file = if !opt_ocaml_coverage then "_tags_coverage" else "_tags" in
let _ = Unix.system ("cp -r " ^ sail_dir ^ "/lib/" ^ tags_file ^ " _tags") in
let out_chan = open_out (spec ^ ".ml") in
- if !opt_ocaml_coverage then
+ if !opt_ocaml_coverage then
ignore(Unix.system ("cp -r " ^ sail_dir ^ "/lib/myocamlbuild_coverage.ml myocamlbuild.ml"));
ocaml_pp_defs out_chan defs generator_types;
close_out out_chan;
diff --git a/src/parse_ast.ml b/src/parse_ast.ml
index db8f9939..f3bb28db 100644
--- a/src/parse_ast.ml
+++ b/src/parse_ast.ml
@@ -56,7 +56,7 @@ type text = string
type l =
| Unknown
- | Int of string * l option
+ | Unique of int * l
| Generated of l
| Range of Lexing.position * Lexing.position
| Documented of string * l
@@ -70,15 +70,16 @@ type x = text (* identifier *)
type ix = text (* infix identifier *)
type
-base_kind_aux = (* base kind *)
- BK_type (* kind of types *)
- | BK_int (* kind of natural number size expressions *)
- | BK_order (* kind of vector order specifications *)
+kind_aux = (* base kind *)
+ K_type (* kind of types *)
+ | K_int (* kind of natural number size expressions *)
+ | K_order (* kind of vector order specifications *)
+ | K_bool (* kind of constraints *)
type
-base_kind =
- BK_aux of base_kind_aux * l
+kind =
+ K_aux of kind_aux * l
type
@@ -110,13 +111,7 @@ id_aux = (* Identifier *)
Id of x
| DeIid of x (* remove infix status *)
-
-type
-kind_aux = (* kinds *)
- K_kind of (base_kind) list
-
-
-type
+type
base_effect =
BE_aux of base_effect_aux * l
@@ -128,19 +123,32 @@ kid =
type
id =
- Id_aux of id_aux * l
+ Id_aux of id_aux * l
+type
+lit_aux = (* Literal constant *)
+ L_unit (* $() : _$ *)
+ | L_zero (* $_ : _$ *)
+ | L_one (* $_ : _$ *)
+ | L_true (* $_ : _$ *)
+ | L_false (* $_ : _$ *)
+ | L_num of Big_int.num (* natural number constant *)
+ | L_hex of string (* bit vector constant, C-style *)
+ | L_bin of string (* bit vector constant, C-style *)
+ | L_undef (* undefined value *)
+ | L_string of string (* string constant *)
+ | L_real of string
-type
-kind =
- K_aux of kind_aux * l
-
+type
+lit =
+ L_aux of lit_aux * l
-type
+type
atyp_aux = (* expressions of all kinds, to be translated to types, nats, orders, and effects after parsing *)
ATyp_id of id (* identifier *)
| ATyp_var of kid (* ticked variable *)
- | ATyp_constant of Big_int.num (* constant *)
+ | ATyp_lit of lit (* literal *)
+ | ATyp_nset of kid * (Big_int.num) list (* set type *)
| ATyp_times of atyp * atyp (* product *)
| ATyp_sum of atyp * atyp (* sum *)
| ATyp_minus of atyp * atyp (* subtraction *)
@@ -155,7 +163,8 @@ atyp_aux = (* expressions of all kinds, to be translated to types, nats, orders
| ATyp_wild
| ATyp_tup of (atyp) list (* Tuple type *)
| ATyp_app of id * (atyp) list (* type constructor application *)
- | ATyp_exist of kid list * n_constraint * atyp
+ | ATyp_exist of kinded_id list * atyp * atyp
+ | ATyp_base of id * atyp * atyp
and atyp =
ATyp_aux of atyp_aux * l
@@ -166,32 +175,14 @@ kinded_id_aux = (* optionally kind-annotated identifier *)
KOpt_none of kid (* identifier *)
| KOpt_kind of kind * kid (* kind-annotated variable *)
-
-and
-n_constraint_aux = (* constraint over kind $_$ *)
- NC_equal of atyp * atyp
- | NC_bounded_ge of atyp * atyp
- | NC_bounded_le of atyp * atyp
- | NC_not_equal of atyp * atyp
- | NC_set of kid * (Big_int.num) list
- | NC_or of n_constraint * n_constraint
- | NC_and of n_constraint * n_constraint
- | NC_app of id * atyp list
- | NC_true
- | NC_false
-
and
-n_constraint =
- NC_aux of n_constraint_aux * l
-
-type
kinded_id =
KOpt_aux of kinded_id_aux * l
type
quant_item_aux = (* Either a kinded identifier or a nexp constraint for a typquant *)
QI_id of kinded_id (* An optionally kinded identifier *)
- | QI_const of n_constraint (* A constraint for this type *)
+ | QI_const of atyp (* A constraint for this type *)
type
@@ -209,32 +200,12 @@ type
typquant =
TypQ_aux of typquant_aux * l
-
-type
-lit_aux = (* Literal constant *)
- L_unit (* $() : _$ *)
- | L_zero (* $_ : _$ *)
- | L_one (* $_ : _$ *)
- | L_true (* $_ : _$ *)
- | L_false (* $_ : _$ *)
- | L_num of Big_int.num (* natural number constant *)
- | L_hex of string (* bit vector constant, C-style *)
- | L_bin of string (* bit vector constant, C-style *)
- | L_undef (* undefined value *)
- | L_string of string (* string constant *)
- | L_real of string
-
-type
+type
typschm_aux = (* type scheme *)
TypSchm_ts of typquant * atyp
type
-lit =
- L_aux of lit_aux * l
-
-
-type
typschm =
TypSchm_aux of typschm_aux * l
@@ -297,7 +268,7 @@ exp_aux = (* Expression *)
| E_let of letbind * exp (* let expression *)
| E_assign of exp * exp (* imperative assignment *)
| E_sizeof of atyp
- | E_constraint of n_constraint
+ | E_constraint of atyp
| E_exit of exp
| E_throw of exp
| E_try of exp * pexp list
@@ -314,12 +285,6 @@ and fexp_aux = (* Field-expression *)
and fexp =
FE_aux of fexp_aux * l
-and fexps_aux = (* Field-expression list *)
- FES_Fexps of (fexp) list * bool
-
-and fexps =
- FES_aux of fexps_aux * l
-
and opt_default_aux = (* Optional default value for indexed vectors, to define a defualt value for any unspecified positions in a sparse map *)
Def_val_empty
| Def_val_dec of exp
@@ -365,6 +330,7 @@ type
rec_opt_aux = (* Optional recursive annotation for functions *)
Rec_nonrec (* non-recursive *)
| Rec_rec (* recursive *)
+ | Rec_measure of pat * exp (* recursive with termination measure *)
type
@@ -425,7 +391,7 @@ name_scm_opt =
type
default_typing_spec_aux = (* Default kinding or typing assumption, and default order for literal vectors and vector shorthands *)
- DT_order of base_kind * atyp
+ DT_order of kind * atyp
type mpat_aux = (* Mapping pattern. Mostly the same as normal patterns but only constructible parts *)
@@ -480,7 +446,7 @@ fundef_aux = (* Function definition *)
type
type_def_aux = (* Type definition body *)
- TD_abbrev of id * name_scm_opt * typschm (* type abbreviation *)
+ TD_abbrev of id * typquant * kind * atyp (* type abbreviation *)
| TD_record of id * name_scm_opt * typquant * ((atyp * id)) list * bool (* struct type definition *)
| TD_variant of id * name_scm_opt * typquant * (type_union) list * bool (* union type definition *)
| TD_enum of id * name_scm_opt * (id) list * bool (* enumeration type definition *)
@@ -493,7 +459,7 @@ val_spec_aux = (* Value type specification *)
type
kind_def_aux = (* Definition body for elements of kind; many are shorthands for type\_defs *)
- KD_abbrev of kind * id * name_scm_opt * typschm (* type abbreviation *)
+ KD_nabbrev of kind * id * name_scm_opt * atyp (* type abbreviation *)
type
dec_spec_aux = (* Register declarations *)
@@ -506,13 +472,13 @@ dec_spec_aux = (* Register declarations *)
type
scattered_def_aux = (* Function and type union definitions that can be spread across
a file. Each one must end in $_$ *)
- SD_scattered_function of rec_opt * tannot_opt * effect_opt * id (* scattered function definition header *)
- | SD_scattered_funcl of funcl (* scattered function definition clause *)
- | SD_scattered_variant of id * name_scm_opt * typquant (* scattered union definition header *)
- | SD_scattered_unioncl of id * type_union (* scattered union definition member *)
- | SD_scattered_mapping of id * tannot_opt
- | SD_scattered_mapcl of id * mapcl
- | SD_scattered_end of id (* scattered definition end *)
+ SD_function of rec_opt * tannot_opt * effect_opt * id (* scattered function definition header *)
+ | SD_funcl of funcl (* scattered function definition clause *)
+ | SD_variant of id * name_scm_opt * typquant (* scattered union definition header *)
+ | SD_unioncl of id * type_union (* scattered union definition member *)
+ | SD_mapping of id * tannot_opt
+ | SD_mapcl of id * mapcl
+ | SD_end of id (* scattered definition end *)
type
@@ -567,7 +533,6 @@ def = (* Top-level definition *)
| DEF_scattered of scattered_def (* scattered definition *)
| DEF_reg_dec of dec_spec (* register declaration *)
| DEF_pragma of string * string * l
- | DEF_constraint of id * kid list * n_constraint
| DEF_internal_mutrec of fundef list
diff --git a/src/parser.mly b/src/parser.mly
index 0fe99280..9fdf27b7 100644
--- a/src/parser.mly
+++ b/src/parser.mly
@@ -78,6 +78,8 @@ let prepend_id str1 = function
let mk_id i n m = Id_aux (i, loc n m)
let mk_kid str n m = Kid_aux (Var str, loc n m)
+let mk_kopt k n m = KOpt_aux (k, loc n m)
+
let id_of_kid = function
| Kid_aux (Var v, l) -> Id_aux (Id (String.sub v 1 (String.length v - 1)), l)
@@ -103,7 +105,6 @@ let mk_typschm_opt ts n m = TypSchm_opt_aux (
let mk_typschm_opt_none = TypSchm_opt_aux (TypSchm_opt_none, Unknown)
-let mk_nc nc n m = NC_aux (nc, loc n m)
let mk_sd s n m = SD_aux (s, loc n m)
let mk_sd_doc s str n m = SD_aux (s, Documented (str, loc n m))
let mk_ir r n m = BF_aux (r, loc n m)
@@ -126,6 +127,8 @@ let doc_vs doc (VS_aux (v, l)) = VS_aux (v, Documented (doc, l))
let qi_id_of_kopt (KOpt_aux (kopt_aux, l) as kopt) = QI_aux (QI_id kopt, l)
+let mk_recr r n m = (Rec_aux(r, loc n m))
+
let mk_recn = (Rec_aux((Rec_nonrec), Unknown))
let mk_typqn = (TypQ_aux(TypQ_no_forall,Unknown))
let mk_tannotn = Typ_annot_opt_aux(Typ_annot_opt_none,Unknown)
@@ -133,23 +136,25 @@ let mk_tannot typq typ n m = Typ_annot_opt_aux(Typ_annot_opt_some (typq, typ), l
let mk_eannotn = Effect_opt_aux(Effect_opt_pure,Unknown)
let mk_namesectn = Name_sect_aux(Name_sect_none,Unknown)
+let mk_typq kopts nc n m = TypQ_aux (TypQ_tq (List.map qi_id_of_kopt kopts @ nc), loc n m)
+
type lchain =
LC_lt
| LC_lteq
| LC_nexp of atyp
+let tyop op t1 t2 s e = mk_typ (ATyp_app (Id_aux (DeIid op, loc s e), [t1; t2])) s e
+
let rec desugar_lchain chain s e =
match chain with
- | [LC_nexp n1; LC_lteq; LC_nexp n2] ->
- mk_nc (NC_bounded_le (n1, n2)) s e
- | [LC_nexp n1; LC_lt; LC_nexp n2] ->
- mk_nc (NC_bounded_le (mk_typ (ATyp_sum (n1, mk_typ (ATyp_constant (Big_int.of_int 1)) s e)) s e, n2)) s e
+ | [LC_nexp n1; LC_lteq; LC_nexp n2] -> tyop "<=" n1 n2 s e
+ | [LC_nexp n1; LC_lt; LC_nexp n2] -> tyop "<" n1 n2 s e
| (LC_nexp n1 :: LC_lteq :: LC_nexp n2 :: chain) ->
- let nc1 = mk_nc (NC_bounded_le (n1, n2)) s e in
- mk_nc (NC_and (nc1, desugar_lchain (LC_nexp n2 :: chain) s e)) s e
+ let nc1 = tyop "<=" n1 n2 s e in
+ tyop "&" nc1 (desugar_lchain (LC_nexp n2 :: chain) s e) s e
| (LC_nexp n1 :: LC_lt :: LC_nexp n2 :: chain) ->
- let nc1 = mk_nc (NC_bounded_le (mk_typ (ATyp_sum (n1, mk_typ (ATyp_constant (Big_int.of_int 1)) s e)) s e, n2)) s e in
- mk_nc (NC_and (nc1, desugar_lchain (LC_nexp n2 :: chain) s e)) s e
+ let nc1 = tyop "<" n1 n2 s e in
+ tyop "&" nc1 (desugar_lchain (LC_nexp n2 :: chain) s e) s e
| _ -> assert false
type rchain =
@@ -159,26 +164,24 @@ type rchain =
let rec desugar_rchain chain s e =
match chain with
- | [RC_nexp n1; RC_gteq; RC_nexp n2] ->
- mk_nc (NC_bounded_ge (n1, n2)) s e
- | [RC_nexp n1; RC_gt; RC_nexp n2] ->
- mk_nc (NC_bounded_ge (n1, mk_typ (ATyp_sum (n2, mk_typ (ATyp_constant (Big_int.of_int 1)) s e)) s e)) s e
+ | [RC_nexp n1; RC_gteq; RC_nexp n2] -> tyop ">=" n1 n2 s e
+ | [RC_nexp n1; RC_gt; RC_nexp n2] -> tyop ">" n1 n2 s e
| (RC_nexp n1 :: RC_gteq :: RC_nexp n2 :: chain) ->
- let nc1 = mk_nc (NC_bounded_ge (n1, n2)) s e in
- mk_nc (NC_and (nc1, desugar_rchain (RC_nexp n2 :: chain) s e)) s e
+ let nc1 = tyop ">=" n1 n2 s e in
+ tyop "&" nc1 (desugar_rchain (RC_nexp n2 :: chain) s e) s e
| (RC_nexp n1 :: RC_gt :: RC_nexp n2 :: chain) ->
- let nc1 = mk_nc (NC_bounded_ge (n1, mk_typ (ATyp_sum (n2, mk_typ (ATyp_constant (Big_int.of_int 1)) s e)) s e)) s e in
- mk_nc (NC_and (nc1, desugar_rchain (RC_nexp n2 :: chain) s e)) s e
+ let nc1 = tyop ">" n1 n2 s e in
+ tyop "&" nc1 (desugar_rchain (RC_nexp n2 :: chain) s e) s e
| _ -> assert false
%}
/*Terminals with no content*/
-%token And As Assert Bitzero Bitone By Match Clause Dec Default Effect End Op Tuple Where
-%token Enum Else False Forall Foreach Overload Function_ Mapping If_ In Inc Let_ Int Order Cast
+%token And As Assert Bitzero Bitone By Match Clause Dec Default Effect End Op Where
+%token Enum Else False Forall Foreach Overload Function_ Mapping If_ In Inc Let_ Int Order Bool Cast
%token Pure Register Return Scattered Sizeof Struct Then True TwoCaret TYPE Typedef
-%token Undefined Union Newtype With Val Constraint Throw Try Catch Exit Bitfield
+%token Undefined Union Newtype With Val Constant Constraint Throw Try Catch Exit Bitfield
%token Barr Depend Rreg Wreg Rmem Rmemt Wmem Wmv Wmvt Eamem Exmem Undef Unspec Nondet Escape
%token Repeat Until While Do Mutual Var Ref Configuration
@@ -196,7 +199,8 @@ let rec desugar_rchain chain s e =
%token <string> String Bin Hex Real
%token <string> Amp At Caret Eq Gt Lt Plus Star EqGt Unit
-%token <string> Colon ColonColon (* CaretCaret *) TildeTilde ExclEq
+%token <string> Colon ColonColon TildeTilde ExclEq
+%token <string> EqEq
%token <string> GtEq
%token <string> LtEq
@@ -212,9 +216,11 @@ let rec desugar_rchain chain s e =
%start file
%start typschm_eof
+%start typ_eof
%start exp_eof
%start def_eof
%type <Parse_ast.typschm> typschm_eof
+%type <Parse_ast.atyp> typ_eof
%type <Parse_ast.exp> exp_eof
%type <Parse_ast.def> def_eof
%type <Parse_ast.defs> file
@@ -260,6 +266,7 @@ id:
| Op Plus { mk_id (DeIid "+") $startpos $endpos }
| Op Minus { mk_id (DeIid "-") $startpos $endpos }
| Op Star { mk_id (DeIid "*") $startpos $endpos }
+ | Op EqEq { mk_id (DeIid "==") $startpos $endpos }
| Op ExclEq { mk_id (DeIid "!=") $startpos $endpos }
| Op Lt { mk_id (DeIid "<") $startpos $endpos }
| Op Gt { mk_id (DeIid ">") $startpos $endpos }
@@ -312,70 +319,40 @@ kid:
| TyVar
{ mk_kid $1 $startpos $endpos }
-kid_list:
- | kid
- { [$1] }
- | kid kid_list
- { $1 :: $2 }
-
-nc:
- | nc Bar nc_and
- { mk_nc (NC_or ($1, $3)) $startpos $endpos }
- | nc_and
- { $1 }
-
-nc_and:
- | nc_and Amp atomic_nc
- { mk_nc (NC_and ($1, $3)) $startpos $endpos }
- | atomic_nc
- { $1 }
-
-atomic_nc:
- | Where id Lparen typ_list Rparen
- { mk_nc (NC_app ($2, $4)) $startpos $endpos }
- | True
- { mk_nc NC_true $startpos $endpos }
- | False
- { mk_nc NC_false $startpos $endpos }
- | typ Eq typ
- { mk_nc (NC_equal ($1, $3)) $startpos $endpos }
- | typ ExclEq typ
- { mk_nc (NC_not_equal ($1, $3)) $startpos $endpos }
- | nc_lchain
- { desugar_lchain $1 $startpos $endpos }
- | nc_rchain
- { desugar_rchain $1 $startpos $endpos }
- | Lparen nc Rparen
- { $2 }
- | kid In Lcurly num_list Rcurly
- { mk_nc (NC_set ($1, $4)) $startpos $endpos }
-
num_list:
| Num
{ [$1] }
| Num Comma num_list
{ $1 :: $3 }
-nc_lchain:
- | typ LtEq typ
+lchain:
+ | typ5 LtEq typ5
{ [LC_nexp $1; LC_lteq; LC_nexp $3] }
- | typ Lt typ
+ | typ5 Lt typ5
{ [LC_nexp $1; LC_lt; LC_nexp $3] }
- | typ LtEq nc_lchain
+ | typ5 LtEq lchain
{ LC_nexp $1 :: LC_lteq :: $3 }
- | typ Lt nc_lchain
+ | typ5 Lt lchain
{ LC_nexp $1 :: LC_lt :: $3 }
-nc_rchain:
- | typ GtEq typ
+rchain:
+ | typ5 GtEq typ5
{ [RC_nexp $1; RC_gteq; RC_nexp $3] }
- | typ Gt typ
+ | typ5 Gt typ5
{ [RC_nexp $1; RC_gt; RC_nexp $3] }
- | typ GtEq nc_rchain
+ | typ5 GtEq rchain
{ RC_nexp $1 :: RC_gteq :: $3 }
- | typ Gt nc_rchain
+ | typ5 Gt rchain
{ RC_nexp $1 :: RC_gt :: $3 }
+tyarg:
+ | Lparen typ_list Rparen
+ { [], $2 }
+
+typ_eof:
+ | typ Eof
+ { $1 }
+
typ:
| typ0
{ $1 }
@@ -415,6 +392,7 @@ typ2:
| typ3 op2 typ3 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ2l op2l typ3 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ3 op2r typ2r { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
+ | typ3 Bar typ2r { mk_typ (ATyp_app (deinfix (mk_id (Id "|") $startpos($2) $endpos($2)), [$1; $3])) $startpos $endpos }
| typ3 { $1 }
typ2l:
| typ3 op2 typ3 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
@@ -423,12 +401,14 @@ typ2l:
typ2r:
| typ3 op2 typ3 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ3 op2r typ2r { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
+ | typ3 Bar typ2r { mk_typ (ATyp_app (deinfix (mk_id (Id "|") $startpos($2) $endpos($2)), [$1; $3])) $startpos $endpos }
| typ3 { $1 }
typ3:
| typ4 op3 typ4 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ3l op3l typ4 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ4 op3r typ3r { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
+ | typ4 Amp typ3r { mk_typ (ATyp_app (deinfix (mk_id (Id "&") $startpos($2) $endpos($2)), [$1; $3])) $startpos $endpos }
| typ4 { $1 }
typ3l:
| typ4 op3 typ4 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
@@ -437,12 +417,17 @@ typ3l:
typ3r:
| typ4 op3 typ4 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ4 op3r typ3r { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
+ | typ4 Amp typ3r { mk_typ (ATyp_app (deinfix (mk_id (Id "&") $startpos($2) $endpos($2)), [$1; $3])) $startpos $endpos }
| typ4 { $1 }
typ4:
| typ5 op4 typ5 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ4l op4l typ5 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ5 op4r typ4r { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
+ | lchain { desugar_lchain $1 $startpos $endpos }
+ | rchain { desugar_rchain $1 $startpos $endpos }
+ | typ5 EqEq typ5 { mk_typ (ATyp_app (deinfix (mk_id (Id $2) $startpos($2) $endpos($2)), [$1; $3])) $startpos $endpos }
+ | typ5 ExclEq typ5 { mk_typ (ATyp_app (deinfix (mk_id (Id $2) $startpos($2) $endpos($2)), [$1; $3])) $startpos $endpos }
| typ5 { $1 }
typ4l:
| typ5 op4 typ5 { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
@@ -522,6 +507,8 @@ typ8r:
| typ9 { $1 }
typ9:
+ | kid In Lcurly num_list Rcurly
+ { mk_typ (ATyp_nset ($1, $4)) $startpos $endpos }
| atomic_typ op9 atomic_typ { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| typ9l op9l atomic_typ { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
| atomic_typ op9r typ9r { mk_typ (ATyp_app (deinfix $2, [$1; $3])) $startpos $endpos }
@@ -542,14 +529,14 @@ atomic_typ:
{ mk_typ ATyp_wild $startpos $endpos }
| kid
{ mk_typ (ATyp_var $1) $startpos $endpos }
- | Num
- { mk_typ (ATyp_constant $1) $startpos $endpos }
+ | lit
+ { mk_typ (ATyp_lit $1) $startpos $endpos }
| Dec
{ mk_typ ATyp_dec $startpos $endpos }
| Inc
{ mk_typ ATyp_inc $startpos $endpos }
- | id Lparen typ_list Rparen
- { mk_typ (ATyp_app ($1, $3)) $startpos $endpos }
+ | id tyarg
+ { mk_typ (ATyp_app ($1, snd $2 @ fst $2)) $startpos $endpos }
| Register Lparen typ Rparen
{ let register_id = mk_id (Id "register") $startpos($1) $endpos($1) in
mk_typ (ATyp_app (register_id, [$3])) $startpos $endpos }
@@ -561,11 +548,13 @@ atomic_typ:
{ let v = mk_kid "n" $startpos $endpos in
let atom_id = mk_id (Id "atom") $startpos $endpos in
let atom_of_v = mk_typ (ATyp_app (atom_id, [mk_typ (ATyp_var v) $startpos $endpos])) $startpos $endpos in
- mk_typ (ATyp_exist ([v], NC_aux (NC_set (v, $2), loc $startpos($2) $endpos($2)), atom_of_v)) $startpos $endpos }
- | Lcurly kid_list Dot typ Rcurly
- { mk_typ (ATyp_exist ($2, NC_aux (NC_true, loc $startpos $endpos), $4)) $startpos $endpos }
- | Lcurly kid_list Comma nc Dot typ Rcurly
+ mk_typ (ATyp_exist ([mk_kopt (KOpt_none v) $startpos $endpos], ATyp_aux (ATyp_nset (v, $2), loc $startpos($2) $endpos($2)), atom_of_v)) $startpos $endpos }
+ | Lcurly kopt_list Dot typ Rcurly
+ { mk_typ (ATyp_exist ($2, ATyp_aux (ATyp_lit (L_aux (L_true, loc $startpos $endpos)), loc $startpos $endpos), $4)) $startpos $endpos }
+ | Lcurly kopt_list Comma typ Dot typ Rcurly
{ mk_typ (ATyp_exist ($2, $4, $6)) $startpos $endpos }
+ | Lcurly id Colon typ Dot typ Rcurly
+ { mk_typ (ATyp_base ($2, $4, $6)) $startpos $endpos }
typ_list:
| typ
@@ -573,17 +562,15 @@ typ_list:
| typ Comma typ_list
{ $1 :: $3 }
-base_kind:
+kind:
| Int
- { BK_aux (BK_int, loc $startpos $endpos) }
+ { K_aux (K_int, loc $startpos $endpos) }
| TYPE
- { BK_aux (BK_type, loc $startpos $endpos) }
+ { K_aux (K_type, loc $startpos $endpos) }
| Order
- { BK_aux (BK_order, loc $startpos $endpos) }
-
-kind:
- | base_kind
- { K_aux (K_kind [$1], loc $startpos $endpos) }
+ { K_aux (K_order, loc $startpos $endpos) }
+ | Bool
+ { K_aux (K_bool, loc $startpos $endpos) }
kopt:
| Lparen kid Colon kind Rparen
@@ -598,7 +585,7 @@ kopt_list:
{ $1 :: $2 }
typquant:
- | kopt_list Comma nc
+ | kopt_list Comma typ
{ let qi_nc = QI_aux (QI_const $3, loc $startpos($3) $endpos($3)) in
TypQ_aux (TypQ_tq (List.map qi_id_of_kopt $1 @ [qi_nc]), loc $startpos $endpos) }
| kopt_list
@@ -677,8 +664,8 @@ pat_string_append:
pat1:
| atomic_pat
{ $1 }
- | atomic_pat Bar pat1
- { mk_pat (P_or ($1, $3)) $startpos $endpos }
+ (* | atomic_pat Bar pat1
+ { mk_pat (P_or ($1, $3)) $startpos $endpos } *)
| atomic_pat At pat_concat
{ mk_pat (P_vector_concat ($1 :: $3)) $startpos $endpos }
| atomic_pat ColonColon pat1
@@ -890,6 +877,7 @@ exp4:
| exp5 LtEq exp5 { mk_exp (E_app_infix ($1, mk_id (Id "<=") $startpos($2) $endpos($2), $3)) $startpos $endpos }
| exp5 GtEq exp5 { mk_exp (E_app_infix ($1, mk_id (Id ">=") $startpos($2) $endpos($2), $3)) $startpos $endpos }
| exp5 ExclEq exp5 { mk_exp (E_app_infix ($1, mk_id (Id "!=") $startpos($2) $endpos($2), $3)) $startpos $endpos }
+ | exp5 EqEq exp5 { mk_exp (E_app_infix ($1, mk_id (Id "==") $startpos($2) $endpos($2), $3)) $startpos $endpos }
| exp4l op4l exp5 { mk_exp (E_app_infix ($1, $2, $3)) $startpos $endpos }
| exp5 op4r exp4r { mk_exp (E_app_infix ($1, $2, $3)) $startpos $endpos }
| exp5 { $1 }
@@ -1046,7 +1034,7 @@ atomic_exp:
{ mk_exp (E_exit $3) $startpos $endpos }
| Sizeof Lparen typ Rparen
{ mk_exp (E_sizeof $3) $startpos $endpos }
- | Constraint Lparen nc Rparen
+ | Constraint Lparen typ Rparen
{ mk_exp (E_constraint $3) $startpos $endpos }
| Assert Lparen exp Rparen
{ mk_exp (E_assert ($3, mk_lit_exp (L_string "") $startpos($4) $endpos($4))) $startpos $endpos }
@@ -1104,12 +1092,14 @@ funcl_patexp:
funcl_patexp_typ:
| pat Eq exp
{ (mk_pexp (Pat_exp ($1, $3)) $startpos $endpos, mk_tannotn) }
- | pat MinusGt funcl_typ Eq exp
- { (mk_pexp (Pat_exp ($1, $5)) $startpos $endpos, $3) }
+ | pat MinusGt typ Eq exp
+ { (mk_pexp (Pat_exp ($1, $5)) $startpos $endpos, mk_tannot mk_typqn $3 $startpos $endpos($3)) }
+ | Forall typquant Dot pat MinusGt typ Eq exp
+ { (mk_pexp (Pat_exp ($4, $8)) $startpos $endpos, mk_tannot $2 $6 $startpos $endpos($6)) }
| Lparen pat If_ exp Rparen Eq exp
{ (mk_pexp (Pat_when ($2, $4, $7)) $startpos $endpos, mk_tannotn) }
- | Lparen pat If_ exp Rparen MinusGt funcl_typ Eq exp
- { (mk_pexp (Pat_when ($2, $4, $9)) $startpos $endpos, $7) }
+ | Forall typquant Dot Lparen pat If_ exp Rparen MinusGt typ Eq exp
+ { (mk_pexp (Pat_when ($5, $7, $12)) $startpos $endpos, mk_tannot $2 $10 $startpos $endpos($10)) }
funcl:
| id funcl_patexp
@@ -1151,14 +1141,37 @@ r_def_body:
| r_id_def Comma r_def_body
{ $1 :: $3 }
+param_kopt:
+ | kid Colon kind
+ { KOpt_aux (KOpt_kind ($3, $1), loc $startpos $endpos) }
+ | kid
+ { KOpt_aux (KOpt_none $1, loc $startpos $endpos) }
+
+param_kopt_list:
+ | param_kopt
+ { [$1] }
+ | param_kopt Comma param_kopt_list
+ { $1 :: $3 }
+
+typaram:
+ | Lparen param_kopt_list Rparen Comma typ
+ { let qi_nc = QI_aux (QI_const $5, loc $startpos($5) $endpos($5)) in
+ mk_typq $2 [qi_nc] $startpos $endpos }
+ | Lparen param_kopt_list Rparen
+ { mk_typq $2 [] $startpos $endpos }
+
type_def:
- | Typedef id typquant Eq typ
- { mk_td (TD_abbrev ($2, mk_namesectn, mk_typschm $3 $5 $startpos($3) $endpos)) $startpos $endpos }
+ | Typedef id typaram Eq typ
+ { mk_td (TD_abbrev ($2, $3, K_aux (K_type, Parse_ast.Unknown), $5)) $startpos $endpos }
| Typedef id Eq typ
- { mk_td (TD_abbrev ($2, mk_namesectn, mk_typschm mk_typqn $4 $startpos($4) $endpos)) $startpos $endpos }
+ { mk_td (TD_abbrev ($2, mk_typqn, K_aux (K_type, Parse_ast.Unknown), $4)) $startpos $endpos }
+ | Typedef id typaram MinusGt kind Eq typ
+ { mk_td (TD_abbrev ($2, $3, $5, $7)) $startpos $endpos }
+ | Typedef id Colon kind Eq typ
+ { mk_td (TD_abbrev ($2, mk_typqn, $4, $6)) $startpos $endpos }
| Struct id Eq Lcurly struct_fields Rcurly
{ mk_td (TD_record ($2, mk_namesectn, TypQ_aux (TypQ_tq [], loc $endpos($2) $startpos($3)), $5, false)) $startpos $endpos }
- | Struct id typquant Eq Lcurly struct_fields Rcurly
+ | Struct id typaram Eq Lcurly struct_fields Rcurly
{ mk_td (TD_record ($2, mk_namesectn, $3, $6, false)) $startpos $endpos }
| Enum id Eq enum_bar
{ mk_td (TD_enum ($2, mk_namesectn, $4, false)) $startpos $endpos }
@@ -1166,11 +1179,11 @@ type_def:
{ mk_td (TD_enum ($2, mk_namesectn, $5, false)) $startpos $endpos }
| Newtype id Eq type_union
{ mk_td (TD_variant ($2, mk_namesectn, TypQ_aux (TypQ_tq [], loc $endpos($2) $startpos($3)), [$4], false)) $startpos $endpos }
- | Newtype id typquant Eq type_union
+ | Newtype id typaram Eq type_union
{ mk_td (TD_variant ($2, mk_namesectn, $3, [$5], false)) $startpos $endpos }
| Union id Eq Lcurly type_unions Rcurly
{ mk_td (TD_variant ($2, mk_namesectn, TypQ_aux (TypQ_tq [], loc $endpos($2) $startpos($3)), $5, false)) $startpos $endpos }
- | Union id typquant Eq Lcurly type_unions Rcurly
+ | Union id typaram Eq Lcurly type_unions Rcurly
{ mk_td (TD_variant ($2, mk_namesectn, $3, $6, false)) $startpos $endpos }
| Bitfield id Colon typ Eq Lcurly r_def_body Rcurly
{ mk_td (TD_bitfield ($2, $4, $7)) $startpos $endpos }
@@ -1215,9 +1228,15 @@ type_unions:
| type_union Comma type_unions
{ $1 :: $3 }
+rec_measure:
+ | Lcurly pat EqGt exp Rcurly
+ { mk_recr (Rec_measure ($2, $4)) $startpos $endpos }
+
fun_def:
| Function_ funcls
{ let funcls, tannot = $2 in mk_fun (FD_function (mk_recn, tannot, mk_eannotn, funcls)) $startpos $endpos }
+ | Function_ rec_measure funcls
+ { let funcls, tannot = $3 in mk_fun (FD_function ($2, tannot, mk_eannotn, funcls)) $startpos $endpos }
fun_def_list:
| fun_def
@@ -1349,28 +1368,28 @@ register_def:
{ mk_reg_dec (DEC_config ($3, $5, $7)) $startpos $endpos }
default_def:
- | Default base_kind Inc
+ | Default kind Inc
{ mk_default (DT_order ($2, mk_typ ATyp_inc $startpos($3) $endpos)) $startpos $endpos }
- | Default base_kind Dec
+ | Default kind Dec
{ mk_default (DT_order ($2, mk_typ ATyp_dec $startpos($3) $endpos)) $startpos $endpos }
scattered_def:
- | Union id typquant
- { mk_sd (SD_scattered_variant($2, mk_namesectn, $3)) $startpos $endpos }
+ | Union id typaram
+ { mk_sd (SD_variant($2, mk_namesectn, $3)) $startpos $endpos }
| Union id
- { mk_sd (SD_scattered_variant($2, mk_namesectn, mk_typqn)) $startpos $endpos }
+ { mk_sd (SD_variant($2, mk_namesectn, mk_typqn)) $startpos $endpos }
| Function_ id
- { mk_sd (SD_scattered_function(mk_recn, mk_tannotn, mk_eannotn, $2)) $startpos $endpos }
+ { mk_sd (SD_function(mk_recn, mk_tannotn, mk_eannotn, $2)) $startpos $endpos }
| Mapping id
- { mk_sd (SD_scattered_mapping ($2, mk_tannotn)) $startpos $endpos }
+ { mk_sd (SD_mapping ($2, mk_tannotn)) $startpos $endpos }
| Mapping id Colon funcl_typ
- { mk_sd (SD_scattered_mapping ($2, $4)) $startpos $endpos }
+ { mk_sd (SD_mapping ($2, $4)) $startpos $endpos }
scattered_clause:
| Doc Function_ Clause funcl
- { mk_sd_doc (SD_scattered_funcl $4) $1 $startpos($2) $endpos }
+ { mk_sd_doc (SD_funcl $4) $1 $startpos($2) $endpos }
| Function_ Clause funcl
- { mk_sd (SD_scattered_funcl $3) $startpos $endpos }
+ { mk_sd (SD_funcl $3) $startpos $endpos }
def:
@@ -1397,15 +1416,16 @@ def:
| scattered_clause
{ DEF_scattered $1 }
| Union Clause id Eq type_union
- { DEF_scattered (mk_sd (SD_scattered_unioncl ($3, $5)) $startpos $endpos) }
+ { DEF_scattered (mk_sd (SD_unioncl ($3, $5)) $startpos $endpos) }
| Mapping Clause id Eq mapcl
- { DEF_scattered (mk_sd (SD_scattered_mapcl ($3, $5)) $startpos $endpos) }
+ { DEF_scattered (mk_sd (SD_mapcl ($3, $5)) $startpos $endpos) }
| End id
- { DEF_scattered (mk_sd (SD_scattered_end $2) $startpos $endpos) }
+ { DEF_scattered (mk_sd (SD_end $2) $startpos $endpos) }
| default_def
{ DEF_default $1 }
- | Constraint id Lparen kid_list Rparen Eq nc
- { DEF_constraint ($2, $4, $7) }
+ | Constant id Eq typ
+ { DEF_kind (KD_aux (KD_nabbrev (K_aux (K_int, loc $startpos($1) $endpos($1)), $2, mk_namesectn, $4),
+ loc $startpos $endpos)) }
| Mutual Lcurly fun_def_list Rcurly
{ DEF_internal_mutrec $3 }
| Pragma
diff --git a/src/pattern_completeness.ml b/src/pattern_completeness.ml
index d54bbd3f..514eb5c0 100644
--- a/src/pattern_completeness.ml
+++ b/src/pattern_completeness.ml
@@ -269,7 +269,7 @@ let combine ctx gpat (l, pat) =
(* This warning liable to false positives as join returns a
pattern that overapproximates what can match, so we only
report when the second match is a constructor. *)
- Util.warn (Printf.sprintf "Possible redundant pattern match at %s\n" (Reporting_basic.loc_to_string l));
+ Util.warn (Printf.sprintf "Possible redundant pattern match at %s\n" (Reporting.loc_to_string l));
GP_wild
| _, gpat' -> join ctx gpat gpat'
@@ -287,7 +287,7 @@ let shrink_loc = function
let check l ctx cases =
match cases_to_pats cases with
- | [] -> Util.warn (Printf.sprintf "No non-guarded patterns at %s\n" (Reporting_basic.loc_to_string (shrink_loc l)))
+ | [] -> Util.warn (Printf.sprintf "No non-guarded patterns at %s\n" (Reporting.loc_to_string (shrink_loc l)))
| (_, pat) :: pats ->
let top_pat = List.fold_left (combine ctx) (generalize ctx pat) pats in
if is_wild top_pat then
@@ -295,7 +295,7 @@ let check l ctx cases =
else
let message =
Printf.sprintf "Possible incomplete pattern match at %s\n\nMost general matched pattern is %s\n"
- (Reporting_basic.loc_to_string (shrink_loc l))
+ (Reporting.loc_to_string (shrink_loc l))
(string_of_gpat top_pat |> Util.cyan |> Util.clear)
in
Util.warn message
diff --git a/src/pretty_print_common.ml b/src/pretty_print_common.ml
index 1fb35158..c01896ac 100644
--- a/src/pretty_print_common.ml
+++ b/src/pretty_print_common.ml
@@ -94,133 +94,5 @@ let rec doc_range (BF_aux(r,_)) = match r with
| BF_range(i1,i2) -> doc_op dotdot (doc_int i1) (doc_int i2)
| BF_concat(ir1,ir2) -> (doc_range ir1) ^^ comma ^^ (doc_range ir2)
-let doc_effect (BE_aux (e,_)) =
- string (match e with
- | BE_rreg -> "rreg"
- | BE_wreg -> "wreg"
- | BE_rmem -> "rmem"
- | BE_rmemt -> "rmemt"
- | BE_wmem -> "wmem"
- | BE_wmv -> "wmv"
- | BE_wmvt -> "wmvt"
- (*| BE_lset -> "lset"
- | BE_lret -> "lret"*)
- | BE_eamem -> "eamem"
- | BE_exmem -> "exmem"
- | BE_barr -> "barr"
- | BE_depend -> "depend"
- | BE_escape -> "escape"
- | BE_undef -> "undef"
- | BE_unspec -> "unspec"
- | BE_nondet -> "nondet"
- | BE_config -> "config")
-
-let doc_effects (Effect_aux(e,_)) = match e with
- | Effect_set [] -> string "pure"
- | Effect_set s -> braces (separate_map comma_sp doc_effect s)
-
-let doc_ord (Ord_aux(o,_)) = match o with
- | Ord_var v -> doc_var v
- | Ord_inc -> string "inc"
- | Ord_dec -> string "dec"
-
-let doc_typ, doc_atomic_typ, doc_nexp, doc_nexp_constraint =
- (* following the structure of parser for precedence *)
- let rec typ ty = fn_typ ty
- and fn_typ ((Typ_aux (t, _)) as ty) = match t with
- | Typ_fn(args,ret,efct) ->
- separate space [parens (separate_map (comma ^^ space) tup_typ args); arrow; fn_typ ret; string "effect"; doc_effects efct]
- | Typ_bidir (t1, t2) ->
- separate space [tup_typ t1; bidir; tup_typ t2]
- | _ -> tup_typ ty
- and tup_typ ((Typ_aux (t, _)) as ty) = match t with
- | Typ_exist (kids, nc, ty) ->
- separate space [string "exist"; separate_map space doc_var kids ^^ comma; nexp_constraint nc ^^ dot; typ ty]
- | Typ_tup typs -> parens (separate_map comma_sp app_typ typs)
- | _ -> app_typ ty
- and app_typ ((Typ_aux (t, _)) as ty) = match t with
- | Typ_app(Id_aux (Id "range", _), [
- Typ_arg_aux(Typ_arg_nexp (Nexp_aux(Nexp_constant n, _)), _);
- Typ_arg_aux(Typ_arg_nexp m, _);]) ->
- (squarebars (if Big_int.equal n Big_int.zero then nexp m else doc_op colon (doc_int n) (nexp m)))
- | Typ_app(Id_aux (Id "atom", _), [Typ_arg_aux(Typ_arg_nexp n,_)]) ->
- (squarecolons (nexp n))
- | Typ_app(id,args) ->
- (* trailing space to avoid >> token in case of nested app types *)
- (doc_id id) ^^ (angles (separate_map comma_sp doc_typ_arg args)) ^^ space
- | _ -> atomic_typ ty (* for simplicity, skip vec_typ - which is only sugar *)
- and atomic_typ ((Typ_aux (t, _)) as ty) = match t with
- | Typ_id id -> doc_id id
- | Typ_var v -> doc_var v
- | Typ_app _ | Typ_tup _ | Typ_fn _ | Typ_bidir _ | Typ_exist _ ->
- (* exhaustiveness matters here to avoid infinite loops
- * if we add a new Typ constructor *)
- group (parens (typ ty))
- | Typ_internal_unknown -> string "UNKNOWN"
-
- and doc_typ_arg (Typ_arg_aux(t,_)) = match t with
- (* Be careful here because typ_arg is implemented as nexp in the
- * parser - in practice falling through app_typ after all the proper nexp
- * cases; so Typ_arg_typ has the same precedence as a Typ_app *)
- | Typ_arg_typ t -> app_typ t
- | Typ_arg_nexp n -> nexp n
- | Typ_arg_order o -> doc_ord o
-
- (* same trick to handle precedence of nexp *)
- and nexp ne = sum_typ ne
- and sum_typ ((Nexp_aux(n,_)) as ne) = match n with
- | Nexp_sum(n1,n2) -> doc_op plus (sum_typ n1) (star_typ n2)
- | Nexp_minus(n1,n2) -> doc_op minus (sum_typ n1) (star_typ n2)
- | _ -> star_typ ne
- and star_typ ((Nexp_aux(n,_)) as ne) = match n with
- | Nexp_times(n1,n2) -> doc_op star (star_typ n1) (exp_typ n2)
- | _ -> exp_typ ne
- and exp_typ ((Nexp_aux(n,_)) as ne) = match n with
- | Nexp_exp n1 -> doc_unop (string "2**") (atomic_nexp_typ n1)
- | _ -> neg_typ ne
- and neg_typ ((Nexp_aux(n,_)) as ne) = match n with
- | Nexp_neg n1 ->
- (* XXX this is not valid Sail, only an internal representation -
- * work around by commenting it *)
- let minus = concat [string "(*"; minus; string "*)"] in
- minus ^^ (atomic_nexp_typ n1)
- | _ -> atomic_nexp_typ ne
- and atomic_nexp_typ ((Nexp_aux(n,_)) as ne) = match n with
- | Nexp_var v -> doc_var v
- | Nexp_id i -> braces (doc_id i)
- | Nexp_app (op, args) -> doc_id op ^^ parens (separate_map (comma ^^ space) nexp args)
- | Nexp_constant i -> if Big_int.less i Big_int.zero then parens(doc_int i) else doc_int i
- | Nexp_neg _ | Nexp_exp _ | Nexp_times _ | Nexp_sum _ | Nexp_minus _->
- group (parens (nexp ne))
-
- and nexp_constraint (NC_aux(nc,_)) = match nc with
- | NC_equal(n1,n2) -> doc_op equals (nexp n1) (nexp n2)
- | NC_not_equal (n1, n2) -> doc_op (string "!=") (nexp n1) (nexp n2)
- | NC_bounded_ge(n1,n2) -> doc_op (string ">=") (nexp n1) (nexp n2)
- | NC_bounded_le(n1,n2) -> doc_op (string "<=") (nexp n1) (nexp n2)
- | NC_set(v,bounds) ->
- doc_op (string "IN") (doc_var v)
- (braces (separate_map comma_sp doc_int bounds))
- | NC_or (nc1, nc2) ->
- parens (separate space [nexp_constraint nc1; string "|"; nexp_constraint nc2])
- | NC_and (nc1, nc2) ->
- separate space [nexp_constraint nc1; string "&"; nexp_constraint nc2]
- | NC_true -> string "true"
- | NC_false -> string "false"
-
- (* expose doc_typ, doc_atomic_typ, doc_nexp and doc_nexp_constraint *)
- in typ, atomic_typ, nexp, nexp_constraint
-
-let pp_format_id (Id_aux(i,_)) =
- match i with
- | Id(i) -> i
- | DeIid(x) -> "(deinfix " ^ x ^ ")"
-
-let rec list_format (sep : string) (fmt : 'a -> string) (ls : 'a list) : string =
- match ls with
- | [] -> ""
- | [a] -> fmt a
- | a::ls -> (fmt a) ^ sep ^ (list_format sep fmt ls)
-
let print ?(len=100) channel doc = ToChannel.pretty 1. len channel doc
let to_buf ?(len=100) buf doc = ToBuffer.pretty 1. len buf doc
diff --git a/src/pretty_print_coq.ml b/src/pretty_print_coq.ml
index ccbde5cd..279a8182 100644
--- a/src/pretty_print_coq.ml
+++ b/src/pretty_print_coq.ml
@@ -65,12 +65,27 @@ let opt_debug_on : string list ref = ref []
* PPrint-based sail-to-coq pprinter
****************************************************************************)
+(* Data representation:
+ *
+ * In pure computations we keep values with top level existential types
+ * (including ranges and nats) separate from the proofs of the accompanying
+ * constraints, which keeps the terms shorter and more manageable.
+ * Existentials embedded in types (e.g., in tuples or datatypes) are dependent
+ * pairs.
+ *
+ * Monadic values always includes the proof in a dependent pair because the
+ * constraint solving tactic won't see the term that defined the value, and
+ * must rely entirely on the type (like the Sail type checker).
+ *)
+
+
type context = {
early_ret : bool;
kid_renames : kid KBindings.t; (* Plain tyvar -> tyvar renames *)
kid_id_renames : id KBindings.t; (* tyvar -> argument renames *)
bound_nvars : KidSet.t;
build_ex_return : bool;
+ recursive_ids : IdSet.t;
debug : bool;
}
let empty_ctxt = {
@@ -79,6 +94,7 @@ let empty_ctxt = {
kid_id_renames = KBindings.empty;
bound_nvars = KidSet.empty;
build_ex_return = false;
+ recursive_ids = IdSet.empty;
debug = false;
}
@@ -240,7 +256,7 @@ let doc_nexp ctx ?(skip_vars=KidSet.empty) nexp =
| Nexp_app (Id_aux (Id "abs_atom",_), [_])
-> parens (plussub nexp)
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
("cannot pretty-print nexp \"" ^ string_of_nexp nexp ^ "\""))
in atomic nexp
@@ -268,7 +284,7 @@ let rec coq_nvars_of_typ (Typ_aux (t,l)) =
| Typ_tup ts ->
List.fold_left (fun s t -> KidSet.union s (trec t))
KidSet.empty ts
- | Typ_app(Id_aux (Id "register", _), [Typ_arg_aux (Typ_arg_typ etyp, _)]) ->
+ | Typ_app(Id_aux (Id "register", _), [A_aux (A_typ etyp, _)]) ->
trec etyp
| Typ_app(Id_aux (Id "implicit", _),_)
(* TODO: update when complex atom types are sorted out *)
@@ -277,14 +293,14 @@ let rec coq_nvars_of_typ (Typ_aux (t,l)) =
List.fold_left (fun s ta -> KidSet.union s (coq_nvars_of_typ_arg ta))
KidSet.empty tas
(* TODO: remove appropriate bound variables *)
- | Typ_exist (kids,_,t) -> trec t
+ | Typ_exist (_,_,t) -> trec t
| Typ_bidir _ -> unreachable l __POS__ "Coq doesn't support bidir types"
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and coq_nvars_of_typ_arg (Typ_arg_aux (ta,_)) =
+and coq_nvars_of_typ_arg (A_aux (ta,_)) =
match ta with
- | Typ_arg_nexp nexp -> tyvars_of_nexp (orig_nexp nexp)
- | Typ_arg_typ typ -> coq_nvars_of_typ typ
- | Typ_arg_order _ -> KidSet.empty
+ | A_nexp nexp -> tyvars_of_nexp (orig_nexp nexp)
+ | A_typ typ -> coq_nvars_of_typ typ
+ | A_order _ -> KidSet.empty
(* Follows Coq precedence levels *)
let rec doc_nc_prop ctx nc =
@@ -353,17 +369,17 @@ let doc_nc_exp ctx nc =
let maybe_expand_range_type (Typ_aux (typ,l) as full_typ) =
match typ with
- | Typ_app(Id_aux (Id "range", _), [Typ_arg_aux(Typ_arg_nexp low,_);
- Typ_arg_aux(Typ_arg_nexp high,_)]) ->
+ | Typ_app(Id_aux (Id "range", _), [A_aux(A_nexp low,_);
+ A_aux(A_nexp high,_)]) ->
(* TODO: avoid name clashes *)
let kid = mk_kid "rangevar" in
let var = nvar kid in
let nc = nc_and (nc_lteq low var) (nc_lteq var high) in
- Some (Typ_aux (Typ_exist ([kid], nc, atom_typ var),Parse_ast.Generated l))
+ Some (Typ_aux (Typ_exist ([mk_kopt K_int kid], nc, atom_typ var),Parse_ast.Generated l))
| Typ_id (Id_aux (Id "nat",_)) ->
let kid = mk_kid "n" in
let var = nvar kid in
- Some (Typ_aux (Typ_exist ([kid], nc_gteq var (nconstant Nat_big_num.zero), atom_typ var),
+ Some (Typ_aux (Typ_exist ([mk_kopt K_int kid], nc_gteq var (nconstant Nat_big_num.zero), atom_typ var),
Parse_ast.Generated l))
| _ -> None
@@ -411,26 +427,26 @@ let doc_typ, doc_atomic_typ =
| _ -> app_typ atyp_needed ty
and app_typ atyp_needed ((Typ_aux (t, l)) as ty) = match t with
| Typ_app(Id_aux (Id "vector", _), [
- Typ_arg_aux (Typ_arg_nexp m, _);
- Typ_arg_aux (Typ_arg_order ord, _);
- Typ_arg_aux (Typ_arg_typ elem_typ, _)]) ->
+ A_aux (A_nexp m, _);
+ A_aux (A_order ord, _);
+ A_aux (A_typ elem_typ, _)]) ->
(* TODO: remove duplication with exists, below *)
let tpp = match elem_typ with
| Typ_aux (Typ_id (Id_aux (Id "bit",_)),_) -> (* TODO: coq-compatible simplification *)
string "mword " ^^ doc_nexp ctx m
| _ -> string "vec" ^^ space ^^ typ elem_typ ^^ space ^^ doc_nexp ctx m in
if atyp_needed then parens tpp else tpp
- | Typ_app(Id_aux (Id "register", _), [Typ_arg_aux (Typ_arg_typ etyp, _)]) ->
+ | Typ_app(Id_aux (Id "register", _), [A_aux (A_typ etyp, _)]) ->
let tpp = string "register_ref regstate register_value " ^^ typ etyp in
if atyp_needed then parens tpp else tpp
| Typ_app(Id_aux (Id "range", _), _)
| Typ_id (Id_aux (Id "nat", _)) ->
(match maybe_expand_range_type ty with
| Some typ -> atomic_typ atyp_needed typ
- | None -> raise (Reporting_basic.err_unreachable l __POS__ "Bad range type"))
+ | None -> raise (Reporting.err_unreachable l __POS__ "Bad range type"))
| Typ_app(Id_aux (Id "implicit", _),_) ->
(string "Z")
- | Typ_app(Id_aux (Id "atom", _), [Typ_arg_aux(Typ_arg_nexp n,_)]) ->
+ | Typ_app(Id_aux (Id "atom", _), [A_aux(A_nexp n,_)]) ->
(string "Z")
| Typ_app(id,args) ->
let tpp = (doc_id_type id) ^^ space ^^ (separate_map space doc_typ_arg args) in
@@ -449,32 +465,33 @@ let doc_typ, doc_atomic_typ =
* if we add a new Typ constructor *)
let tpp = typ ty in
if atyp_needed then parens tpp else tpp
- | Typ_exist (kids,nc,ty') -> begin
- let kids,nc,ty' = match maybe_expand_range_type ty' with
- | Some (Typ_aux (Typ_exist (kids',nc',ty'),_)) ->
- kids'@kids,nc_and nc nc',ty'
- | _ -> kids,nc,ty'
+ (* TODO: handle non-integer kopts *)
+ | Typ_exist (kopts,nc,ty') -> begin
+ let kopts,nc,ty' = match maybe_expand_range_type ty' with
+ | Some (Typ_aux (Typ_exist (kopts',nc',ty'),_)) ->
+ kopts'@kopts,nc_and nc nc',ty'
+ | _ -> kopts,nc,ty'
in
match ty' with
| Typ_aux (Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp nexp,_)]),_) ->
- begin match nexp, kids with
- | (Nexp_aux (Nexp_var kid,_)), [kid'] when Kid.compare kid kid' == 0 ->
+ [A_aux (A_nexp nexp,_)]),_) ->
+ begin match nexp, kopts with
+ | (Nexp_aux (Nexp_var kid,_)), [kopt] when Kid.compare kid (kopt_kid kopt) == 0 ->
braces (separate space [doc_var ctx kid; colon; string "Z";
ampersand; doc_arithfact ctx nc])
| _ ->
let var = mk_kid "_atom" in (* TODO collision avoid *)
let nc = nice_and (nc_eq (nvar var) nexp) nc in
braces (separate space [doc_var ctx var; colon; string "Z";
- ampersand; doc_arithfact ctx ~exists:kids nc])
+ ampersand; doc_arithfact ctx ~exists:(List.map kopt_kid kopts) nc])
end
| Typ_aux (Typ_app (Id_aux (Id "vector",_),
- [Typ_arg_aux (Typ_arg_nexp m, _);
- Typ_arg_aux (Typ_arg_order ord, _);
- Typ_arg_aux (Typ_arg_typ elem_typ, _)]),_) ->
+ [A_aux (A_nexp m, _);
+ A_aux (A_order ord, _);
+ A_aux (A_typ elem_typ, _)]),_) ->
(* TODO: proper handling of m, complex elem type, dedup with above *)
let var = mk_kid "_vec" in (* TODO collision avoid *)
- let kid_set = KidSet.of_list kids in
+ let kid_set = KidSet.of_list (List.map kopt_kid kopts) in
let m_pp = doc_nexp ctx ~skip_vars:kid_set m in
let tpp, len_pp = match elem_typ with
| Typ_aux (Typ_id (Id_aux (Id "bit",_)),_) ->
@@ -489,9 +506,9 @@ let doc_typ, doc_atomic_typ =
braces (separate space
[doc_var ctx var; colon; tpp;
ampersand;
- doc_arithfact ctx ~exists:kids ?extra:length_constraint_pp nc])
+ doc_arithfact ctx ~exists:(List.map kopt_kid kopts) ?extra:length_constraint_pp nc])
| _ ->
- raise (Reporting_basic.err_todo l
+ raise (Reporting.err_todo l
("Non-atom existential type not yet supported in Coq: " ^
string_of_typ ty))
end
@@ -515,10 +532,10 @@ let doc_typ, doc_atomic_typ =
end*)
| Typ_bidir _ -> unreachable l __POS__ "Coq doesn't support bidir types"
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
- and doc_typ_arg (Typ_arg_aux(t,_)) = match t with
- | Typ_arg_typ t -> app_typ true t
- | Typ_arg_nexp n -> doc_nexp ctx n
- | Typ_arg_order o -> empty
+ and doc_typ_arg (A_aux(t,_)) = match t with
+ | A_typ t -> app_typ true t
+ | A_nexp n -> doc_nexp ctx n
+ | A_order o -> empty
in typ', atomic_typ
in (fun ctx -> (fst (fns ctx))), (fun ctx -> (snd (fns ctx)))
@@ -530,10 +547,10 @@ let contains_t_pp_var ctxt (Typ_aux (t,a) as typ) =
(* TODO: should we resurrect this?
let replace_typ_size ctxt env (Typ_aux (t,a)) =
match t with
- | Typ_app (Id_aux (Id "vector",_) as id, [Typ_arg_aux (Typ_arg_nexp size,_);ord;typ']) ->
+ | Typ_app (Id_aux (Id "vector",_) as id, [A_aux (A_nexp size,_);ord;typ']) ->
begin
let mk_typ nexp =
- Some (Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp nexp,Parse_ast.Unknown);ord;typ']),a))
+ Some (Typ_aux (Typ_app (id, [A_aux (A_nexp nexp,Parse_ast.Unknown);ord;typ']),a))
in
match Type_check.solve env size with
| Some n -> mk_typ (nconstant n)
@@ -556,6 +573,10 @@ let doc_tannot ctxt env eff typ =
else string " : " ^^ ta
in of_typ typ
+(* Only double-quotes need escaped - by doubling them. *)
+let coq_escape_string s =
+ Str.global_replace (Str.regexp "\"") "\"\"" s
+
let doc_lit (L_aux(lit,l)) =
match lit with
| L_unit -> utf8string "tt"
@@ -570,7 +591,7 @@ let doc_lit (L_aux(lit,l)) =
| L_bin n -> failwith "Shouldn't happen" (*"(num_to_vec " ^ ("0b" ^ n) ^ ")" (*shouldn't happen*)*)
| L_undef ->
utf8string "(Fail \"undefined value of unsupported type\")"
- | L_string s -> utf8string ("\"" ^ s ^ "\"")
+ | L_string s -> utf8string ("\"" ^ (coq_escape_string s) ^ "\"")
| L_real s ->
(* Lem does not support decimal syntax, so we translate a string
of the form "x.y" into the ratio (x * 10^len(y) + y) / 10^len(y).
@@ -584,24 +605,31 @@ let doc_lit (L_aux(lit,l)) =
let denom = Big_int.pow_int_positive 10 (String.length f) in
(Big_int.add (Big_int.mul (Big_int.of_string i) denom) (Big_int.of_string f), denom)
| _ ->
- raise (Reporting_basic.Fatal_error
- (Reporting_basic.Err_syntax_locn (l, "could not parse real literal"))) in
+ raise (Reporting.Fatal_error
+ (Reporting.Err_syntax_locn (l, "could not parse real literal"))) in
parens (separate space (List.map string [
"realFromFrac"; Big_int.to_string num; Big_int.to_string denom]))
let doc_quant_item_id ctx delimit (QI_aux (qi,_)) =
match qi with
- | QI_id (KOpt_aux (KOpt_none kid,_)) ->
- if KBindings.mem kid ctx.kid_id_renames then None else
- Some (delimit (separate space [doc_var ctx kid; colon; string "Z"]))
- | QI_id (KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (kind,_)],_),kid),_)) -> begin
+ | QI_id (KOpt_aux (KOpt_kind (K_aux (kind,_),kid),_)) -> begin
if KBindings.mem kid ctx.kid_id_renames then None else
match kind with
- | BK_type -> Some (delimit (separate space [doc_var ctx kid; colon; string "Type"]))
- | BK_int -> Some (delimit (separate space [doc_var ctx kid; colon; string "Z"]))
- | BK_order -> None
+ | K_type -> Some (delimit (separate space [doc_var ctx kid; colon; string "Type"]))
+ | K_int -> Some (delimit (separate space [doc_var ctx kid; colon; string "Z"]))
+ | K_order -> None
+ end
+ | QI_const nc -> None
+
+let quant_item_id_name ctx (QI_aux (qi,_)) =
+ match qi with
+ | QI_id (KOpt_aux (KOpt_kind (K_aux (kind,_),kid),_)) -> begin
+ if KBindings.mem kid ctx.kid_id_renames then None else
+ match kind with
+ | K_type -> Some (doc_var ctx kid)
+ | K_int -> Some (doc_var ctx kid)
+ | K_order -> None
end
- | QI_id _ -> failwith "Quantifier with multiple kinds"
| QI_const nc -> None
let doc_quant_item_constr ctx delimit (QI_aux (qi,_)) =
@@ -609,6 +637,13 @@ let doc_quant_item_constr ctx delimit (QI_aux (qi,_)) =
| QI_id _ -> None
| QI_const nc -> Some (bquote ^^ braces (doc_arithfact ctx nc))
+(* At the moment these are all anonymous - when used we rely on Coq to fill
+ them in. *)
+let quant_item_constr_name ctx (QI_aux (qi,_)) =
+ match qi with
+ | QI_id _ -> None
+ | QI_const nc -> Some underscore
+
let doc_typquant_items ctx delimit (TypQ_aux (tq,_)) =
match tq with
| TypQ_tq qis ->
@@ -623,6 +658,14 @@ let doc_typquant_items_separate ctx delimit (TypQ_aux (tq,_)) =
Util.map_filter (doc_quant_item_constr ctx delimit) qis
| TypQ_no_forall -> [], []
+let typquant_names_separate ctx (TypQ_aux (tq,_)) =
+ match tq with
+ | TypQ_tq qis ->
+ Util.map_filter (quant_item_id_name ctx) qis,
+ Util.map_filter (quant_item_constr_name ctx) qis
+ | TypQ_no_forall -> [], []
+
+
let doc_typquant ctx (TypQ_aux(tq,_)) typ = match tq with
| TypQ_tq ((_ :: _) as qs) ->
string "forall " ^^ separate_opt space (doc_quant_item_id ctx braces) qs ^/^
@@ -641,10 +684,10 @@ let rec typeclass_nexps (Typ_aux(t,l)) =
| Typ_fn (t1,t2,_) -> List.fold_left NexpSet.union (typeclass_nexps t2) (List.map typeclass_nexps t1)
| Typ_tup ts -> List.fold_left NexpSet.union NexpSet.empty (List.map typeclass_nexps ts)
| Typ_app (Id_aux (Id "vector",_),
- [Typ_arg_aux (Typ_arg_nexp size_nexp,_);
- _;Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)])
+ [A_aux (A_nexp size_nexp,_);
+ _;A_aux (A_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)])
| Typ_app (Id_aux (Id "itself",_),
- [Typ_arg_aux (Typ_arg_nexp size_nexp,_)]) ->
+ [A_aux (A_nexp size_nexp,_)]) ->
let size_nexp = nexp_simp size_nexp in
if is_nexp_constant size_nexp then NexpSet.empty else
NexpSet.singleton (orig_nexp size_nexp)
@@ -663,7 +706,7 @@ let is_ctor env id = match Env.lookup_id id env with
let is_auto_decomposed_exist env typ =
let typ = expand_range_type typ in
- match destruct_exist env typ with
+ match destruct_exist_plain (Env.expand_synonyms env typ) with
| Some (_, _, typ') -> Some typ'
| _ -> None
@@ -689,8 +732,7 @@ let rec doc_pat ctxt apat_needed exists_as_pairs (P_aux (p,(l,annot)) as pat, ty
let arg_typs =
match Env.expand_synonyms env ctor_typ with
| Typ_aux (Typ_fn (arg_typs, ret_typ, _), _) ->
- (* The FIXME comes from the typechecker code, not sure what it's about... *)
- let unifiers, _, _ (* FIXME! *) = unify l env ret_typ typ in
+ let unifiers = unify l env (tyvars_of_typ ret_typ) ret_typ typ in
List.map (subst_unifiers unifiers) arg_typs
| _ -> assert false
in
@@ -720,34 +762,34 @@ let rec doc_pat ctxt apat_needed exists_as_pairs (P_aux (p,(l,annot)) as pat, ty
let el_typ =
match destruct_vector env typ with
| Some (_,_,t) -> t
- | None -> raise (Reporting_basic.err_unreachable l __POS__ "vector pattern doesn't have vector type")
+ | None -> raise (Reporting.err_unreachable l __POS__ "vector pattern doesn't have vector type")
in
let ppp = brackets (separate_map semi (fun p -> doc_pat ctxt true exists_as_pairs (p,el_typ)) pats) in
if apat_needed then parens ppp else ppp
| P_vector_concat pats ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"vector concatenation patterns should have been removed before pretty-printing")
| P_tup pats ->
let typs = match typ with
| Typ_aux (Typ_tup typs, _) -> typs
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "tuple pattern doesn't have tuple type")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "tuple pattern doesn't have tuple type")
in
(match pats, typs with
- | [p], [typ'] -> doc_pat ctxt apat_needed exists_as_pairs (p, typ')
- | [_], _ -> raise (Reporting_basic.err_unreachable l __POS__ "tuple pattern length does not match tuple type length")
- | _ -> parens (separate_map comma_sp (doc_pat ctxt false exists_as_pairs) (List.combine pats typs)))
+ | [p], [typ'] -> doc_pat ctxt apat_needed true (p, typ')
+ | [_], _ -> raise (Reporting.err_unreachable l __POS__ "tuple pattern length does not match tuple type length")
+ | _ -> parens (separate_map comma_sp (doc_pat ctxt false true) (List.combine pats typs)))
| P_list pats ->
let el_typ = match typ with
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_typ el_typ,_)]),_)
+ | Typ_aux (Typ_app (f, [A_aux (A_typ el_typ,_)]),_)
when Id.compare f (mk_id "list") = 0 -> el_typ
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "list pattern not a list")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "list pattern not a list")
in
brackets (separate_map semi (fun p -> doc_pat ctxt false true (p, el_typ)) pats)
| P_cons (p,p') ->
let el_typ = match typ with
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_typ el_typ,_)]),_)
+ | Typ_aux (Typ_app (f, [A_aux (A_typ el_typ,_)]),_)
when Id.compare f (mk_id "list") = 0 -> el_typ
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "list pattern not a list")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "list pattern not a list")
in
doc_op (string "::") (doc_pat ctxt true true (p, el_typ)) (doc_pat ctxt true true (p', typ))
| P_string_append _ -> unreachable l __POS__
@@ -772,10 +814,10 @@ let find_e_ids exp =
let typ_id_of (Typ_aux (typ, l)) = match typ with
| Typ_id id -> id
- | Typ_app (register, [Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id id, _)), _)])
+ | Typ_app (register, [A_aux (A_typ (Typ_aux (Typ_id id, _)), _)])
when string_of_id register = "register" -> id
| Typ_app (id, _) -> id
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "failed to get type id")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "failed to get type id")
(* TODO: maybe Nexp_exp, division? *)
(* Evaluation of constant nexp subexpressions, because Coq will be able to do those itself *)
@@ -800,11 +842,18 @@ let rec nexp_const_eval (Nexp_aux (n,l) as nexp) =
(* Decide whether two nexps used in a vector size are similar; if not
a cast will be inserted *)
-let similar_nexps env n1 n2 =
+let similar_nexps ctxt env n1 n2 =
let rec same_nexp_shape (Nexp_aux (n1,_)) (Nexp_aux (n2,_)) =
match n1, n2 with
| Nexp_id _, Nexp_id _ -> true
- | Nexp_var k1, Nexp_var k2 -> prove env (nc_eq (nvar k1) (nvar k2))
+ (* TODO: this is really just an approximation to what we really want:
+ will the Coq types have the same names? We could probably do better
+ by tracking which existential kids are equal to bound kids. *)
+ | Nexp_var k1, Nexp_var k2 ->
+ Kid.compare k1 k2 == 0 ||
+ (prove env (nc_eq (nvar k1) (nvar k2)) && (
+ not (KidSet.mem k1 ctxt.bound_nvars) ||
+ not (KidSet.mem k2 ctxt.bound_nvars)))
| Nexp_constant c1, Nexp_constant c2 -> Nat_big_num.equal c1 c2
| Nexp_app (f1,args1), Nexp_app (f2,args2) ->
Id.compare f1 f2 == 0 && List.for_all2 same_nexp_shape args1 args2
@@ -850,16 +899,16 @@ let is_no_Z_proof_fn env id =
let replace_atom_return_type ret_typ =
(* TODO: more complex uses of atom *)
match ret_typ with
- | Typ_aux (Typ_app (Id_aux (Id "atom",_), [Typ_arg_aux (Typ_arg_nexp nexp,_)]),l) ->
+ | Typ_aux (Typ_app (Id_aux (Id "atom",_), [A_aux (A_nexp nexp,_)]),l) ->
let kid = mk_kid "_retval" in (* TODO: collision avoidance *)
- true, Typ_aux (Typ_exist ([kid], nc_eq (nvar kid) nexp, atom_typ (nvar kid)),Parse_ast.Generated l)
+ true, Typ_aux (Typ_exist ([mk_kopt K_int kid], nc_eq (nvar kid) nexp, atom_typ (nvar kid)),Parse_ast.Generated l)
| _ -> false, ret_typ
let is_range_from_atom env (Typ_aux (argty,_)) (Typ_aux (fnty,_)) =
match argty, fnty with
- | Typ_app(Id_aux (Id "atom", _), [Typ_arg_aux (Typ_arg_nexp nexp,_)]),
- Typ_app(Id_aux (Id "range", _), [Typ_arg_aux(Typ_arg_nexp low,_);
- Typ_arg_aux(Typ_arg_nexp high,_)]) ->
+ | Typ_app(Id_aux (Id "atom", _), [A_aux (A_nexp nexp,_)]),
+ Typ_app(Id_aux (Id "range", _), [A_aux(A_nexp low,_);
+ A_aux(A_nexp high,_)]) ->
Type_check.prove env (nc_and (nc_eq nexp low) (nc_eq nexp high))
| _ -> false
@@ -872,8 +921,13 @@ let general_typ_of_annot annot =
let general_typ_of (E_aux (_,annot)) = general_typ_of_annot annot
+let is_prefix s s' =
+ let l = String.length s in
+ String.length s' >= l &&
+ String.sub s' 0 l = s
+
let prefix_recordtype = true
-let report = Reporting_basic.err_unreachable
+let report = Reporting.err_unreachable
let doc_exp, doc_let =
let rec top_exp (ctxt : context) (aexp_needed : bool)
(E_aux (e, (l,annot)) as full_exp) =
@@ -895,7 +949,7 @@ let doc_exp, doc_let =
debug ctxt (lazy (" at type " ^ string_of_typ typ))
in
let typ = expand_range_type typ in
- match destruct_exist env typ with
+ match destruct_exist_plain typ with
| None -> epp
| Some _ ->
let epp = string "build_ex" ^/^ epp in
@@ -911,19 +965,19 @@ let doc_exp, doc_let =
| _ ->
let typ' = expand_range_type (Env.expand_synonyms (env_of exp) typ) in
let build_ex, out_typ =
- match destruct_exist env typ' with
+ match destruct_exist_plain typ' with
| Some (_,_,t) -> true, t
| None -> false, typ'
in
let in_typ = expand_range_type (Env.expand_synonyms (env_of exp) (typ_of exp)) in
- let in_typ = match destruct_exist env in_typ with Some (_,_,t) -> t | None -> in_typ in
+ let in_typ = match destruct_exist_plain in_typ with Some (_,_,t) -> t | None -> in_typ in
let autocast =
(* Avoid using helper functions which simplify the nexps *)
is_bitvector_typ in_typ && is_bitvector_typ out_typ &&
match in_typ, out_typ with
- | Typ_aux (Typ_app (_,[Typ_arg_aux (Typ_arg_nexp n1,_);_;_]),_),
- Typ_aux (Typ_app (_,[Typ_arg_aux (Typ_arg_nexp n2,_);_;_]),_) ->
- not (similar_nexps (env_of exp) n1 n2)
+ | Typ_aux (Typ_app (_,[A_aux (A_nexp n1,_);_;_]),_),
+ Typ_aux (Typ_app (_,[A_aux (A_nexp n2,_);_;_]),_) ->
+ not (similar_nexps ctxt (env_of exp) n1 n2)
| _ -> false
in
let exp_pp = expV (want_parens || autocast || build_ex) exp in
@@ -1002,7 +1056,7 @@ let doc_exp, doc_let =
| _ ->
liftR ((prefix 2 1) (string "write_reg") (doc_lexp_deref ctxt le ^/^ expY e)))
| E_vector_append(le,re) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_append should have been rewritten before pretty-printing")
| E_cons(le,re) -> doc_op (group (colon^^colon)) (expY le) (expY re)
| E_if(c,t,e) ->
@@ -1036,11 +1090,11 @@ let doc_exp, doc_let =
| (P_aux (P_var (P_aux (P_id id, _), _), _))
| (P_aux (P_id id, _))), _), _),
body), _), _), _)), _)), _) -> id, body
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ ("Unable to find loop variable in " ^ string_of_exp body)) in
+ | _ -> raise (Reporting.err_unreachable l __POS__ ("Unable to find loop variable in " ^ string_of_exp body)) in
let dir = match ord_exp with
| E_aux (E_lit (L_aux (L_false, _)), _) -> "_down"
| E_aux (E_lit (L_aux (L_true, _)), _) -> "_up"
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ ("Unexpected loop direction " ^ string_of_exp ord_exp))
+ | _ -> raise (Reporting.err_unreachable l __POS__ ("Unexpected loop direction " ^ string_of_exp ord_exp))
in
let combinator = if effectful (effect_of body) then "foreach_ZM" else "foreach_Z" in
let combinator = combinator ^ dir in
@@ -1069,7 +1123,7 @@ let doc_exp, doc_let =
(prefix 2 1 (group body_lambda) (expN body))
)
)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ | _ -> raise (Reporting.err_unreachable l __POS__
"Unexpected number of arguments for loop combinator")
end
| Id_aux (Id (("while" | "until") as combinator), _) ->
@@ -1106,7 +1160,7 @@ let doc_exp, doc_let =
(parens (prefix 2 1 (group lambda) (expN cond)))
(parens (prefix 2 1 (group lambda) (expN body))))
)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ | _ -> raise (Reporting.err_unreachable l __POS__
"Unexpected number of arguments for loop combinator")
end
| Id_aux (Id "early_return", _) ->
@@ -1129,24 +1183,52 @@ let doc_exp, doc_let =
doc_atomic_typ ctxt false (typ_of exp)] in
true, doc_op colon epp tannot in
if aexp_needed then parens tepp else tepp
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ | _ -> raise (Reporting.err_unreachable l __POS__
"Unexpected number of arguments for early_return builtin")
end
| _ ->
let env = env_of_annot (l,annot) in
let () = debug ctxt (lazy ("Function application " ^ string_of_id f)) in
- let call, is_extern, is_ctor =
- if Env.is_union_constructor f env then doc_id_ctor f, false, true else
+ let call, is_extern, is_ctor, is_rec =
+ if Env.is_union_constructor f env then doc_id_ctor f, false, true, false else
if Env.is_extern f env "coq"
- then string (Env.get_extern f env "coq"), true, false
- else doc_id f, false, false in
- let (tqs,fn_ty) = Env.get_val_spec_orig f env in
+ then string (Env.get_extern f env "coq"), true, false, false
+ else if IdSet.mem f ctxt.recursive_ids
+ then doc_id f, false, false, true
+ else doc_id f, false, false, false in
+ let (tqs,fn_ty) = Env.get_val_spec f env in
+ (* Calculate the renaming *)
+ let tqs_map = List.fold_left
+ (fun m k ->
+ let kid = kopt_kid k in
+ KBindings.add (orig_kid kid) kid m)
+ KBindings.empty (quant_kopts tqs) in
let arg_typs, ret_typ, eff = match fn_ty with
| Typ_aux (Typ_fn (arg_typs,ret_typ,eff),_) -> arg_typs, ret_typ, eff
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "Function not a function type")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "Function not a function type")
in
let inst =
- match instantiation_of_without_type full_exp with
+ (* We attempt to get an instantiation of the function signature's
+ type variables which agrees with Coq by
+ 1. using dummy variables with the expected type of each argument
+ (avoiding the inferred type, which might have (e.g.) stripped
+ out an existential quantifier)
+ 2. calculating the instantiation without using the expected
+ return type, so that we can work out if we need a cast around
+ the function call. *)
+ let dummy_args =
+ Util.list_mapi (fun i exp -> mk_id ("#coq#arg" ^ string_of_int i),
+ general_typ_of exp) args
+ in
+ let dummy_exp = mk_exp (E_app (f, List.map (fun (id,_) -> mk_exp (E_id id)) dummy_args)) in
+ let dummy_env = List.fold_left (fun env (id,typ) -> Env.add_local id (Immutable,typ) env) env dummy_args in
+ let inst_exp =
+ try infer_exp dummy_env dummy_exp
+ with ex ->
+ debug ctxt (lazy (" cannot infer dummy application " ^ Printexc.to_string ex));
+ full_exp
+ in
+ match instantiation_of_without_type inst_exp with
| x -> x
(* Not all function applications can be inferred, so try falling back to the
type inferred when we know the target type.
@@ -1154,7 +1236,8 @@ let doc_exp, doc_let =
to cast. *)
| exception _ -> instantiation_of full_exp
in
- let inst = KBindings.fold (fun k u m -> KBindings.add (orig_kid k) u m) inst KBindings.empty in
+ let inst = KBindings.fold (fun k u m -> KBindings.add (KBindings.find (orig_kid k) tqs_map) u m) inst KBindings.empty in
+ let () = debug ctxt (lazy (" instantiations: " ^ String.concat ", " (List.map (fun (kid,tyarg) -> string_of_kid kid ^ " => " ^ string_of_typ_arg tyarg) (KBindings.bindings inst)))) in
(* Insert existential packing of arguments where necessary *)
let doc_arg want_parens arg typ_from_fn =
@@ -1174,24 +1257,48 @@ let doc_exp, doc_let =
(* Avoid using helper functions which simplify the nexps *)
is_bitvector_typ typ_of_arg' && is_bitvector_typ typ_from_fn' &&
match typ_of_arg', typ_from_fn' with
- | Typ_aux (Typ_app (_,[Typ_arg_aux (Typ_arg_nexp n1,_);_;_]),_),
- Typ_aux (Typ_app (_,[Typ_arg_aux (Typ_arg_nexp n2,_);_;_]),_) ->
- not (similar_nexps env n1 n2)
+ | Typ_aux (Typ_app (_,[A_aux (A_nexp n1,_);_;_]),_),
+ Typ_aux (Typ_app (_,[A_aux (A_nexp n2,_);_;_]),_) ->
+ not (similar_nexps ctxt env n1 n2)
| _ -> false
in
- let want_parens1 = want_parens || autocast in
- let arg_pp =
- construct_dep_pairs env want_parens1 arg typ_from_fn
+ (* If the argument is an integer that can be inferred from the
+ context in a different form, let Coq fill it in. E.g.,
+ when "64" is really "8 * width". Avoid cases where the
+ type checker has introduced a phantom type variable while
+ calculating the instantiations. *)
+ let vars_in_env n =
+ let ekids = Env.get_typ_vars env in
+ KidSet.for_all (fun kid -> KBindings.mem kid ekids) (nexp_frees n)
in
- if autocast && false
- then let arg_pp = string "autocast" ^^ space ^^ arg_pp in
- if want_parens then parens arg_pp else arg_pp
- else arg_pp
+ match typ_of_arg, typ_from_fn with
+ | Typ_aux (Typ_app (Id_aux (Id "atom",_),[A_aux (A_nexp n1,_)]),_),
+ Typ_aux (Typ_app (Id_aux (Id "atom",_),[A_aux (A_nexp n2,_)]),_)
+ when vars_in_env n2 && not (similar_nexps ctxt env n1 n2) ->
+ underscore
+ | _ ->
+ let want_parens1 = want_parens || autocast in
+ let arg_pp =
+ construct_dep_pairs env want_parens1 arg typ_from_fn
+ in
+ if autocast && false
+ then let arg_pp = string "autocast" ^^ space ^^ arg_pp in
+ if want_parens then parens arg_pp else arg_pp
+ else arg_pp
in
let epp =
if is_ctor
then hang 2 (call ^^ break 1 ^^ parens (flow (comma ^^ break 1) (List.map2 (doc_arg false) args arg_typs)))
- else hang 2 (flow (break 1) (call :: List.map2 (doc_arg true) args arg_typs)) in
+ else
+ let main_call = call :: List.map2 (doc_arg true) args arg_typs in
+ let all =
+ if is_rec then main_call @
+ [parens (string "_limit_reduces _acc")]
+ else match f with
+ | Id_aux (Id x,_) when is_prefix "#rec#" x ->
+ main_call @ [parens (string "Zwf_well_founded _ _")]
+ | _ -> main_call
+ in hang 2 (flow (break 1) all) in
(* Decide whether to unpack an existential result, pack one, or cast.
To do this we compare the expected type stored in the checked expression
@@ -1224,9 +1331,9 @@ let doc_exp, doc_let =
(* Avoid using helper functions which simplify the nexps *)
is_bitvector_typ in_typ && is_bitvector_typ out_typ &&
match in_typ, out_typ with
- | Typ_aux (Typ_app (_,[Typ_arg_aux (Typ_arg_nexp n1,_);_;_]),_),
- Typ_aux (Typ_app (_,[Typ_arg_aux (Typ_arg_nexp n2,_);_;_]),_) ->
- not (similar_nexps env n1 n2)
+ | Typ_aux (Typ_app (_,[A_aux (A_nexp n1,_);_;_]),_),
+ Typ_aux (Typ_app (_,[A_aux (A_nexp n2,_);_;_]),_) ->
+ not (similar_nexps ctxt env n1 n2)
| _ -> false
in pack,unpack,autocast
in
@@ -1244,10 +1351,10 @@ let doc_exp, doc_let =
liftR (if aexp_needed then parens (align epp) else epp)
end
| E_vector_access (v,e) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_access should have been rewritten before pretty-printing")
| E_vector_subrange (v,e1,e2) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_subrange should have been rewritten before pretty-printing")
| E_field((E_aux(_,(l,fannot)) as fexp),id) ->
(match destruct_tannot fannot with
@@ -1322,9 +1429,9 @@ let doc_exp, doc_let =
(* Avoid using helper functions which simplify the nexps *)
is_bitvector_typ outer_typ' && is_bitvector_typ cast_typ' &&
match outer_typ', cast_typ' with
- | Typ_aux (Typ_app (_,[Typ_arg_aux (Typ_arg_nexp n1,_);_;_]),_),
- Typ_aux (Typ_app (_,[Typ_arg_aux (Typ_arg_nexp n2,_);_;_]),_) ->
- not (similar_nexps env n1 n2)
+ | Typ_aux (Typ_app (_,[A_aux (A_nexp n1,_);_;_]),_),
+ Typ_aux (Typ_app (_,[A_aux (A_nexp n2,_);_;_]),_) ->
+ not (similar_nexps ctxt env n1 n2)
| _ -> false
in
let effects = effectful (effect_of e) in
@@ -1332,7 +1439,11 @@ let doc_exp, doc_let =
if effects then
if inner_ex then
if cast_ex
- then string "derive_m" ^^ space ^^ epp
+ (* If the types are the same use the cast as a hint to Coq,
+ otherwise derive the new type from the old one. *)
+ then if alpha_equivalent env inner_typ cast_typ
+ then epp
+ else string "derive_m" ^^ space ^^ epp
else string "projT1_m" ^^ space ^^ epp
else if cast_ex
then string "build_ex_m" ^^ space ^^ epp
@@ -1358,8 +1469,8 @@ let doc_exp, doc_let =
in
if aexp_needed then parens epp else epp
| E_tuple exps ->
- parens (align (group (separate_map (comma ^^ break 1) expN exps)))
- | E_record(FES_aux(FES_Fexps(fexps,_),_)) ->
+ construct_dep_pairs (env_of_annot (l,annot)) true full_exp (general_typ_of full_exp)
+ | E_record fexps ->
let recordtyp = match destruct_tannot annot with
| Some (env, Typ_aux (Typ_id tid,_), _)
| Some (env, Typ_aux (Typ_app (tid, _), _), _) ->
@@ -1370,7 +1481,7 @@ let doc_exp, doc_let =
(semi_sp ^^ break 1)
(doc_fexp ctxt recordtyp) fexps)) in
if aexp_needed then parens epp else epp
- | E_record_update(e,(FES_aux(FES_Fexps(fexps,_),_))) ->
+ | E_record_update(e, fexps) ->
let recordtyp, env = match destruct_tannot annot with
| Some (env, Typ_aux (Typ_id tid,_), _)
| Some (env, Typ_aux (Typ_app (tid, _), _), _)
@@ -1402,7 +1513,7 @@ let doc_exp, doc_let =
let t = Env.base_typ_of (env_of full_exp) (typ_of full_exp) in
let start, (len, order, etyp) =
if is_vector_typ t then vector_start_index t, vector_typ_args_of t
- else raise (Reporting_basic.err_unreachable l __POS__
+ else raise (Reporting.err_unreachable l __POS__
"E_vector of non-vector type") in
let dir,dir_out = if is_order_inc order then (true,"true") else (false, "false") in
let expspp =
@@ -1427,10 +1538,10 @@ let doc_exp, doc_let =
(vepp,aexp_needed) in
if aexp_needed then parens (align epp) else epp
| E_vector_update(v,e1,e2) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_update should have been rewritten before pretty-printing")
| E_vector_update_subrange(v,e1,e2,e3) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_update should have been rewritten before pretty-printing")
| E_list exps ->
brackets (separate_map semi (expN) exps)
@@ -1451,7 +1562,7 @@ let doc_exp, doc_let =
(string "end)")) in
if aexp_needed then parens (align epp) else align epp
else
- raise (Reporting_basic.err_todo l "Warning: try-block around pure expression")
+ raise (Reporting.err_todo l "Warning: try-block around pure expression")
| E_throw e ->
let epp = liftR (separate space [string "throw"; expY e]) in
if aexp_needed then parens (align epp) else align epp
@@ -1460,7 +1571,7 @@ let doc_exp, doc_let =
let epp = liftR (separate space [string "assert_exp"; expY e1; expY e2]) in
if aexp_needed then parens (align epp) else align epp
| E_app_infix (e1,id,e2) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_app_infix should have been rewritten before pretty-printing")
| E_var(lexp, eq_exp, in_exp) ->
raise (report l __POS__ "E_vars should have been removed before pretty-printing")
@@ -1518,7 +1629,7 @@ let doc_exp, doc_let =
| P_aux (P_var (P_aux (P_typ (typ, P_aux (P_id id,_)),_),_),_)
when not (is_enum (env_of e1) id) ->
let full_typ = (expand_range_type typ) in
- let binder = match destruct_exist (env_of e1) full_typ with
+ let binder = match destruct_exist_plain (Env.expand_synonyms (env_of e1) full_typ) with
| Some _ ->
squote ^^ parens (separate space [string "existT"; underscore; doc_id id; underscore; colon; doc_typ ctxt typ])
| _ ->
@@ -1548,7 +1659,7 @@ let doc_exp, doc_let =
(match nexp_simp nexp with
| Nexp_aux (Nexp_constant i, _) -> doc_lit (L_aux (L_num i, l))
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"pretty-printing non-constant sizeof expressions to Lem not supported"))
| E_return r ->
let ret_monad = " : MR" in
@@ -1567,7 +1678,7 @@ let doc_exp, doc_let =
align (parens (string "early_return" ^//^ exp_pp ^//^ ta))
| E_constraint nc -> wrap_parens (doc_nc_exp ctxt nc)
| E_internal_value _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"unsupported internal expression encountered while pretty-printing")
and if_exp ctxt (elseif : bool) c t e =
let if_pp = string (if elseif then "else if" else "if") in
@@ -1620,7 +1731,7 @@ let doc_exp, doc_let =
group (prefix 3 1 (separate space [pipe; doc_pat ctxt false false (pat,typ);bigarrow])
(group (top_exp ctxt false e)))
| Pat_aux(Pat_when(_,_,_),(l,_)) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"guarded pattern expression should have been rewritten before pretty-printing")
and doc_lexp_deref ctxt ((LEXP_aux(lexp,(l,annot)))) = match lexp with
@@ -1630,10 +1741,66 @@ let doc_exp, doc_let =
| LEXP_cast (typ,id) -> doc_id (append_id id "_ref")
| LEXP_tup lexps -> parens (separate_map comma_sp (doc_lexp_deref ctxt) lexps)
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__ ("doc_lexp_deref: Unsupported lexp"))
+ raise (Reporting.err_unreachable l __POS__ ("doc_lexp_deref: Unsupported lexp"))
(* expose doc_exp and doc_let *)
in top_exp, let_exp
+(* FIXME: A temporary definition of List.init until 4.06 is more standard *)
+let list_init n f = Array.to_list (Array.init n f)
+
+let types_used_with_generic_eq defs =
+ let rec add_typ idset (Typ_aux (typ,_)) =
+ match typ with
+ | Typ_id id -> IdSet.add id idset
+ | Typ_app (id,args) ->
+ List.fold_left add_typ_arg (IdSet.add id idset) args
+ | Typ_tup ts -> List.fold_left add_typ idset ts
+ | _ -> idset
+ and add_typ_arg idset (A_aux (ta,_)) =
+ match ta with
+ | A_typ typ -> add_typ idset typ
+ | _ -> idset
+ in
+ let alg =
+ { (Rewriter.compute_exp_alg IdSet.empty IdSet.union) with
+ Rewriter.e_aux = fun ((typs,exp),annot) ->
+ let typs' =
+ match exp with
+ | E_app (f,[arg1;_]) ->
+ if Env.is_extern f (env_of_annot annot) "coq" then
+ let f' = Env.get_extern f (env_of_annot annot) "coq" in
+ if f' = "generic_eq" || f' = "generic_neq" then
+ add_typ typs (Env.expand_synonyms (env_of arg1) (typ_of arg1))
+ else typs
+ else typs
+ | _ -> typs
+ in typs', E_aux (exp,annot) }
+ in
+ let typs_req_funcl (FCL_aux (FCL_Funcl (_,pexp), _)) =
+ fst (Rewriter.fold_pexp alg pexp)
+ in
+ let typs_req_def = function
+ | DEF_kind _
+ | DEF_type _
+ | DEF_spec _
+ | DEF_fixity _
+ | DEF_overload _
+ | DEF_default _
+ | DEF_pragma _
+ | DEF_reg_dec _
+ -> IdSet.empty
+ | DEF_fundef (FD_aux (FD_function (_,_,_,fcls),_)) ->
+ List.fold_left IdSet.union IdSet.empty (List.map typs_req_funcl fcls)
+ | DEF_mapdef (MD_aux (_,(l,_)))
+ | DEF_scattered (SD_aux (_,(l,_)))
+ -> unreachable l __POS__ "Internal definition found in the Coq back-end"
+ | DEF_internal_mutrec _
+ -> unreachable Unknown __POS__ "Internal definition found in the Coq back-end"
+ | DEF_val lb ->
+ fst (Rewriter.fold_letbind alg lb)
+ in
+ List.fold_left IdSet.union IdSet.empty (List.map typs_req_def defs)
+
let doc_type_union ctxt typ_name (Tu_aux(Tu_ty_id(typ,id),_)) =
separate space [doc_id_ctor id; colon;
doc_typ ctxt typ; arrow; typ_name]
@@ -1643,8 +1810,9 @@ let rec doc_range (BF_aux(r,_)) = match r with
| BF_range(i1,i2) -> parens (doc_op comma (doc_int i1) (doc_int i2))
| BF_concat(ir1,ir2) -> (doc_range ir1) ^^ comma ^^ (doc_range ir2)
-let doc_typdef (TD_aux(td, (l, annot))) = match td with
- | TD_abbrev(id,nm,(TypSchm_aux (TypSchm_ts (typq, _), _) as typschm)) ->
+let doc_typdef generic_eq_types (TD_aux(td, (l, annot))) = match td with
+ | TD_abbrev(id,typq,A_aux (A_typ typ, _)) ->
+ let typschm = TypSchm_aux (TypSchm_ts (typq, typ), l) in
doc_op coloneq
(separate space [string "Definition"; doc_id_type id;
doc_typquant_items empty_ctxt parens typq;
@@ -1659,9 +1827,8 @@ let doc_typdef (TD_aux(td, (l, annot))) = match td with
let rectyp = match typq with
| TypQ_aux (TypQ_tq qs, _) ->
let quant_item = function
- | QI_aux (QI_id (KOpt_aux (KOpt_none kid, _)), l)
| QI_aux (QI_id (KOpt_aux (KOpt_kind (_, kid), _)), l) ->
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid, l)), l)]
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid, l)), l)]
| _ -> [] in
let targs = List.concat (List.map quant_item qs) in
mk_typ (Typ_app (id, targs))
@@ -1679,41 +1846,31 @@ let doc_typdef (TD_aux(td, (l, annot))) = match td with
space ^^ string "|})."
in
let updates_pp = separate hardline (List.map doc_update_field fs) in
- (* let doc_field (ftyp, fid) =
- let reftyp =
- mk_typ (Typ_app (Id_aux (Id "field_ref", Parse_ast.Unknown),
- [mk_typ_arg (Typ_arg_typ rectyp);
- mk_typ_arg (Typ_arg_typ ftyp)])) in
- let rfannot = doc_tannot empty_ctxt env false reftyp in
- let get, set =
- string "rec_val" ^^ dot ^^ fname fid,
- anglebars (space ^^ string "rec_val with " ^^
- (doc_op equals (fname fid) (string "v")) ^^ space) in
- let base_ftyp = match annot with
- | Some (env, _, _) -> Env.base_typ_of env ftyp
- | _ -> ftyp in
- let (start, is_inc) =
- try
- let start, (_, ord, _) = vector_start_index base_ftyp, vector_typ_args_of base_ftyp in
- match nexp_simp start with
- | Nexp_aux (Nexp_constant i, _) -> (i, is_order_inc ord)
- | _ ->
- raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__
- ("register " ^ string_of_id id ^ " has non-constant start index " ^ string_of_nexp start))
- with
- | _ -> (Big_int.zero, true) in
- doc_op equals
- (concat [string "let "; parens (concat [doc_id id; underscore; doc_id fid; rfannot])])
- (anglebars (concat [space;
- doc_op equals (string "field_name") (string_lit (doc_id fid)); semi_sp;
- doc_op equals (string "field_start") (string (Big_int.to_string start)); semi_sp;
- doc_op equals (string "field_is_inc") (string (if is_inc then "true" else "false")); semi_sp;
- doc_op equals (string "get_field") (parens (doc_op arrow (string "fun rec_val") get)); semi_sp;
- doc_op equals (string "set_field") (parens (doc_op arrow (string "fun rec_val v") set)); space])) in *)
+ let id_pp = doc_id_type id in
+ let numfields = List.length fs in
+ let intros_pp s =
+ string " intros [" ^^
+ separate space (list_init numfields (fun n -> string (s ^ string_of_int n))) ^^
+ string "]." ^^ hardline
+ in
+ let eq_pp =
+ if IdSet.mem id generic_eq_types then
+ string "Instance Decidable_eq_" ^^ id_pp ^^ space ^^ colon ^/^
+ string "forall (x y : " ^^ id_pp ^^ string "), Decidable (x = y)." ^^
+ hardline ^^ intros_pp "x" ^^ intros_pp "y" ^^
+ separate hardline (list_init numfields
+ (fun n ->
+ let ns = string_of_int n in
+ string ("cmp_record_field x" ^ ns ^ " y" ^ ns ^ "."))) ^^
+ hardline ^^
+ string "refine (Build_Decidable _ true _). subst. split; reflexivity." ^^ hardline ^^
+ string "Defined." ^^ hardline
+ else empty
+ in
doc_op coloneq
- (separate space [string "Record"; doc_id_type id; doc_typquant_items empty_ctxt parens typq])
+ (separate space [string "Record"; id_pp; doc_typquant_items empty_ctxt parens typq])
((*doc_typquant typq*) (braces (space ^^ align fs_doc ^^ space))) ^^
- dot ^^ hardline ^^ updates_pp
+ dot ^^ hardline ^^ eq_pp ^^ updates_pp
| TD_variant(id,nm,typq,ar,_) ->
(match id with
| Id_aux ((Id "read_kind"),_) -> empty
@@ -1755,11 +1912,11 @@ let doc_typdef (TD_aux(td, (l, annot))) = match td with
(concat [string "Inductive"; space; id_pp])
(enums_doc) in
let eq1_pp = string "Scheme Equality for" ^^ space ^^ id_pp ^^ dot in
- let eq2_pp = string "Instance Decidable_eq_" ^^ id_pp ^^ space ^^ colon ^^ space ^^
+ let eq2_pp = string "Instance Decidable_eq_" ^^ id_pp ^^ space ^^ colon ^/^
string "forall (x y : " ^^ id_pp ^^ string "), Decidable (x = y) :=" ^/^
string "Decidable_eq_from_dec " ^^ id_pp ^^ string "_eq_dec." in
typ_pp ^^ dot ^^ hardline ^^ eq1_pp ^^ hardline ^^ eq2_pp ^^ hardline)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "register with non-constant indices")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "register with non-constant indices")
let args_of_typ l env typs =
let arg i typ =
@@ -1768,6 +1925,12 @@ let args_of_typ l env typs =
E_aux (E_id id, (l, mk_tannot env typ no_effect)) in
List.split (List.mapi arg typs)
+(* Sail currently has a single pattern to match against a list of
+ argument types. We need to tweak everything to match up,
+ especially so that the function is presented in curried form. In
+ particular, if there's a single binder for multiple arguments
+ (which rewriting can currently introduce) then we need to turn it
+ into multiple binders and reconstruct it in the function body. *)
let rec untuple_args_pat typs (P_aux (paux, ((l, _) as annot)) as pat) =
let env = env_of_annot annot in
let identity = (fun body -> body) in
@@ -1791,10 +1954,6 @@ let rec untuple_args_pat typs (P_aux (paux, ((l, _) as annot)) as pat) =
| _, _ ->
unreachable l __POS__ "Unexpected pattern/type combination"
-let doc_rec (Rec_aux(r,_)) = match r with
- | Rec_nonrec -> string "Definition"
- | Rec_rec -> string "Fixpoint"
-
let doc_fun_body ctxt exp =
let doc_exp = doc_exp ctxt false exp in
if ctxt.early_ret
@@ -1813,15 +1972,37 @@ let demote_as_pattern i (P_aux (_,p_annot) as pat,typ) =
E_aux (E_let (LB_aux (LB_val (pat, E_aux (E_id id, p_annot)),p_annot),e),e_ann)
else (pat,typ), fun e -> e
+let pat_is_plain_binder env (P_aux (p,_)) =
+ match p with
+ | P_id id
+ | P_typ (_,P_aux (P_id id,_))
+ when not (is_enum env id) -> Some id
+ | _ -> None
+
+let demote_all_patterns env i (P_aux (p,p_annot) as pat,typ) =
+ match pat_is_plain_binder env pat with
+ | Some id ->
+ if Util.is_none (is_auto_decomposed_exist env typ)
+ then (pat,typ), fun e -> e
+ else
+ (P_aux (P_id id, p_annot),typ),
+ fun (E_aux (_,e_ann) as e) ->
+ E_aux (E_let (LB_aux (LB_val (pat, E_aux (E_id id, p_annot)),p_annot),e),e_ann)
+ | None ->
+ let id = mk_id ("arg" ^ string_of_int i) in (* TODO: name conflicts *)
+ (P_aux (P_id id, p_annot),typ),
+ fun (E_aux (_,e_ann) as e) ->
+ E_aux (E_let (LB_aux (LB_val (pat, E_aux (E_id id, p_annot)),p_annot),e),e_ann)
+
(* Add equality constraints between arguments and nexps, except in the case
that they've been merged. *)
let rec atom_constraint ctxt (pat, typ) =
- let typ = Env.base_typ_of (pat_env_of pat) typ in
+ let typ = Env.base_typ_of (env_of_pat pat) typ in
match pat, typ with
| P_aux (P_id id, _),
Typ_aux (Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp nexp,_)]),_) ->
+ [A_aux (A_nexp nexp,_)]),_) ->
(match nexp with
(* When the kid is mapped to the id, we don't need a constraint *)
| Nexp_aux (Nexp_var kid,_)
@@ -1888,7 +2069,7 @@ let merge_kids_atoms pats =
| Some (Nexp_aux (Nexp_var kid,l)) ->
if KidSet.mem kid seen then
let () =
- Reporting_basic.print_err false true l "merge_kids_atoms"
+ Reporting.print_err false true l "merge_kids_atoms"
("want to merge tyvar and argument for " ^ string_of_kid kid ^
" but rearranging arguments isn't supported yet") in
gone,map,seen
@@ -1910,7 +2091,7 @@ let merge_var_patterns map pats =
| _ -> map, (pat,typ)::pats) (map,[]) pats
in map, List.rev pats
-let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) =
+let doc_funcl rec_opt (FCL_aux(FCL_Funcl(id, pexp), annot)) =
let env = env_of_annot annot in
let (tq,typ) = Env.get_val_spec_orig id env in
let (arg_typs, ret_typ, eff) = match typ with
@@ -1918,24 +2099,38 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) =
| _ -> failwith ("Function " ^ string_of_id id ^ " does not have function type")
in
let build_ex, ret_typ = replace_atom_return_type ret_typ in
- let build_ex = match destruct_exist env (expand_range_type ret_typ) with
+ let build_ex = match destruct_exist_plain (Env.expand_synonyms env (expand_range_type ret_typ)) with
| Some _ -> true
| _ -> build_ex
in
let ids_to_avoid = all_ids pexp in
let bound_kids = tyvars_of_typquant tq in
let pat,guard,exp,(l,_) = destruct_pexp pexp in
- let pats, bind = untuple_args_pat arg_typs pat in (* FIXME is this needed any more? *)
- let pats, binds = List.split (Util.list_mapi demote_as_pattern pats) in
+ let pats, bind = untuple_args_pat arg_typs pat in
+ (* Fixpoint definitions can only use simple binders, but even Definitions
+ can't handle as patterns *)
+ let pattern_elim =
+ match rec_opt with
+ | Rec_aux (Rec_nonrec,_) -> demote_as_pattern
+ | _ -> demote_all_patterns env
+ in
+ let pats, binds = List.split (Util.list_mapi pattern_elim pats) in
let eliminated_kids, kid_to_arg_rename = merge_kids_atoms pats in
let kid_to_arg_rename, pats = merge_var_patterns kid_to_arg_rename pats in
let kids_used = KidSet.diff bound_kids eliminated_kids in
+ let is_measured, recursive_ids = match rec_opt with
+ (* No mutual recursion in this backend yet; only change recursive
+ definitions where we have a measure *)
+ | Rec_aux (Rec_measure _,_) -> true, IdSet.singleton id
+ | _ -> false, IdSet.empty
+ in
let ctxt =
{ early_ret = contains_early_return exp;
kid_renames = mk_kid_renames ids_to_avoid kids_used;
kid_id_renames = kid_to_arg_rename;
bound_nvars = bound_kids;
build_ex_return = effectful eff && build_ex;
+ recursive_ids = recursive_ids;
debug = List.mem (string_of_id id) (!opt_debug_on)
} in
let () =
@@ -1956,48 +2151,32 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) =
debug ctxt (lazy (" pattern " ^ string_of_pat pat));
debug ctxt (lazy (" with expanded type " ^ string_of_typ exp_typ))
in
- match p with
- | P_id id
- | P_typ (_,P_aux (P_id id,_))
- when Util.is_none (is_auto_decomposed_exist env exp_typ) &&
- not (is_enum env id) ->
- parens (separate space [doc_id id; colon; doc_typ ctxt typ])
-(* | P_id id
- | P_typ (_,P_aux (P_id id,_))
- when not (is_enum env id) -> begin
- match destruct_exist env (expand_range_type exp_typ) with
- | Some (kids, NC_aux (NC_true,_), typ) ->
- parens (separate space [doc_id id; colon; doc_typ ctxt typ])
- | Some (kids, nc, typ) ->
- parens (separate space [doc_id id; colon; doc_typ ctxt typ]) ^^ space ^^
- bquote ^^ braces (doc_arithfact ctxt nc)
- | None ->
- parens (separate space [doc_id id; colon; doc_typ ctxt typ])
- end*)
- | P_id id
- | P_typ (_,P_aux (P_id id,_))
- when not (is_enum env id) -> begin
+ match pat_is_plain_binder env pat with
+ | Some id ->
+ if Util.is_none (is_auto_decomposed_exist env exp_typ) then
+ parens (separate space [doc_id id; colon; doc_typ ctxt typ])
+ else begin
let full_typ = (expand_range_type exp_typ) in
- match destruct_exist env full_typ with
- | Some ([kid], NC_aux (NC_true,_),
+ match destruct_exist_plain (Env.expand_synonyms env full_typ) with
+ | Some ([kopt], NC_aux (NC_true,_),
Typ_aux (Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid',_)),_)]),_))
- when Kid.compare kid kid' == 0 ->
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid,_)),_)]),_))
+ when Kid.compare (kopt_kid kopt) kid == 0 ->
parens (separate space [doc_id id; colon; string "Z"])
- | Some ([kid], nc,
+ | Some ([kopt], nc,
Typ_aux (Typ_app (Id_aux (Id "atom",_),
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid',_)),_)]),_))
- when Kid.compare kid kid' == 0 ->
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid,_)),_)]),_))
+ when Kid.compare (kopt_kid kopt) kid == 0 && not is_measured ->
(used_a_pattern := true;
squote ^^ parens (separate space [string "existT"; underscore; doc_id id; underscore; colon; doc_typ ctxt typ]))
| _ ->
parens (separate space [doc_id id; colon; doc_typ ctxt typ])
end
- | _ ->
+ | None ->
(used_a_pattern := true;
squote ^^ parens (separate space [doc_pat ctxt true true (pat, exp_typ); colon; doc_typ ctxt typ]))
in
- let patspp = separate_map space doc_binder pats in
+ let patspp = flow_map (break 1) doc_binder pats in
let atom_constrs = Util.map_filter (atom_constraint ctxt) pats in
let atom_constr_pp = separate space atom_constrs in
let retpp =
@@ -2006,6 +2185,31 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) =
else doc_typ ctxt ret_typ
in
let idpp = doc_id id in
+ let intropp, accpp, measurepp, fixupspp = match rec_opt with
+ | Rec_aux (Rec_measure _,_) ->
+ let fixupspp =
+ Util.map_filter (fun (pat,typ) ->
+ match pat_is_plain_binder env pat with
+ | Some id -> begin
+ match destruct_exist_plain (Env.expand_synonyms env (expand_range_type typ)) with
+ | Some (_, NC_aux (NC_true,_), _) -> None
+ | Some ([KOpt_aux (KOpt_kind (_, kid), _)], nc,
+ Typ_aux (Typ_app (Id_aux (Id "atom",_),
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid',_)),_)]),_))
+ when Kid.compare kid kid' == 0 ->
+ Some (string "let " ^^ doc_id id ^^ string " := projT1 " ^^ doc_id id ^^ string " in")
+ | _ -> None
+ end
+ | None -> None) pats
+ in
+ string "Fixpoint",
+ [parens (string "_acc : Acc (Zwf 0) _reclimit")],
+ [string "{struct _acc}"],
+ fixupspp
+ | Rec_aux (r,_) ->
+ let d = match r with Rec_nonrec -> "Definition" | _ -> "Fixpoint" in
+ string d, [], [], []
+ in
(* Work around Coq bug 7975 about pattern binders followed by implicit arguments *)
let implicitargs =
if !used_a_pattern && List.length constrspp + List.length atom_constrs > 0 then
@@ -2021,13 +2225,14 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) =
let _ = match guard with
| None -> ()
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"guarded pattern expression should have been rewritten before pretty-printing") in
let bodypp = doc_fun_body ctxt exp in
let bodypp = if effectful eff || not build_ex then bodypp else string "build_ex" ^^ parens bodypp in
+ let bodypp = separate (break 1) fixupspp ^/^ bodypp in
group (prefix 3 1
- (separate space ([idpp] @ quantspp @ [patspp] @ constrspp @ [atom_constr_pp]) ^/^
- separate space [colon; retpp; coloneq])
+ (flow (break 1) ([intropp; idpp] @ quantspp @ [patspp] @ constrspp @ [atom_constr_pp] @ accpp) ^/^
+ flow (break 1) (measurepp @ [colon; retpp; coloneq]))
(bodypp ^^ dot)) ^^ implicitargs
let get_id = function
@@ -2038,7 +2243,7 @@ let get_id = function
joined by "and", although it has worked for Isabelle before. However, all
the funcls should have been merged by the merge_funcls rewrite now. *)
let doc_fundef_rhs (FD_aux(FD_function(r, typa, efa, funcls),fannot)) =
- separate_map (hardline ^^ string "and ") doc_funcl funcls
+ separate_map (hardline ^^ string "and ") (doc_funcl r) funcls
let doc_mutrec = function
| [] -> failwith "DEF_internal_mutrec with empty function list"
@@ -2051,7 +2256,7 @@ let rec doc_fundef (FD_aux(FD_function(r, typa, efa, fcls),fannot)) =
| [] -> failwith "FD_function with empty function list"
| [FCL_aux (FCL_Funcl(id,_),annot) as funcl]
when not (Env.is_extern id (env_of_annot annot) "coq") ->
- (doc_rec r) ^^ space ^^ (doc_funcl funcl)
+ doc_funcl r funcl
| [_] -> empty (* extern *)
| _ -> failwith "FD_function with more than one clause"
@@ -2076,8 +2281,8 @@ let doc_dec (DEC_aux (reg, ((l, _) as annot))) =
string o;
string "[]"]))
^/^ hardline
- else raise (Reporting_basic.err_unreachable l __POS__ ("can't deal with register type " ^ string_of_typ typ))
- else raise (Reporting_basic.err_unreachable l __POS__ ("can't deal with register type " ^ string_of_typ typ)) *)
+ else raise (Reporting.err_unreachable l __POS__ ("can't deal with register type " ^ string_of_typ typ))
+ else raise (Reporting.err_unreachable l __POS__ ("can't deal with register type " ^ string_of_typ typ)) *)
| DEC_config _ -> empty
| DEC_alias(id,alspec) -> empty
| DEC_typ_alias(typ,id,alspec) -> empty
@@ -2094,7 +2299,7 @@ let is_field_accessor regtypes fdef =
let doc_regtype_fields (tname, (n1, n2, fields)) =
let i1, i2 = match n1, n2 with
| Nexp_aux(Nexp_constant i1,_),Nexp_aux(Nexp_constant i2,_) -> i1, i2
- | _ -> raise (Reporting_basic.err_typ Parse_ast.Unknown
+ | _ -> raise (Reporting.err_typ Parse_ast.Unknown
("Non-constant indices in register type " ^ tname)) in
let dir_b = i1 < i2 in
let dir = (if dir_b then "true" else "false") in
@@ -2102,7 +2307,7 @@ let doc_regtype_fields (tname, (n1, n2, fields)) =
let i, j = match fr with
| BF_aux (BF_single i, _) -> (i, i)
| BF_aux (BF_range (i, j), _) -> (i, j)
- | _ -> raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__
+ | _ -> raise (Reporting.err_unreachable Parse_ast.Unknown __POS__
("Unsupported type in field " ^ string_of_id fid ^ " of " ^ tname)) in
let fsize = Big_int.succ (Big_int.abs (Big_int.sub i j)) in
(* TODO Assumes normalised, decreasing bitvector slices; however, since
@@ -2111,8 +2316,8 @@ let doc_regtype_fields (tname, (n1, n2, fields)) =
let ftyp = vector_typ (nconstant fsize) dec_ord bit_typ in
let reftyp =
mk_typ (Typ_app (Id_aux (Id "field_ref", Parse_ast.Unknown),
- [mk_typ_arg (Typ_arg_typ (mk_id_typ (mk_id tname)));
- mk_typ_arg (Typ_arg_typ ftyp)])) in
+ [mk_typ_arg (A_typ (mk_id_typ (mk_id tname)));
+ mk_typ_arg (A_typ ftyp)])) in
let rfannot = doc_tannot empty_ctxt Env.empty false reftyp in
doc_op equals
(concat [string "let "; parens (concat [string tname; underscore; doc_id fid; rfannot])])
@@ -2184,7 +2389,7 @@ let doc_val pat exp =
id, None
| P_aux (P_typ (typ, P_aux (P_var (P_aux (P_id id, _), TP_aux (TP_var kid, _)),_)),_) when Id.compare id (id_of_kid kid) == 0 ->
id, Some typ
- | _ -> raise (Reporting_basic.err_todo (pat_loc pat)
+ | _ -> raise (Reporting.err_todo (pat_loc pat)
"Top-level value definition with complex pattern not supported for Coq yet")
in
let typpp = match pat_typ with
@@ -2198,7 +2403,7 @@ let doc_val pat exp =
| None -> typpp, exp
| Some typ ->
let typ = expand_range_type (Env.expand_synonyms env typ) in
- match destruct_exist env typ with
+ match destruct_exist_plain typ with
| None -> typpp, exp
| Some _ ->
empty, match exp with
@@ -2210,13 +2415,13 @@ let doc_val pat exp =
group (string "Definition" ^^ space ^^ idpp ^^ typpp ^^ space ^^ coloneq ^/^ base_pp) ^^ hardline ^^
group (separate space [string "Hint Unfold"; idpp; colon; string "sail."]) ^^ hardline
-let rec doc_def unimplemented def =
+let rec doc_def unimplemented generic_eq_types def =
(* let _ = Pretty_print_sail.pp_defs stderr (Defs [def]) in *)
match def with
| DEF_spec v_spec -> doc_val_spec unimplemented v_spec
| DEF_fixity _ -> empty
| DEF_overload _ -> empty
- | DEF_type t_def -> group (doc_typdef t_def) ^/^ hardline
+ | DEF_type t_def -> group (doc_typdef generic_eq_types t_def) ^/^ hardline
| DEF_reg_dec dec -> group (doc_dec dec)
| DEF_default df -> empty
@@ -2226,6 +2431,7 @@ let rec doc_def unimplemented def =
| DEF_scattered sdef -> failwith "doc_def: shoulnd't have DEF_scattered at this point"
| DEF_mapdef (MD_aux (_, (l,_))) -> unreachable l __POS__ "Coq doesn't support mappings"
| DEF_kind _ -> empty
+ | DEF_pragma _ -> empty
let find_exc_typ defs =
let is_exc_typ_def = function
@@ -2271,8 +2477,10 @@ try
let statedefs, defs = List.partition is_state_def defs in
let register_refs = State.register_refs_coq (State.find_registers defs) in
let unimplemented = find_unimplemented defs in
+ let generic_eq_types = types_used_with_generic_eq defs in
+ let doc_def = doc_def unimplemented generic_eq_types in
let () = if !opt_undef_axioms || IdSet.is_empty unimplemented then () else
- Reporting_basic.print_err false false Parse_ast.Unknown "Warning"
+ Reporting.print_err false false Parse_ast.Unknown "Warning"
("The following functions were declared but are undefined:\n" ^
String.concat "\n" (List.map string_of_id (IdSet.elements unimplemented)))
in
@@ -2281,9 +2489,9 @@ try
[string "(*" ^^ (string top_line) ^^ string "*)";hardline;
(separate_map hardline)
(fun lib -> separate space [string "Require Import";string lib] ^^ dot) types_modules;hardline;
- separate empty (List.map (doc_def unimplemented) typdefs); hardline;
+ separate empty (List.map doc_def typdefs); hardline;
hardline;
- separate empty (List.map (doc_def unimplemented) statedefs); hardline;
+ separate empty (List.map doc_def statedefs); hardline;
hardline;
register_refs; hardline;
concat [
@@ -2305,7 +2513,7 @@ try
string "Section Content.";
hardline;
hardline;
- separate empty (List.map (doc_def unimplemented) defs);
+ separate empty (List.map doc_def defs);
hardline;
string "End Content.";
hardline])
@@ -2316,4 +2524,4 @@ with Type_check.Type_error (l,err) ->
then "\n" ^ Printexc.get_backtrace ()
else "(backtracing unavailable)"
in
- raise (Reporting_basic.err_typ l (Type_error.string_of_type_error err ^ extra))
+ raise (Reporting.err_typ l (Type_error.string_of_type_error err ^ extra))
diff --git a/src/pretty_print_lem.ml b/src/pretty_print_lem.ml
index ba2b797b..a3bd1bba 100644
--- a/src/pretty_print_lem.ml
+++ b/src/pretty_print_lem.ml
@@ -194,7 +194,7 @@ let doc_nexp_lem nexp =
| Nexp_exp n -> "exp_" ^ mangle_nexp n
| Nexp_neg n -> "neg_" ^ mangle_nexp n
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
("cannot pretty-print nexp \"" ^ string_of_nexp full_nexp ^ "\""))
end in
string ("'" ^ mangle_nexp full_nexp)
@@ -224,14 +224,14 @@ let rec lem_nexps_of_typ (Typ_aux (t,l)) =
List.fold_left (fun s t -> NexpSet.union s (trec t))
NexpSet.empty ts
| Typ_app(Id_aux (Id "vector", _), [
- Typ_arg_aux (Typ_arg_nexp m, _);
- Typ_arg_aux (Typ_arg_order ord, _);
- Typ_arg_aux (Typ_arg_typ elem_typ, _)]) ->
+ A_aux (A_nexp m, _);
+ A_aux (A_order ord, _);
+ A_aux (A_typ elem_typ, _)]) ->
let m = nexp_simp m in
if !opt_mwords && is_bit_typ elem_typ && not (is_nexp_constant m) then
NexpSet.singleton (orig_nexp m)
else trec elem_typ
- | Typ_app(Id_aux (Id "register", _), [Typ_arg_aux (Typ_arg_typ etyp, _)]) ->
+ | Typ_app(Id_aux (Id "register", _), [A_aux (A_typ etyp, _)]) ->
trec etyp
| Typ_app(Id_aux (Id "range", _),_)
| Typ_app(Id_aux (Id "implicit", _),_)
@@ -240,13 +240,14 @@ let rec lem_nexps_of_typ (Typ_aux (t,l)) =
List.fold_left (fun s ta -> NexpSet.union s (lem_nexps_of_typ_arg ta))
NexpSet.empty tas
| Typ_exist (kids,_,t) -> trec t
- | Typ_bidir _ -> raise (Reporting_basic.err_unreachable l __POS__ "Lem doesn't support bidir types")
- | Typ_internal_unknown -> raise (Reporting_basic.err_unreachable l __POS__ "escaped Typ_internal_unknown")
-and lem_nexps_of_typ_arg (Typ_arg_aux (ta,_)) =
+ | Typ_bidir _ -> raise (Reporting.err_unreachable l __POS__ "Lem doesn't support bidir types")
+ | Typ_internal_unknown -> raise (Reporting.err_unreachable l __POS__ "escaped Typ_internal_unknown")
+and lem_nexps_of_typ_arg (A_aux (ta,_)) =
match ta with
- | Typ_arg_nexp nexp -> NexpSet.singleton (nexp_simp (orig_nexp nexp))
- | Typ_arg_typ typ -> lem_nexps_of_typ typ
- | Typ_arg_order _ -> NexpSet.empty
+ | A_nexp nexp -> NexpSet.singleton (nexp_simp (orig_nexp nexp))
+ | A_typ typ -> lem_nexps_of_typ typ
+ | A_order _ -> NexpSet.empty
+ | A_bool _ -> NexpSet.empty
let lem_tyvars_of_typ typ =
NexpSet.fold (fun nexp ks -> KidSet.union ks (tyvars_of_nexp nexp))
@@ -274,28 +275,30 @@ let doc_typ_lem, doc_atomic_typ_lem =
| _ -> app_typ atyp_needed ty
and app_typ atyp_needed ((Typ_aux (t, l)) as ty) = match t with
| Typ_app(Id_aux (Id "vector", _), [
- Typ_arg_aux (Typ_arg_nexp m, _);
- Typ_arg_aux (Typ_arg_order ord, _);
- Typ_arg_aux (Typ_arg_typ elem_typ, _)]) ->
+ A_aux (A_nexp m, _);
+ A_aux (A_order ord, _);
+ A_aux (A_typ elem_typ, _)]) ->
let tpp = match elem_typ with
| Typ_aux (Typ_id (Id_aux (Id "bit",_)),_) when !opt_mwords ->
string "mword " ^^ doc_nexp_lem (nexp_simp m)
(* (match nexp_simp m with
| (Nexp_aux(Nexp_constant i,_)) -> string "bitvector ty" ^^ doc_int i
| (Nexp_aux(Nexp_var _, _)) -> separate space [string "bitvector"; doc_nexp m]
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ | _ -> raise (Reporting.err_unreachable l __POS__
"cannot pretty-print bitvector type with non-constant length")) *)
| _ -> string "list" ^^ space ^^ typ elem_typ in
if atyp_needed then parens tpp else tpp
- | Typ_app(Id_aux (Id "register", _), [Typ_arg_aux (Typ_arg_typ etyp, _)]) ->
+ | Typ_app(Id_aux (Id "register", _), [A_aux (A_typ etyp, _)]) ->
let tpp = string "register_ref regstate register_value " ^^ typ etyp in
if atyp_needed then parens tpp else tpp
| Typ_app(Id_aux (Id "range", _),_) ->
(string "integer")
| Typ_app(Id_aux (Id "implicit", _),_) ->
(string "integer")
- | Typ_app(Id_aux (Id "atom", _), [Typ_arg_aux(Typ_arg_nexp n,_)]) ->
+ | Typ_app(Id_aux (Id "atom", _), [A_aux(A_nexp n,_)]) ->
(string "integer")
+ | Typ_app(Id_aux (Id "atom_bool", _), [A_aux(A_bool nc,_)]) ->
+ (string "bool")
| Typ_app(id,args) ->
let tpp = (doc_id_lem_type id) ^^ space ^^ (separate_map space doc_typ_arg_lem args) in
if atyp_needed then parens tpp else tpp
@@ -313,22 +316,25 @@ let doc_typ_lem, doc_atomic_typ_lem =
* if we add a new Typ constructor *)
let tpp = typ ty in
if atyp_needed then parens tpp else tpp
- | Typ_exist (kids,_,ty) -> begin
+ | Typ_exist (kopts,_,ty) when List.for_all is_nat_kopt kopts -> begin
+ let kids = List.map kopt_kid kopts in
let tpp = typ ty in
let visible_vars = lem_tyvars_of_typ ty in
match List.filter (fun kid -> KidSet.mem kid visible_vars) kids with
| [] -> if atyp_needed then parens tpp else tpp
- | bad -> raise (Reporting_basic.err_general l
+ | bad -> raise (Reporting.err_general l
("Existential type variable(s) " ^
String.concat ", " (List.map string_of_kid bad) ^
" escape into Lem"))
end
+ | Typ_exist _ -> unreachable l __POS__ "Non-integer existentials currently unsupported in Lem" (* TODO *)
| Typ_bidir _ -> unreachable l __POS__ "Lem doesn't support bidir types"
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
- and doc_typ_arg_lem (Typ_arg_aux(t,_)) = match t with
- | Typ_arg_typ t -> app_typ true t
- | Typ_arg_nexp n -> doc_nexp_lem (nexp_simp n)
- | Typ_arg_order o -> empty
+ and doc_typ_arg_lem (A_aux(t,_)) = match t with
+ | A_typ t -> app_typ true t
+ | A_nexp n -> doc_nexp_lem (nexp_simp n)
+ | A_order o -> empty
+ | A_bool _ -> empty
in typ', atomic_typ
(* Check for variables in types that would be pretty-printed. *)
@@ -338,10 +344,10 @@ let contains_t_pp_var ctxt (Typ_aux (t,a) as typ) =
let replace_typ_size ctxt env (Typ_aux (t,a)) =
match t with
- | Typ_app (Id_aux (Id "vector",_) as id, [Typ_arg_aux (Typ_arg_nexp size,_);ord;typ']) ->
+ | Typ_app (Id_aux (Id "vector",_) as id, [A_aux (A_nexp size,_);ord;typ']) ->
begin
let mk_typ nexp =
- Some (Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp nexp,Parse_ast.Unknown);ord;typ']),a))
+ Some (Typ_aux (Typ_app (id, [A_aux (A_nexp nexp,Parse_ast.Unknown);ord;typ']),a))
in
match Type_check.solve env size with
| Some n -> mk_typ (nconstant n)
@@ -391,7 +397,7 @@ let doc_lit_lem (L_aux(lit,l)) =
| L_bin n -> failwith "Shouldn't happen" (*"(num_to_vec " ^ ("0b" ^ n) ^ ")" (*shouldn't happen*)*)
| L_undef ->
utf8string "(return (failwith \"undefined value of unsupported type\"))"
- | L_string s -> utf8string ("\"" ^ s ^ "\"")
+ | L_string s -> utf8string ("\"" ^ (String.escaped s) ^ "\"")
| L_real s ->
(* Lem does not support decimal syntax, so we translate a string
of the form "x.y" into the ratio (x * 10^len(y) + y) / 10^len(y).
@@ -405,14 +411,13 @@ let doc_lit_lem (L_aux(lit,l)) =
let denom = Big_int.pow_int_positive 10 (String.length f) in
(Big_int.add (Big_int.mul (Big_int.of_string i) denom) (Big_int.of_string f), denom)
| _ ->
- raise (Reporting_basic.Fatal_error
- (Reporting_basic.Err_syntax_locn (l, "could not parse real literal"))) in
+ raise (Reporting.Fatal_error
+ (Reporting.Err_syntax_locn (l, "could not parse real literal"))) in
parens (separate space (List.map string [
"realFromFrac"; Big_int.to_string num; Big_int.to_string denom]))
(* typ_doc is the doc for the type being quantified *)
let doc_quant_item vars_included (QI_aux (qi, _)) = match qi with
-| QI_id (KOpt_aux (KOpt_none kid, _))
| QI_id (KOpt_aux (KOpt_kind (_, kid), _)) ->
(match vars_included with
None -> doc_var kid
@@ -443,16 +448,16 @@ let rec typeclass_nexps (Typ_aux(t,l)) =
| Typ_fn (ts,t,_) -> List.fold_left NexpSet.union (typeclass_nexps t) (List.map typeclass_nexps ts)
| Typ_tup ts -> List.fold_left NexpSet.union NexpSet.empty (List.map typeclass_nexps ts)
| Typ_app (Id_aux (Id "vector",_),
- [Typ_arg_aux (Typ_arg_nexp size_nexp,_);
- _;Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)])
+ [A_aux (A_nexp size_nexp,_);
+ _;A_aux (A_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)])
| Typ_app (Id_aux (Id "itself",_),
- [Typ_arg_aux (Typ_arg_nexp size_nexp,_)]) ->
+ [A_aux (A_nexp size_nexp,_)]) ->
let size_nexp = nexp_simp size_nexp in
if is_nexp_constant size_nexp then NexpSet.empty else
NexpSet.singleton (orig_nexp size_nexp)
| Typ_app (id, args) ->
let add_arg_nexps nexps = function
- | Typ_arg_aux (Typ_arg_typ typ, _) ->
+ | A_aux (A_typ typ, _) ->
NexpSet.union nexps (typeclass_nexps typ)
| _ -> nexps
in
@@ -513,7 +518,7 @@ let rec doc_pat_lem ctxt apat_needed (P_aux (p,(l,annot)) as pa) = match p with
let ppp = brackets (separate_map semi (doc_pat_lem ctxt true) pats) in
if apat_needed then parens ppp else ppp
| P_vector_concat pats ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"vector concatenation patterns should have been removed before pretty-printing")
| P_tup pats ->
(match pats with
@@ -529,12 +534,13 @@ let rec typ_needs_printed (Typ_aux (t,_) as typ) = match t with
| Typ_app (Id_aux (Id "itself",_),_) -> true
| Typ_app (_, targs) -> is_bitvector_typ typ || List.exists typ_needs_printed_arg targs
| Typ_fn (ts,t,_) -> List.exists typ_needs_printed ts || typ_needs_printed t
- | Typ_exist (kids,_,t) ->
+ | Typ_exist (kopts,_,t) ->
+ let kids = List.map kopt_kid kopts in (* TODO: Check this *)
let visible_kids = KidSet.inter (KidSet.of_list kids) (lem_tyvars_of_typ t) in
typ_needs_printed t && KidSet.is_empty visible_kids
| _ -> false
-and typ_needs_printed_arg (Typ_arg_aux (targ, _)) = match targ with
- | Typ_arg_typ t -> typ_needs_printed t
+and typ_needs_printed_arg (A_aux (targ, _)) = match targ with
+ | A_typ t -> typ_needs_printed t
| _ -> false
let contains_early_return exp =
@@ -553,13 +559,13 @@ let find_e_ids exp =
let typ_id_of (Typ_aux (typ, l)) = match typ with
| Typ_id id -> id
- | Typ_app (register, [Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id id, _)), _)])
+ | Typ_app (register, [A_aux (A_typ (Typ_aux (Typ_id id, _)), _)])
when string_of_id register = "register" -> id
| Typ_app (id, _) -> id
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "failed to get type id")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "failed to get type id")
let prefix_recordtype = true
-let report = Reporting_basic.err_unreachable
+let report = Reporting.err_unreachable
let doc_exp_lem, doc_let_lem =
let rec top_exp (ctxt : context) (aexp_needed : bool)
(E_aux (e, (l,annot)) as full_exp) =
@@ -632,7 +638,7 @@ let doc_exp_lem, doc_let_lem =
| _ ->
liftR ((prefix 2 1) (string "write_reg") (doc_lexp_deref_lem ctxt le ^/^ expY e)))
| E_vector_append(le,re) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_append should have been rewritten before pretty-printing")
| E_cons(le,re) -> doc_op (group (colon^^colon)) (expY le) (expY re)
| E_if(c,t,e) -> wrap_parens (align (if_exp ctxt false c t e))
@@ -663,7 +669,7 @@ let doc_exp_lem, doc_let_lem =
| (P_aux (P_var (P_aux (P_id id, _), _), _))
| (P_aux (P_id id, _))), _), _),
body), _), _), _)), _)), _) -> id, body
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ ("Unable to find loop variable in " ^ string_of_exp body)) in
+ | _ -> raise (Reporting.err_unreachable l __POS__ ("Unable to find loop variable in " ^ string_of_exp body)) in
let step = match ord_exp with
| E_aux (E_lit (L_aux (L_false, _)), _) ->
parens (separate space [string "integerNegate"; expY exp3])
@@ -694,7 +700,7 @@ let doc_exp_lem, doc_let_lem =
(prefix 2 1 (group body_lambda) (expN body))
)
)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ | _ -> raise (Reporting.err_unreachable l __POS__
"Unexpected number of arguments for loop combinator")
end
| Id_aux (Id (("while" | "until") as combinator), _) ->
@@ -731,7 +737,7 @@ let doc_exp_lem, doc_let_lem =
(parens (prefix 2 1 (group lambda) (expN cond)))
(parens (prefix 2 1 (group lambda) (expN body))))
)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ | _ -> raise (Reporting.err_unreachable l __POS__
"Unexpected number of arguments for loop combinator")
end
| Id_aux (Id "early_return", _) ->
@@ -751,7 +757,7 @@ let doc_exp_lem, doc_let_lem =
| _ -> aexp_needed, epp
in
if aexp_needed then parens tepp else tepp
- | _ -> raise (Reporting_basic.err_unreachable l __POS__
+ | _ -> raise (Reporting.err_unreachable l __POS__
"Unexpected number of arguments for early_return builtin")
end
| _ ->
@@ -787,10 +793,10 @@ let doc_exp_lem, doc_let_lem =
end
end
| E_vector_access (v,e) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_access should have been rewritten before pretty-printing")
| E_vector_subrange (v,e1,e2) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_subrange should have been rewritten before pretty-printing")
| E_field((E_aux(_,(l,fannot)) as fexp),id) ->
let ft = typ_of_annot (l,fannot) in
@@ -825,7 +831,7 @@ let doc_exp_lem, doc_let_lem =
| E_cast(typ,e) -> expV aexp_needed e
| E_tuple exps ->
parens (align (group (separate_map (comma ^^ break 1) expN exps)))
- | E_record(FES_aux(FES_Fexps(fexps,_),_)) ->
+ | E_record fexps ->
let recordtyp = match destruct_tannot annot with
| Some (env, Typ_aux (Typ_id tid,_), _)
| Some (env, Typ_aux (Typ_app (tid, _), _), _) ->
@@ -835,7 +841,7 @@ let doc_exp_lem, doc_let_lem =
wrap_parens (anglebars (space ^^ (align (separate_map
(semi_sp ^^ break 1)
(doc_fexp ctxt recordtyp) fexps)) ^^ space))
- | E_record_update(e,(FES_aux(FES_Fexps(fexps,_),_))) ->
+ | E_record_update(e, fexps) ->
let recordtyp = match destruct_tannot annot with
| Some (env, Typ_aux (Typ_id tid,_), _)
| Some (env, Typ_aux (Typ_app (tid, _), _), _)
@@ -847,7 +853,7 @@ let doc_exp_lem, doc_let_lem =
let t = Env.base_typ_of (env_of full_exp) (typ_of full_exp) in
let start, (len, order, etyp) =
if is_vector_typ t then vector_start_index t, vector_typ_args_of t
- else raise (Reporting_basic.err_unreachable l __POS__
+ else raise (Reporting.err_unreachable l __POS__
"E_vector of non-vector type") in
let dir,dir_out = if is_order_inc order then (true,"true") else (false, "false") in
let start = match nexp_simp start with
@@ -874,10 +880,10 @@ let doc_exp_lem, doc_let_lem =
else (epp,aexp_needed) in
if aexp_needed then parens (align epp) else epp
| E_vector_update(v,e1,e2) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_update should have been rewritten before pretty-printing")
| E_vector_update_subrange(v,e1,e2,e3) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_vector_update should have been rewritten before pretty-printing")
| E_list exps ->
brackets (separate_map semi (expN) exps)
@@ -895,7 +901,7 @@ let doc_exp_lem, doc_let_lem =
(separate_map (break 1) (doc_case ctxt) pexps) ^/^
(string "end)")))
else
- raise (Reporting_basic.err_todo l "Warning: try-block around pure expression")
+ raise (Reporting.err_todo l "Warning: try-block around pure expression")
| E_throw e ->
align (liftR (separate space [string "throw"; expY e]))
| E_exit e -> liftR (separate space [string "exit"; expY e])
@@ -932,7 +938,7 @@ let doc_exp_lem, doc_let_lem =
(match nexp_simp nexp with
| Nexp_aux (Nexp_constant i, _) -> doc_lit_lem (L_aux (L_num i, l))
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"pretty-printing non-constant sizeof expressions to Lem not supported"))
| E_return r ->
let ta =
@@ -948,7 +954,7 @@ let doc_exp_lem, doc_let_lem =
align (parens (string "early_return" ^//^ expV true r ^//^ ta))
| E_constraint _ -> string "true"
| E_internal_value _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"unsupported internal expression encountered while pretty-printing")
and if_exp ctxt (elseif : bool) c t e =
let if_pp = string (if elseif then "else if" else "if") in
@@ -981,7 +987,7 @@ let doc_exp_lem, doc_let_lem =
group (prefix 3 1 (separate space [pipe; doc_pat_lem ctxt false pat;arrow])
(group (top_exp ctxt false e)))
| Pat_aux(Pat_when(_,_,_),(l,_)) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"guarded pattern expression should have been rewritten before pretty-printing")
and doc_lexp_deref_lem ctxt ((LEXP_aux(lexp,(l,annot))) as le) = match lexp with
@@ -991,7 +997,7 @@ let doc_exp_lem, doc_let_lem =
| LEXP_cast (typ,id) -> doc_id_lem (append_id id "_ref")
| LEXP_tup lexps -> parens (separate_map comma_sp (doc_lexp_deref_lem ctxt) lexps)
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__ ("doc_lexp_deref_lem: Unsupported lexp"))
+ raise (Reporting.err_unreachable l __POS__ ("doc_lexp_deref_lem: Unsupported lexp"))
(* expose doc_exp_lem and doc_let *)
in top_exp, let_exp
@@ -1006,10 +1012,12 @@ let rec doc_range_lem (BF_aux(r,_)) = match r with
| BF_concat(ir1,ir2) -> (doc_range ir1) ^^ comma ^^ (doc_range ir2)
let doc_typdef_lem (TD_aux(td, (l, annot))) = match td with
- | TD_abbrev(id,nm,(TypSchm_aux (TypSchm_ts (typq, _), _) as typschm)) ->
+ | TD_abbrev(id,typq,A_aux (A_typ typ, _)) ->
+ let typschm = TypSchm_aux (TypSchm_ts (typq, typ), l) in
doc_op equals
(separate space [string "type"; doc_id_lem_type id; doc_typquant_items_lem None typq])
(doc_typschm_lem false typschm)
+ | TD_abbrev _ -> empty
| TD_record(id,nm,typq,fs,_) ->
let fname fid = if prefix_recordtype && string_of_id id <> "regstate"
then concat [doc_id_lem id;string "_";doc_id_lem_type fid;]
@@ -1019,9 +1027,8 @@ let doc_typdef_lem (TD_aux(td, (l, annot))) = match td with
let rectyp = match typq with
| TypQ_aux (TypQ_tq qs, _) ->
let quant_item = function
- | QI_aux (QI_id (KOpt_aux (KOpt_none kid, _)), l)
| QI_aux (QI_id (KOpt_aux (KOpt_kind (_, kid), _)), l) ->
- [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid, l)), l)]
+ [A_aux (A_nexp (Nexp_aux (Nexp_var kid, l)), l)]
| _ -> [] in
let targs = List.concat (List.map quant_item qs) in
mk_typ (Typ_app (id, targs))
@@ -1030,8 +1037,8 @@ let doc_typdef_lem (TD_aux(td, (l, annot))) = match td with
(* let doc_field (ftyp, fid) =
let reftyp =
mk_typ (Typ_app (Id_aux (Id "field_ref", Parse_ast.Unknown),
- [mk_typ_arg (Typ_arg_typ rectyp);
- mk_typ_arg (Typ_arg_typ ftyp)])) in
+ [mk_typ_arg (A_typ rectyp);
+ mk_typ_arg (A_typ ftyp)])) in
let rfannot = doc_tannot_lem empty_ctxt env false reftyp in
let get, set =
string "rec_val" ^^ dot ^^ fname fid,
@@ -1046,7 +1053,7 @@ let doc_typdef_lem (TD_aux(td, (l, annot))) = match td with
match nexp_simp start with
| Nexp_aux (Nexp_constant i, _) -> (i, is_order_inc ord)
| _ ->
- raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__
+ raise (Reporting.err_unreachable Parse_ast.Unknown __POS__
("register " ^ string_of_id id ^ " has non-constant start index " ^ string_of_nexp start))
with
| _ -> (Big_int.zero, true) in
@@ -1226,7 +1233,7 @@ let doc_typdef_lem (TD_aux(td, (l, annot))) = match td with
fromInterpValuePP ^^ hardline ^^ hardline ^^
fromToInterpValuePP ^^ hardline
else empty)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "register with non-constant indices")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "register with non-constant indices")
let args_of_typs l env typs =
let arg i typ =
@@ -1242,26 +1249,24 @@ let rec untuple_args_pat (P_aux (paux, ((l, _) as annot)) as pat) arg_typs =
| P_tup [], _ ->
let annot = (l, mk_tannot Env.empty unit_typ no_effect) in
[P_aux (P_lit (mk_lit L_unit), annot)], identity
- | P_wild, [Typ_aux (Typ_tup typs, _)] ->
+ | P_wild, (_::_::_) ->
let wild typ = P_aux (P_wild, (l, mk_tannot env typ no_effect)) in
- List.map wild typs, identity
+ List.map wild arg_typs, identity
| P_typ (_, pat), _ -> untuple_args_pat pat arg_typs
- | P_as _, [Typ_aux (Typ_tup _, _)]
- | P_id _, [Typ_aux (Typ_tup _, _)]
- | P_tup _, [Typ_aux (Typ_tup _, _)] ->
+ | P_as _, (_::_::_)
+ | P_id _, (_::_::_) ->
let argpats, argexps = args_of_typs l env arg_typs in
let argexp = E_aux (E_tuple argexps, annot) in
let bindargs (E_aux (_, bannot) as body) =
E_aux (E_let (LB_aux (LB_val (pat, argexp), annot), body), bannot) in
argpats, bindargs
+ (* The type checker currently has a special case for a single arg type; if
+ that is removed, then remove the next case. *)
+ | P_tup pats, [_] -> [pat], identity
| P_tup pats, _ -> pats, identity
| _, _ ->
[pat], identity
-let doc_rec_lem force_rec (Rec_aux(r,_)) = match r with
- | Rec_nonrec when not force_rec -> space
- | _ -> space ^^ string "rec" ^^ space
-
let doc_tannot_opt_lem (Typ_annot_opt_aux(t,_)) = match t with
| Typ_annot_opt_some(tq,typ) -> (*doc_typquant_lem tq*) (doc_typ_lem typ)
| Typ_annot_opt_none -> empty
@@ -1288,7 +1293,7 @@ let doc_funcl_lem (FCL_aux(FCL_Funcl(id, pexp), annot)) =
let _ = match guard with
| None -> ()
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"guarded pattern expression should have been rewritten before pretty-printing") in
group (prefix 3 1
(separate space [doc_id_lem id; patspp; equals])
@@ -1315,9 +1320,19 @@ let doc_mutrec_lem = function
let rec doc_fundef_lem (FD_aux(FD_function(r, typa, efa, fcls),fannot) as fd) =
match fcls with
| [] -> failwith "FD_function with empty function list"
- | FCL_aux (FCL_Funcl(id,_),annot) :: _
- when not (Env.is_extern id (env_of_annot annot) "lem") ->
- string "let" ^^ (doc_rec_lem (List.length fcls > 1) r) ^^ (doc_fundef_rhs_lem fd)
+ | FCL_aux (FCL_Funcl(id, pexp),annot) :: _
+ when not (Env.is_extern id (env_of_annot annot) "lem") ->
+ (* Output "rec" modifier if function calls itself. Mutually recursive
+ functions are handled separately by doc_mutrec_lem. *)
+ let is_funcl_rec =
+ fold_pexp
+ { (pure_exp_alg false (||)) with
+ e_app = (fun (id', args) -> List.fold_left (||) (Id.compare id id' = 0) args);
+ e_app_infix = (fun (l, id', r) -> l || (Id.compare id id' = 0) || r) }
+ pexp
+ in
+ let doc_rec = if is_funcl_rec then [string "rec"] else [] in
+ separate space ([string "let"] @ doc_rec @ [doc_fundef_rhs_lem fd])
| _ -> empty
@@ -1342,8 +1357,8 @@ let doc_dec_lem (DEC_aux (reg, ((l, _) as annot))) =
string o;
string "[]"]))
^/^ hardline
- else raise (Reporting_basic.err_unreachable l __POS__ ("can't deal with register type " ^ string_of_typ typ))
- else raise (Reporting_basic.err_unreachable l __POS__ ("can't deal with register type " ^ string_of_typ typ)) *)
+ else raise (Reporting.err_unreachable l __POS__ ("can't deal with register type " ^ string_of_typ typ))
+ else raise (Reporting.err_unreachable l __POS__ ("can't deal with register type " ^ string_of_typ typ)) *)
| DEC_alias(id,alspec) -> empty
| DEC_typ_alias(typ,id,alspec) -> empty
@@ -1369,7 +1384,7 @@ let is_field_accessor regtypes fdef =
let doc_regtype_fields (tname, (n1, n2, fields)) =
let i1, i2 = match n1, n2 with
| Nexp_aux(Nexp_constant i1,_),Nexp_aux(Nexp_constant i2,_) -> i1, i2
- | _ -> raise (Reporting_basic.err_typ Parse_ast.Unknown
+ | _ -> raise (Reporting.err_typ Parse_ast.Unknown
("Non-constant indices in register type " ^ tname)) in
let dir_b = i1 < i2 in
let dir = (if dir_b then "true" else "false") in
@@ -1377,7 +1392,7 @@ let doc_regtype_fields (tname, (n1, n2, fields)) =
let i, j = match fr with
| BF_aux (BF_single i, _) -> (i, i)
| BF_aux (BF_range (i, j), _) -> (i, j)
- | _ -> raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__
+ | _ -> raise (Reporting.err_unreachable Parse_ast.Unknown __POS__
("Unsupported type in field " ^ string_of_id fid ^ " of " ^ tname)) in
let fsize = Big_int.succ (Big_int.abs (Big_int.sub i j)) in
(* TODO Assumes normalised, decreasing bitvector slices; however, since
@@ -1386,8 +1401,8 @@ let doc_regtype_fields (tname, (n1, n2, fields)) =
let ftyp = vector_typ (nconstant fsize) dec_ord bit_typ in
let reftyp =
mk_typ (Typ_app (Id_aux (Id "field_ref", Parse_ast.Unknown),
- [mk_typ_arg (Typ_arg_typ (mk_id_typ (mk_id tname)));
- mk_typ_arg (Typ_arg_typ ftyp)])) in
+ [mk_typ_arg (A_typ (mk_id_typ (mk_id tname)));
+ mk_typ_arg (A_typ ftyp)])) in
let rfannot = doc_tannot_lem empty_ctxt Env.empty false reftyp in
doc_op equals
(concat [string "let "; parens (concat [string tname; underscore; doc_id_lem fid; rfannot])])
@@ -1418,6 +1433,7 @@ let rec doc_def_lem def =
| DEF_kind _ -> empty
| DEF_mapdef (MD_aux (_, (l, _))) -> unreachable l __POS__ "Lem doesn't support mappings"
+ | DEF_pragma _ -> empty
let find_exc_typ defs =
let is_exc_typ_def = function
diff --git a/src/pretty_print_sail.ml b/src/pretty_print_sail.ml
index 179ef208..3d4f77e6 100644
--- a/src/pretty_print_sail.ml
+++ b/src/pretty_print_sail.ml
@@ -52,6 +52,8 @@ open Ast
open Ast_util
open PPrint
+let opt_use_heuristics = ref false
+
module Big_int = Nat_big_num
let doc_op symb a b = infix 2 1 symb a b
@@ -63,10 +65,16 @@ let doc_id (Id_aux (id_aux, _)) =
let doc_kid kid = string (Ast_util.string_of_kid kid)
+let doc_kopt = function
+ | kopt when is_nat_kopt kopt -> doc_kid (kopt_kid kopt)
+ | kopt when is_typ_kopt kopt -> parens (separate space [doc_kid (kopt_kid kopt); colon; string "Type"])
+ | kopt when is_order_kopt kopt -> parens (separate space [doc_kid (kopt_kid kopt); colon; string "Order"])
+ | kopt -> parens (separate space [doc_kid (kopt_kid kopt); colon; string "Bool"])
+
let doc_int n = string (Big_int.to_string n)
let docstring (l, _) = match l with
- | Parse_ast.Documented (str, _) -> string "/**" ^^ string str ^^ string "*/" ^^ hardline
+ | Parse_ast.Documented (str, _) -> string "/*!" ^^ string str ^^ string "*/" ^^ hardline
| _ -> empty
let doc_ord (Ord_aux(o,_)) = match o with
@@ -111,63 +119,85 @@ let rec doc_nexp =
in
nexp0
-let doc_nc =
+let rec doc_nc nc =
let nc_op op n1 n2 = separate space [doc_nexp n1; string op; doc_nexp n2] in
let rec atomic_nc (NC_aux (nc_aux, _) as nc) =
match nc_aux with
| NC_true -> string "true"
| NC_false -> string "false"
- | NC_equal (n1, n2) -> nc_op "=" n1 n2
+ | NC_equal (n1, n2) -> nc_op "==" n1 n2
| NC_not_equal (n1, n2) -> nc_op "!=" n1 n2
| NC_bounded_ge (n1, n2) -> nc_op ">=" n1 n2
| NC_bounded_le (n1, n2) -> nc_op "<=" n1 n2
| NC_set (kid, ints) ->
separate space [doc_kid kid; string "in"; braces (separate_map (comma ^^ space) doc_int ints)]
- | NC_app (id, nexps) -> string "where" ^^ space ^^ doc_id id ^^ parens (separate_map (comma ^^ space) doc_nexp nexps)
- | _ -> parens (nc0 nc)
- and nc0 (NC_aux (nc_aux, _) as nc) =
- match nc_aux with
- | NC_or (c1, c2) -> separate space [nc0 c1; string "|"; nc1 c2]
- | _ -> nc1 nc
+ | NC_app (id, args) ->
+ doc_id id ^^ parens (separate_map (comma ^^ space) doc_typ_arg args)
+ | NC_var kid -> doc_kid kid
+ | NC_or _ | NC_and _ -> nc0 ~parenthesize:true nc
+ and nc0 ?parenthesize:(parenthesize=false) (NC_aux (nc_aux, _) as nc) =
+ (* Rather than parens (nc0 x) we use nc0 ~parenthesize:true x, because if
+ we rewrite a disjunction as a set constraint, then we can
+ always omit the parens. *)
+ let parens' = if parenthesize then parens else (fun x -> x) in
+ let disjs = constraint_disj nc in
+ let collect_constants kid = function
+ | NC_aux (NC_equal (Nexp_aux (Nexp_var kid', _), Nexp_aux (Nexp_constant c, _)), _) when Kid.compare kid kid' = 0 -> Some c
+ | _ -> None
+ in
+ match disjs with
+ | NC_aux (NC_equal (Nexp_aux (Nexp_var kid, _), Nexp_aux (Nexp_constant c, _)), _) :: ncs ->
+ let constants = List.map (collect_constants kid) ncs in
+ begin match Util.option_all (List.map (collect_constants kid) ncs) with
+ | None | Some [] -> parens' (separate_map (space ^^ bar ^^ space) nc1 disjs)
+ | Some cs ->
+ separate space [doc_kid kid; string "in"; braces (separate_map (comma ^^ space) doc_int (c :: cs))]
+ end
+ | _ -> parens' (separate_map (space ^^ bar ^^ space) nc1 disjs)
and nc1 (NC_aux (nc_aux, _) as nc) =
- match nc_aux with
- | NC_and (c1, c2) -> separate space [nc1 c1; string "&"; atomic_nc c2]
- | _ -> atomic_nc nc
+ let conjs = constraint_conj nc in
+ separate_map (space ^^ string "&" ^^ space) atomic_nc conjs
in
- nc0
+ atomic_nc (constraint_simp nc)
-let rec doc_typ (Typ_aux (typ_aux, l)) =
+and doc_typ ?(simple=false) (Typ_aux (typ_aux, l)) =
match typ_aux with
| Typ_id id -> doc_id id
| Typ_app (id, []) -> doc_id id
| Typ_app (Id_aux (DeIid str, _), [x; y]) ->
separate space [doc_typ_arg x; doc_typ_arg y]
- (*
- | Typ_app (id, [_; len; _; Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id tid, _)), _)]) when Id.compare (mk_id "vector") id == 0 && Id.compare (mk_id "bit") tid == 0->
- string "bits" ^^ parens (doc_typ_arg len)
- *)
+ | Typ_app (id, typs) when Id.compare id (mk_id "atom") = 0 ->
+ string "int" ^^ parens (separate_map (string ", ") doc_typ_arg typs)
+ | Typ_app (id, typs) when Id.compare id (mk_id "atom_bool") = 0 ->
+ string "bool" ^^ parens (separate_map (string ", ") doc_typ_arg typs)
| Typ_app (id, typs) -> doc_id id ^^ parens (separate_map (string ", ") doc_typ_arg typs)
| Typ_tup typs -> parens (separate_map (string ", ") doc_typ typs)
| Typ_var kid -> doc_kid kid
(* Resugar set types like {|1, 2, 3|} *)
- | Typ_exist ([kid1], NC_aux (NC_set (kid2, ints), _), Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid3, _)), _)]), _))
- when Kid.compare kid1 kid2 == 0 && Kid.compare kid2 kid3 == 0 && Id.compare (mk_id "atom") id == 0 ->
+ | Typ_exist ([kopt],
+ NC_aux (NC_set (kid1, ints), _),
+ Typ_aux (Typ_app (id, [A_aux (A_nexp (Nexp_aux (Nexp_var kid2, _)), _)]), _))
+ when Kid.compare (kopt_kid kopt) kid1 == 0 && Kid.compare kid1 kid2 == 0 && Id.compare (mk_id "atom") id == 0 ->
enclose (string "{|") (string "|}") (separate_map (string ", ") doc_int ints)
- | Typ_exist (kids, nc, typ) ->
- braces (separate_map space doc_kid kids ^^ comma ^^ space ^^ doc_nc nc ^^ dot ^^ space ^^ doc_typ typ)
+ | Typ_exist (kopts, nc, typ) ->
+ braces (separate_map space doc_kopt kopts ^^ comma ^^ space ^^ doc_nc nc ^^ dot ^^ space ^^ doc_typ typ)
| Typ_fn (typs, typ, Effect_aux (Effect_set [], _)) ->
separate space [doc_arg_typs typs; string "->"; doc_typ typ]
| Typ_fn (typs, typ, Effect_aux (Effect_set effs, _)) ->
let ocaml_eff = braces (separate (comma ^^ space) (List.map (fun be -> string (string_of_base_effect be)) effs)) in
- separate space [doc_arg_typs typs; string "->"; doc_typ typ; string "effect"; ocaml_eff]
+ if simple then
+ separate space [doc_arg_typs typs; string "->"; doc_typ ~simple:simple typ]
+ else
+ separate space [doc_arg_typs typs; string "->"; doc_typ typ; string "effect"; ocaml_eff]
| Typ_bidir (typ1, typ2) ->
separate space [doc_typ typ1; string "<->"; doc_typ typ2]
- | Typ_internal_unknown -> raise (Reporting_basic.err_unreachable l __POS__ "escaped Typ_internal_unknown")
-and doc_typ_arg (Typ_arg_aux (ta_aux, _)) =
+ | Typ_internal_unknown -> raise (Reporting.err_unreachable l __POS__ "escaped Typ_internal_unknown")
+and doc_typ_arg (A_aux (ta_aux, _)) =
match ta_aux with
- | Typ_arg_typ typ -> doc_typ typ
- | Typ_arg_nexp nexp -> doc_nexp nexp
- | Typ_arg_order o -> doc_ord o
+ | A_typ typ -> doc_typ typ
+ | A_nexp nexp -> doc_nexp nexp
+ | A_order o -> doc_ord o
+ | A_bool nc -> doc_nc nc
and doc_arg_typs = function
| [typ] -> doc_typ typ
| typs -> parens (separate_map (comma ^^ space) doc_typ typs)
@@ -175,9 +205,9 @@ and doc_arg_typs = function
let doc_quants quants =
let doc_qi_kopt (QI_aux (qi_aux, _)) =
match qi_aux with
- | QI_id (KOpt_aux (KOpt_none kid, _)) -> [doc_kid kid]
| QI_id kopt when is_nat_kopt kopt -> [parens (separate space [doc_kid (kopt_kid kopt); colon; string "Int"])]
| QI_id kopt when is_typ_kopt kopt -> [parens (separate space [doc_kid (kopt_kid kopt); colon; string "Type"])]
+ | QI_id kopt when is_bool_kopt kopt -> [parens (separate space [doc_kid (kopt_kid kopt); colon; string "Bool"])]
| QI_id kopt -> [parens (separate space [doc_kid (kopt_kid kopt); colon; string "Order"])]
| QI_const nc -> []
in
@@ -193,24 +223,53 @@ let doc_quants quants =
| [nc] -> kdoc ^^ comma ^^ space ^^ doc_nc nc
| nc :: ncs -> kdoc ^^ comma ^^ space ^^ doc_nc (List.fold_left nc_and nc ncs)
+let doc_param_quants quants =
+ let doc_qi_kopt (QI_aux (qi_aux, _)) =
+ match qi_aux with
+ | QI_id kopt when is_nat_kopt kopt -> [doc_kid (kopt_kid kopt) ^^ colon ^^ space ^^ string "Int"]
+ | QI_id kopt when is_typ_kopt kopt -> [doc_kid (kopt_kid kopt) ^^ colon ^^ space ^^ string "Type"]
+ | QI_id kopt when is_bool_kopt kopt -> [doc_kid (kopt_kid kopt) ^^ colon ^^ space ^^ string "Bool"]
+ | QI_id kopt -> [doc_kid (kopt_kid kopt) ^^ colon ^^ space ^^ string "Order"]
+ | QI_const nc -> []
+ in
+ let qi_nc (QI_aux (qi_aux, _)) =
+ match qi_aux with
+ | QI_const nc -> [nc]
+ | _ -> []
+ in
+ let kdoc = separate (comma ^^ space) (List.concat (List.map doc_qi_kopt quants)) in
+ let ncs = List.concat (List.map qi_nc quants) in
+ match ncs with
+ | [] -> parens kdoc
+ | [nc] -> parens kdoc ^^ comma ^^ space ^^ doc_nc nc
+ | nc :: ncs -> parens kdoc ^^ comma ^^ space ^^ doc_nc (List.fold_left nc_and nc ncs)
-
-let doc_binding (TypQ_aux (tq_aux, _), typ) =
+let doc_binding ?(simple=false) ((TypQ_aux (tq_aux, _) as typq), typ) =
match tq_aux with
- | TypQ_no_forall -> doc_typ typ
- | TypQ_tq [] -> doc_typ typ
+ | TypQ_no_forall -> doc_typ ~simple:simple typ
+ | TypQ_tq [] -> doc_typ ~simple:simple typ
| TypQ_tq qs ->
- string "forall" ^^ space ^^ doc_quants qs ^^ dot ^//^ doc_typ typ
-
-let doc_typschm (TypSchm_aux (TypSchm_ts (typq, typ), _)) = doc_binding (typq, typ)
+ if !opt_use_heuristics && String.length (string_of_typquant typq) > 60 then
+ let kopts, ncs = quant_split typq in
+ if ncs = [] then
+ string "forall" ^^ space ^^ separate_map space doc_kopt kopts ^^ dot
+ ^//^ doc_typ ~simple:simple typ
+ else
+ string "forall" ^^ space ^^ separate_map space doc_kopt kopts ^^ comma
+ ^//^ (separate_map (space ^^ string "&" ^^ space) doc_nc ncs ^^ dot
+ ^^ hardline ^^ doc_typ ~simple:simple typ)
+ else
+ string "forall" ^^ space ^^ doc_quants qs ^^ dot ^//^ doc_typ ~simple:simple typ
+
+let doc_typschm ?(simple=false) (TypSchm_aux (TypSchm_ts (typq, typ), _)) = doc_binding ~simple:simple (typq, typ)
let doc_typschm_typ (TypSchm_aux (TypSchm_ts (TypQ_aux (tq_aux, _), typ), _)) = doc_typ typ
-let doc_typschm_quants (TypSchm_aux (TypSchm_ts (TypQ_aux (tq_aux, _), typ), _)) =
+let doc_typquant (TypQ_aux (tq_aux, _)) =
match tq_aux with
| TypQ_no_forall -> None
| TypQ_tq [] -> None
- | TypQ_tq qs -> Some (doc_quants qs)
+ | TypQ_tq qs -> Some (doc_param_quants qs)
let doc_lit (L_aux(l,_)) =
utf8string (match l with
@@ -226,7 +285,7 @@ let doc_lit (L_aux(l,_)) =
| L_undef -> "undefined"
| L_string s -> "\"" ^ String.escaped s ^ "\"")
-let rec doc_pat (P_aux (p_aux, _) as pat) =
+let rec doc_pat (P_aux (p_aux, (l, _)) as pat) =
match p_aux with
| P_id id -> doc_id id
| P_or (pat1, pat2) -> parens (doc_pat pat1 ^^ string " | " ^^ doc_pat pat2)
@@ -237,14 +296,18 @@ let rec doc_pat (P_aux (p_aux, _) as pat) =
(* P_var short form sugar *)
| P_var (P_aux (P_id id, _), TP_aux (TP_var kid, _)) when Id.compare (id_of_kid kid) id == 0 ->
doc_kid kid
- | P_var (pat, tpat) -> separate space [doc_pat pat; string "as"; doc_typ_pat tpat]
+ | P_var (pat, tpat) -> parens (separate space [doc_pat pat; string "as"; doc_typ_pat tpat])
| P_vector pats -> brackets (separate_map (comma ^^ space) doc_pat pats)
| P_vector_concat pats -> separate_map (space ^^ string "@" ^^ space) doc_pat pats
| P_wild -> string "_"
| P_as (pat, id) -> parens (separate space [doc_pat pat; string "as"; doc_id id])
| P_app (id, pats) -> doc_id id ^^ parens (separate_map (comma ^^ space) doc_pat pats)
| P_list pats -> string "[|" ^^ separate_map (comma ^^ space) doc_pat pats ^^ string "|]"
- | _ -> string (string_of_pat pat)
+ | P_cons (hd_pat, tl_pat) -> separate space [doc_pat hd_pat; string "::"; doc_pat tl_pat]
+ | P_string_append [] -> string "\"\""
+ | P_string_append pats ->
+ parens (separate_map (string " ^ ") doc_pat pats)
+ | P_record _ -> raise (Reporting.err_unreachable l __POS__ "P_record passed to doc_pat")
(* if_block_x is true if x should be printed like a block, i.e. with
newlines. Blocks are automatically printed as blocks, so this
@@ -286,8 +349,8 @@ let fixities =
let rec doc_exp (E_aux (e_aux, _) as exp) =
match e_aux with
| E_block [] -> string "()"
- | E_block [exp] -> doc_exp exp
- | E_block exps -> surround 2 0 lbrace (doc_block exps) rbrace
+ | E_block exps ->
+ group (lbrace ^^ nest 4 (hardline ^^ doc_block exps) ^^ hardline ^^ rbrace)
| E_nondet exps -> assert false
(* This is mostly for the -convert option *)
| E_app_infix (x, id, y) when Id.compare (mk_id "quot") id == 0 ->
@@ -336,21 +399,16 @@ let rec doc_exp (E_aux (e_aux, _) as exp) =
| E_assign (lexp, exp) ->
separate space [doc_lexp lexp; equals; doc_exp exp]
| E_for (id, exp1, exp2, exp3, order, exp4) ->
- begin
- let header =
- string "foreach" ^^ space ^^
- group (parens (separate (break 1)
- [ doc_id id;
- string "from " ^^ doc_atomic_exp exp1;
- string "to " ^^ doc_atomic_exp exp2;
- string "by " ^^ doc_atomic_exp exp3;
- string "in " ^^ doc_ord order ]))
- in
- match exp4 with
- | E_aux (E_block [_], _) -> header ^//^ doc_exp exp4
- | E_aux (E_block _, _) -> header ^^ space ^^ doc_exp exp4
- | _ -> header ^//^ doc_exp exp4
- end
+ let header =
+ string "foreach" ^^ space ^^
+ group (parens (separate (break 1)
+ [ doc_id id;
+ string "from " ^^ doc_atomic_exp exp1;
+ string "to " ^^ doc_atomic_exp exp2;
+ string "by " ^^ doc_atomic_exp exp3;
+ string "in " ^^ doc_ord order ]))
+ in
+ header ^^ space ^^ doc_exp exp4
(* Resugar an assert with an empty message *)
| E_throw exp -> string "throw" ^^ parens (doc_exp exp)
| E_try (exp, pexps) ->
@@ -404,7 +462,7 @@ and doc_atomic_exp (E_aux (e_aux, _) as exp) =
brackets (separate space [doc_exp exp1; string "with"; doc_atomic_exp exp2; string ".."; doc_atomic_exp exp3; equals; doc_exp exp4])
| E_internal_value v -> string (Value.string_of_value v |> Util.green |> Util.clear)
| _ -> parens (doc_exp exp)
-and doc_fexps (FES_aux (FES_Fexps (fexps, _), _)) =
+and doc_fexps fexps =
separate_map (comma ^^ space) doc_fexp fexps
and doc_fexp (FE_aux (FE_Fexp (id, exp), _)) =
separate space [doc_id id; equals; doc_exp exp]
@@ -451,13 +509,21 @@ let doc_funcl (FCL_aux (FCL_Funcl (id, Pat_aux (pexp,_)), _)) =
let doc_default (DT_aux (DT_order ord, _)) = separate space [string "default"; string "Order"; doc_ord ord]
-let doc_fundef (FD_aux (FD_function (r, typa, efa, funcls), _)) =
- match funcls with
- | [] -> failwith "Empty function list"
- | _ ->
- let sep = hardline ^^ string "and" ^^ space in
- let clauses = separate_map sep doc_funcl funcls in
- string "function" ^^ space ^^ clauses
+let doc_rec (Rec_aux (r,_)) =
+ match r with
+ | Rec_nonrec
+ | Rec_rec -> empty
+ | Rec_measure (pat,exp) -> braces (doc_pat pat ^^ string " => " ^^ doc_exp exp) ^^ space
+
+let doc_fundef (FD_aux (FD_function (r, typa, efa, funcls), annot)) =
+ docstring annot
+ ^^ match funcls with
+ | [] -> failwith "Empty function list"
+ | _ ->
+ let rec_pp = doc_rec r in
+ let sep = hardline ^^ string "and" ^^ space in
+ let clauses = separate_map sep doc_funcl funcls in
+ string "function" ^^ space ^^ rec_pp ^^ clauses
let rec doc_mpat (MP_aux (mp_aux, _) as mpat) =
match mp_aux with
@@ -512,38 +578,45 @@ let doc_field (typ, id) =
let doc_union (Tu_aux (Tu_ty_id (typ, id), l)) = separate space [doc_id id; colon; doc_typ typ]
+let doc_typ_arg_kind (A_aux (aux, _)) =
+ match aux with
+ | A_nexp _ -> space ^^ string "->" ^^ space ^^string "Int"
+ | A_bool _ -> space ^^ string "->" ^^ space ^^ string "Bool"
+ | A_order _ -> space ^^ string "->" ^^ space ^^ string "Order"
+ | A_typ _ -> empty
+
let doc_typdef (TD_aux(td,_)) = match td with
- | TD_abbrev (id, _, typschm) ->
+ | TD_abbrev (id, typq, typ_arg) ->
begin
- match doc_typschm_quants typschm with
+ match doc_typquant typq with
| Some qdoc ->
- doc_op equals (concat [string "type"; space; doc_id id; space; qdoc]) (doc_typschm_typ typschm)
+ doc_op equals (concat [string "type"; space; doc_id id; qdoc; doc_typ_arg_kind typ_arg]) (doc_typ_arg typ_arg)
| None ->
- doc_op equals (concat [string "type"; space; doc_id id]) (doc_typschm_typ typschm)
+ doc_op equals (concat [string "type"; space; doc_id id; doc_typ_arg_kind typ_arg]) (doc_typ_arg typ_arg)
end
| TD_enum (id, _, ids, _) ->
separate space [string "enum"; doc_id id; equals; surround 2 0 lbrace (separate_map (comma ^^ break 1) doc_id ids) rbrace]
| TD_record (id, _, TypQ_aux (TypQ_no_forall, _), fields, _) | TD_record (id, _, TypQ_aux (TypQ_tq [], _), fields, _) ->
separate space [string "struct"; doc_id id; equals; surround 2 0 lbrace (separate_map (comma ^^ break 1) doc_field fields) rbrace]
| TD_record (id, _, TypQ_aux (TypQ_tq qs, _), fields, _) ->
- separate space [string "struct"; doc_id id; doc_quants qs; equals;
+ separate space [string "struct"; doc_id id; doc_param_quants qs; equals;
surround 2 0 lbrace (separate_map (comma ^^ break 1) doc_field fields) rbrace]
| TD_variant (id, _, TypQ_aux (TypQ_no_forall, _), unions, _) | TD_variant (id, _, TypQ_aux (TypQ_tq [], _), unions, _) ->
separate space [string "union"; doc_id id; equals; surround 2 0 lbrace (separate_map (comma ^^ break 1) doc_union unions) rbrace]
| TD_variant (id, _, TypQ_aux (TypQ_tq qs, _), unions, _) ->
- separate space [string "union"; doc_id id; doc_quants qs; equals;
+ separate space [string "union"; doc_id id; doc_param_quants qs; equals;
surround 2 0 lbrace (separate_map (comma ^^ break 1) doc_union unions) rbrace]
| _ -> string "TYPEDEF"
-let doc_spec (VS_aux (v, annot)) =
+let doc_spec ?comment:(comment=false) (VS_aux (v, annot)) =
let doc_extern ext =
let docs = List.map (fun (backend, rep) -> string (backend ^ ":") ^^ space ^^ utf8string ("\"" ^ String.escaped rep ^ "\"")) ext in
if docs = [] then empty else equals ^^ space ^^ braces (separate (comma ^^ space) docs)
in
match v with
| VS_val_spec(ts,id,ext,is_cast) ->
- docstring annot
+ if comment then docstring annot else empty
^^ string "val" ^^ space
^^ (if is_cast then (string "cast" ^^ space) else empty)
^^ doc_id id ^^ space
@@ -561,13 +634,18 @@ let doc_kind_def (KD_aux (KD_nabbrev (_, id, _, nexp), _)) =
let rec doc_scattered (SD_aux (sd_aux, _)) =
match sd_aux with
- | SD_scattered_function (_, _, _, id) ->
+ | SD_function (_, _, _, id) ->
string "scattered" ^^ space ^^ string "function" ^^ space ^^ doc_id id
- | SD_scattered_funcl funcl ->
+ | SD_funcl funcl ->
string "function" ^^ space ^^ string "clause" ^^ space ^^ doc_funcl funcl
- | SD_scattered_end id ->
+ | SD_end id ->
string "end" ^^ space ^^ doc_id id
- | _ -> string "SCATTERED"
+ | SD_variant (id, _, TypQ_aux (TypQ_no_forall, _)) ->
+ string "scattered" ^^ space ^^ string "union" ^^ space ^^ doc_id id
+ | SD_variant (id, _, TypQ_aux (TypQ_tq quants, _)) ->
+ string "scattered" ^^ space ^^ string "union" ^^ space ^^ doc_id id ^^ doc_param_quants quants
+ | SD_unioncl (id, tu) ->
+ separate space [string "union clause"; doc_id id; equals; doc_union tu]
let rec doc_def def = group (match def with
| DEF_default df -> doc_default df
@@ -582,11 +660,11 @@ let rec doc_def def = group (match def with
^^ hardline ^^ string "}"
| DEF_reg_dec dec -> doc_dec dec
| DEF_scattered sdef -> doc_scattered sdef
+ | DEF_pragma (pragma, arg, l) ->
+ string ("$" ^ pragma ^ " " ^ arg)
| DEF_fixity (prec, n, id) ->
fixities := Bindings.add id (prec, Big_int.to_int n) !fixities;
separate space [doc_prec prec; doc_int n; doc_id id]
- | DEF_constraint (id, kids, nc) ->
- separate space [string "constraint"; doc_id id; parens (separate_map (comma ^^ space) doc_kid kids); equals; doc_nc nc]
| DEF_overload (id, ids) ->
separate space [string "overload"; doc_id id; equals; surround 2 0 lbrace (separate_map (comma ^^ break 1) doc_id ids) rbrace]
) ^^ hardline
diff --git a/src/process_file.ml b/src/process_file.ml
index 344c7921..87acd83a 100644
--- a/src/process_file.ml
+++ b/src/process_file.ml
@@ -65,7 +65,7 @@ let get_lexbuf f =
lexbuf, in_chan
let parse_file ?loc:(l=Parse_ast.Unknown) (f : string) : Parse_ast.defs =
- let open Reporting_basic in
+ let open Reporting in
try
let lexbuf, in_chan = get_lexbuf f in
begin
@@ -75,7 +75,8 @@ let parse_file ?loc:(l=Parse_ast.Unknown) (f : string) : Parse_ast.defs =
with
| Parser.Error ->
let pos = Lexing.lexeme_start_p lexbuf in
- raise (Fatal_error (Err_syntax (pos, "no information")))
+ let tok = Lexing.lexeme lexbuf in
+ raise (Fatal_error (Err_syntax (pos, "current token: " ^ tok)))
| Lexer.LexError(s,p) ->
raise (Fatal_error (Err_lex (p, s)))
end
@@ -111,7 +112,7 @@ let cond_pragma l defs =
decr depth; push_def def; scan defs
| def :: defs ->
push_def def; scan defs
- | [] -> raise (Reporting_basic.err_general l "$ifdef or $ifndef never ended by $endif")
+ | [] -> raise (Reporting.err_general l "$ifdef or $ifndef never ended by $endif")
in
scan defs
@@ -123,19 +124,24 @@ let parseid_to_string (Parse_ast.Id_aux (id, _)) =
match id with
| Parse_ast.Id x | Parse_ast.DeIid x -> x
-let rec realise_union_anon_rec_types (Parse_ast.TD_variant (union_id, name_scm_opt, typq, _, flag) as orig_union) arms =
- match arms with
- | [] -> []
- | arm :: arms ->
- match arm with
- | (Parse_ast.Tu_aux ((Parse_ast.Tu_ty_id _), _)) -> (None, arm) :: realise_union_anon_rec_types orig_union arms
- | (Parse_ast.Tu_aux ((Parse_ast.Tu_ty_anon_rec (fields, id)), l)) ->
- let open Parse_ast in
- let record_str = "_" ^ parseid_to_string union_id ^ "_" ^ parseid_to_string id ^ "_record" in
- let record_id = Id_aux (Id record_str, Generated l) in
- let new_arm = Tu_aux ((Tu_ty_id ((ATyp_aux (ATyp_id record_id, Generated l)), id)), Generated l) in
- let new_rec_def = DEF_type (TD_aux (TD_record (record_id, name_scm_opt, typq, fields, flag), Generated l)) in
- (Some new_rec_def, new_arm) :: (realise_union_anon_rec_types orig_union arms)
+let rec realise_union_anon_rec_types orig_union arms =
+ match orig_union with
+ | Parse_ast.TD_variant (union_id, name_scm_opt, typq, _, flag) ->
+ begin match arms with
+ | [] -> []
+ | arm :: arms ->
+ match arm with
+ | (Parse_ast.Tu_aux ((Parse_ast.Tu_ty_id _), _)) -> (None, arm) :: realise_union_anon_rec_types orig_union arms
+ | (Parse_ast.Tu_aux ((Parse_ast.Tu_ty_anon_rec (fields, id)), l)) ->
+ let open Parse_ast in
+ let record_str = "_" ^ parseid_to_string union_id ^ "_" ^ parseid_to_string id ^ "_record" in
+ let record_id = Id_aux (Id record_str, Generated l) in
+ let new_arm = Tu_aux ((Tu_ty_id ((ATyp_aux (ATyp_id record_id, Generated l)), id)), Generated l) in
+ let new_rec_def = DEF_type (TD_aux (TD_record (record_id, name_scm_opt, typq, fields, flag), Generated l)) in
+ (Some new_rec_def, new_arm) :: (realise_union_anon_rec_types orig_union arms)
+ end
+ | _ ->
+ raise (Reporting.err_unreachable Parse_ast.Unknown __POS__ "Non union type-definition passed to realise_union_anon_rec_typs")
let rec preprocess opts = function
| [] -> []
@@ -149,11 +155,10 @@ let rec preprocess opts = function
let args = Str.split (Str.regexp " +") command in
Arg.parse_argv ~current:(ref 0) (Array.of_list ("sail" :: args)) opts (fun _ -> ()) "";
with
- | Arg.Bad message | Arg.Help message -> raise (Reporting_basic.err_general l message)
+ | Arg.Bad message | Arg.Help message -> raise (Reporting.err_general l message)
end;
preprocess opts defs
-
| Parse_ast.DEF_pragma ("ifndef", symbol, l) :: defs ->
let then_defs, else_defs, defs = cond_pragma l defs in
if not (StringSet.mem symbol !symbols) then
@@ -200,8 +205,8 @@ let rec preprocess opts = function
let help = "Make sure the filename is surrounded by quotes or angle brackets" in
(Util.warn ("Skipping bad $include " ^ file ^ ". " ^ help); preprocess opts defs)
- | Parse_ast.DEF_pragma (p, arg, _) :: defs ->
- (Util.warn ("Bad pragma $" ^ p ^ " " ^ arg); preprocess opts defs)
+ | Parse_ast.DEF_pragma (p, arg, l) :: defs ->
+ Parse_ast.DEF_pragma (p, arg, l) :: preprocess opts defs
(* realise any anonymous record arms of variants *)
| Parse_ast.DEF_type (Parse_ast.TD_aux
@@ -309,7 +314,7 @@ let output_lem filename libs defs =
open_output_with_check_unformatted (filename ^ ".lem") in
(Pretty_print.pp_defs_lem
(ot, base_imports)
- (o, base_imports @ (String.capitalize types_module :: libs))
+ (o, base_imports @ (String.capitalize_ascii types_module :: libs))
defs generated_line);
close_output_with_check ext_ot;
close_output_with_check ext_o;
@@ -360,8 +365,10 @@ let output libpath out_arg files =
output1 libpath out_arg f defs)
files
-let rewrite_step defs (name,rewriter) =
+let rewrite_step defs (name, rewriter) =
+ let t = Profile.start () in
let defs = rewriter defs in
+ Profile.finish ("rewrite " ^ name) t;
let _ = match !(opt_ddump_rewrite_ast) with
| Some (f, i) ->
begin
@@ -378,10 +385,9 @@ let rewrite_step defs (name,rewriter) =
let rewrite rewriters env defs =
try List.fold_left rewrite_step defs rewriters with
| Type_check.Type_error (l, err) ->
- raise (Reporting_basic.err_typ l (Type_error.string_of_type_error err))
+ raise (Reporting.err_typ l (Type_error.string_of_type_error err))
let rewrite_ast = rewrite [("initial", Rewriter.rewrite_defs)]
-let rewrite_undefined bitvectors = rewrite [("undefined", fun x -> Rewrites.rewrite_undefined bitvectors x)]
let rewrite_ast_lem = rewrite Rewrites.rewrite_defs_lem
let rewrite_ast_coq = rewrite Rewrites.rewrite_defs_coq
let rewrite_ast_ocaml = rewrite Rewrites.rewrite_defs_ocaml
diff --git a/src/process_file.mli b/src/process_file.mli
index 7862c121..7b860a73 100644
--- a/src/process_file.mli
+++ b/src/process_file.mli
@@ -56,7 +56,6 @@ val convert_ast : Ast.order -> Parse_ast.defs -> unit Ast.defs
val preprocess_ast : (Arg.key * Arg.spec * Arg.doc) list -> Parse_ast.defs -> Parse_ast.defs
val check_ast: Type_check.Env.t -> unit Ast.defs -> Type_check.tannot Ast.defs * Type_check.Env.t
val rewrite_ast: Type_check.Env.t -> Type_check.tannot Ast.defs -> Type_check.tannot Ast.defs
-val rewrite_undefined: bool -> Type_check.Env.t -> Type_check.tannot Ast.defs -> Type_check.tannot Ast.defs
val rewrite_ast_lem : Type_check.Env.t -> Type_check.tannot Ast.defs -> Type_check.tannot Ast.defs
val rewrite_ast_coq : Type_check.Env.t -> Type_check.tannot Ast.defs -> Type_check.tannot Ast.defs
val rewrite_ast_ocaml : Type_check.Env.t -> Type_check.tannot Ast.defs -> Type_check.tannot Ast.defs
diff --git a/src/profile.ml b/src/profile.ml
new file mode 100644
index 00000000..cb374403
--- /dev/null
+++ b/src/profile.ml
@@ -0,0 +1,91 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+let opt_profile = ref false
+
+type profile = {
+ z3_calls : int;
+ z3_time : float
+ }
+
+let new_profile = {
+ z3_calls = 0;
+ z3_time = 0.0
+ }
+
+let profile_stack = ref []
+
+let update_profile f =
+ match !profile_stack with
+ | [] -> ()
+ | (p :: ps) ->
+ profile_stack := f p :: ps
+
+let start_z3 () =
+ update_profile (fun p -> { p with z3_calls = p.z3_calls + 1 });
+ Sys.time ()
+
+let finish_z3 t =
+ update_profile (fun p -> { p with z3_time = p.z3_time +. (Sys.time () -. t) })
+
+let start () =
+ profile_stack := new_profile :: !profile_stack;
+ Sys.time ()
+
+let finish msg t =
+ if !opt_profile then
+ begin match !profile_stack with
+ | p :: ps ->
+ prerr_endline (Printf.sprintf "%s %s: %fs" Util.("Profile" |> magenta |> clear) msg (Sys.time () -. t));
+ prerr_endline (Printf.sprintf " Z3 calls: %d, Z3 time: %fs" p.z3_calls p.z3_time);
+ profile_stack := ps
+ | [] -> ()
+ end
+ else ()
diff --git a/src/reporting_basic.ml b/src/reporting.ml
index a90c2bcd..858e5c41 100644
--- a/src/reporting_basic.ml
+++ b/src/reporting.ml
@@ -169,6 +169,14 @@ let format_pos2 ff p1 p2 =
Format.pp_print_flush ff ()
end
+let format_just_pos ff p1 p2 =
+ let open Lexing in
+ Format.fprintf ff "file \"%s\", line %d, character %d to line %d, character %d"
+ p1.pos_fname
+ p1.pos_lnum (p1.pos_cnum - p1.pos_bol + 1)
+ p2.pos_lnum (p2.pos_cnum - p2.pos_bol);
+ Format.pp_print_flush ff ()
+
(* reads the part between p1 and p2 from the file *)
let read_from_file_pos2 p1 p2 =
@@ -187,36 +195,29 @@ let read_from_file_pos2 p1 p2 =
let _ = close_in ic in
(buf, not (multi = None))
-(* Destruct a location by splitting all the Internal strings except possibly the
- last one into a string list and keeping only the last location *)
-let dest_loc (l : Parse_ast.l) : (Parse_ast.l * string list) =
- let rec aux acc l = match l with
- | Parse_ast.Int(s, Some l') -> aux (s::acc) l'
- | _ -> (l, acc)
- in
- aux [] l
-
-let rec format_loc_aux ff l =
- let (l_org, mod_s) = dest_loc l in
- let _ = match l_org with
- | Parse_ast.Unknown -> Format.fprintf ff "no location information available"
- | Parse_ast.Generated l -> Format.fprintf ff "code generated: original nearby source is "; (format_loc_aux ff l)
- | Parse_ast.Range(p1,p2) -> format_pos2 ff p1 p2
- | Parse_ast.Int(s,_) -> Format.fprintf ff "code in lib from: %s" s
- | Parse_ast.Documented(_, l) -> format_loc_aux ff l
- in
- ()
+let rec format_loc_aux ?code:(code=true) ff = function
+ | Parse_ast.Unknown ->
+ Format.fprintf ff "no location information available"
+ | Parse_ast.Generated l ->
+ Format.fprintf ff "code generated: original nearby source is ";
+ format_loc_aux ~code:code ff l
+ | Parse_ast.Unique (n, l) ->
+ Format.fprintf ff "code unique (%d): original nearby source is " n;
+ format_loc_aux ~code:code ff l
+ | Parse_ast.Range (p1, p2) when code ->
+ format_pos2 ff p1 p2
+ | Parse_ast.Range (p1, p2) ->
+ format_just_pos ff p1 p2
+ | Parse_ast.Documented (_, l) ->
+ format_loc_aux ~code:code ff l
-let format_loc_source ff l =
- match dest_loc l with
- | (Parse_ast.Range (p1, p2), _) ->
- begin
- let (s, multi_line) = read_from_file_pos2 p1 p2 in
- if multi_line then
- Format.fprintf ff " original input:\n%s\n" (Bytes.to_string s)
- else
- Format.fprintf ff " original input: \"%s\"\n" (Bytes.to_string s)
- end
+let format_loc_source ff = function
+ | Parse_ast.Range (p1, p2) ->
+ let (s, multi_line) = read_from_file_pos2 p1 p2 in
+ if multi_line then
+ Format.fprintf ff " original input:\n%s\n" (Bytes.to_string s)
+ else
+ Format.fprintf ff " original input: \"%s\"\n" (Bytes.to_string s)
| _ -> ()
let format_loc ff l =
@@ -231,9 +232,9 @@ let print_err_loc l =
let print_pos p = format_pos Format.std_formatter p
let print_err_pos p = format_pos Format.err_formatter p
-let loc_to_string l =
+let loc_to_string ?code:(code=true) l =
let _ = Format.flush_str_formatter () in
- let _ = format_loc_aux Format.str_formatter l in
+ let _ = format_loc_aux ~code:code Format.str_formatter l in
let s = Format.flush_str_formatter () in
s
@@ -265,9 +266,12 @@ type error =
| Err_type of Parse_ast.l * string
| Err_type_dual of Parse_ast.l * Parse_ast.l * string
+let issues = "\n\nPlease report this as an issue on GitHub at https://github.com/rems-project/sail/issues"
+
let dest_err = function
| Err_general (l, m) -> ("Error", false, Loc l, m)
- | Err_unreachable (l, (file, line, _, _), m) -> ((Printf.sprintf "Internal error: Unreachable code (at \"%s\" line %d)" file line), false, Loc l, m)
+ | Err_unreachable (l, (file, line, _, _), m) ->
+ ((Printf.sprintf "Internal error: Unreachable code (at \"%s\" line %d)" file line), false, Loc l, m ^ issues)
| Err_todo (l, m) -> ("Todo" ^ m, false, Loc l, "")
| Err_syntax (p, m) -> ("Syntax error", false, Pos p, m)
| Err_syntax_locn (l, m) -> ("Syntax error", false, Loc l, m)
@@ -284,7 +288,7 @@ let err_general l m = Fatal_error (Err_general (l, m))
let err_typ l m = Fatal_error (Err_type (l,m))
let err_typ_dual l1 l2 m = Fatal_error (Err_type_dual (l1,l2,m))
-let report_error e =
+let report_error e =
let (m1, verb_pos, pos_l, m2) = dest_err e in
(print_err_internal verb_pos false pos_l m1 m2; exit 1)
diff --git a/src/reporting_basic.mli b/src/reporting.mli
index 39ac32f0..63ed3eee 100644
--- a/src/reporting_basic.mli
+++ b/src/reporting.mli
@@ -50,7 +50,7 @@
(** Basic error reporting
- [Reporting_basic] contains functions to report errors and warnings.
+ [Reporting] contains functions to report errors and warnings.
It contains functions to print locations ([Parse_ast.l] and [Ast.l]) and lexing positions.
The main functionality is reporting errors. This is done by raising a
@@ -62,7 +62,8 @@
(** {2 Auxiliary Functions } *)
-val loc_to_string : Parse_ast.l -> string
+(** [loc_to_string] includes code from file if code optional argument is true (default) *)
+val loc_to_string : ?code:bool -> Parse_ast.l -> string
(** [print_err fatal print_loc_source l head mes] prints an error / warning message to
std-err. It starts with printing location information stored in [l]
diff --git a/src/return_analysis.ml b/src/return_analysis.ml
new file mode 100644
index 00000000..256f97cf
--- /dev/null
+++ b/src/return_analysis.ml
@@ -0,0 +1,182 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast
+open Ast_util
+open Type_check
+
+let analyze_exp_returns exp =
+ let returns = ref [] in
+ let add_return annot = returns := annot :: !returns in
+
+ print_endline ("\nAnalyzing " ^ string_of_exp exp);
+
+ let rec analyze last (E_aux (e_aux, annot)) =
+ let env = env_of_annot annot in
+ match e_aux with
+ | E_block exps ->
+ begin match List.rev exps with
+ | [] -> ()
+ | (exp :: exps) ->
+ List.iter (analyze false) exps;
+ analyze last exp
+ end
+
+ | E_nondet exps -> List.iter (analyze last) exps
+
+ | E_id id ->
+ if last then
+ add_return annot
+ else
+ ()
+
+ | E_lit _ when last ->
+ add_return annot
+
+ | E_app _ when last ->
+ add_return annot
+ | E_app (_, exps) ->
+ List.iter (analyze false) exps
+
+ | E_if (_, then_exp, else_exp) ->
+ analyze last then_exp; analyze last else_exp
+
+ | E_return (E_aux (_, annot)) ->
+ add_return annot
+
+ | E_for (_, exp1, exp2, exp3, _, body) ->
+ analyze false exp1; analyze false exp2; analyze false exp3;
+ analyze last body
+
+ | _ -> ()
+ in
+ analyze true exp;
+
+ !returns
+
+type existential =
+ | Equal of nexp
+ | Constraint of (kid -> n_constraint)
+ | Anything
+
+let existentialize_annot funcl_annot annot =
+ let funcl_env = env_of_annot funcl_annot in
+ let env = env_of_annot annot in
+ match Env.expand_synonyms env (typ_of_annot annot) with
+ | (Typ_aux (Typ_app (ty_id, [A_aux (A_nexp nexp, _)]), _) as typ)
+ when Id.compare ty_id (mk_id "atom") = 0 ->
+ let tyvars = Env.get_typ_vars funcl_env |> KBindings.bindings in
+ let toplevel_kids =
+ List.filter (fun (kid, k) -> match k with K_int -> true | _ -> false) tyvars |> List.map fst |> KidSet.of_list
+ in
+ let new_kids = KidSet.diff (tyvars_of_nexp nexp) toplevel_kids in
+
+ if KidSet.cardinal new_kids = 0 then
+ Some (Equal nexp)
+ else if KidSet.cardinal new_kids = 1 then
+ let ex_kid = KidSet.min_elt new_kids in
+ (* Now we search for constraints that involve the existential
+ kid, and only reference toplevel type variables. *)
+ let constraints = List.concat (List.map constraint_conj (Env.get_constraints env)) in
+ let constraints = List.filter (fun nc -> KidSet.mem ex_kid (tyvars_of_constraint nc)) constraints in
+ let constraints =
+ List.filter (fun nc -> KidSet.subset (tyvars_of_constraint nc) (KidSet.add ex_kid toplevel_kids)) constraints
+ in
+
+ match constraints with
+ | c :: cs ->
+ Some (Constraint (fun kid -> nc_subst_nexp ex_kid (Nexp_var kid) (List.fold_left nc_and c cs)))
+ | [] ->
+ Some Anything
+ else
+ Some Anything
+ | _ ->
+ None
+
+let union_existential ex1 ex2 =
+ match ex1, ex2 with
+ | Equal nexp1, Equal nexp2 ->
+ Constraint (fun kid -> nc_or (nc_eq (nvar kid) nexp1) (nc_eq (nvar kid) nexp2))
+
+ | Equal nexp, Constraint c ->
+ Constraint (fun kid -> nc_or (nc_eq (nvar kid) nexp) (c kid))
+
+ | Constraint c, Equal nexp ->
+ Constraint (fun kid -> nc_or (c kid) (nc_eq (nvar kid) nexp))
+
+ | _, _ -> Anything
+
+let typ_of_existential = function
+ | Anything -> int_typ
+ | Equal nexp -> atom_typ nexp
+ | Constraint c -> exist_typ c (fun kid -> atom_typ (nvar kid))
+
+let analyze_def_returns = function
+ | DEF_fundef (FD_aux (FD_function (_, _, _, funcls), _)) ->
+ let analyze_funcls = function
+ | FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (pat, exp), _)), funcl_annot) ->
+ let return_exs =
+ List.map (fun annot -> existentialize_annot funcl_annot annot) (analyze_exp_returns exp)
+ in
+ begin match Util.option_all return_exs with
+ | Some [] -> ()
+ | Some (ex :: exs) ->
+ print_endline (string_of_typ (typ_of_existential (List.fold_left union_existential ex exs)))
+ | None -> ()
+ end
+
+ | _ -> ()
+ in
+ List.iter analyze_funcls funcls
+
+ | def -> ()
+
+let analyze_returns (Defs defs) = List.iter analyze_def_returns defs
+
diff --git a/src/rewriter.ml b/src/rewriter.ml
index a7505ca7..a70f6fab 100644
--- a/src/rewriter.ml
+++ b/src/rewriter.ml
@@ -64,11 +64,10 @@ type 'a rewriters = {
rewrite_defs : 'a rewriters -> 'a defs -> 'a defs;
}
-
let effect_of_fpat (FP_aux (_,(_,a))) = effect_of_annot a
let effect_of_lexp (LEXP_aux (_,(_,a))) = effect_of_annot a
let effect_of_fexp (FE_aux (_,(_,a))) = effect_of_annot a
-let effect_of_fexps (FES_aux (FES_Fexps (fexps,_),_)) =
+let effect_of_fexps fexps =
List.fold_left union_effects no_effect (List.map effect_of_fexp fexps)
let effect_of_opt_default (Def_val_aux (_,(_,a))) = effect_of_annot a
(* The typechecker does not seem to annotate pexps themselves *)
@@ -95,7 +94,7 @@ let lookup_generated_kid env kid =
let generated_kids typ = KidSet.filter is_kid_generated (tyvars_of_typ typ)
let resolve_generated_kids env typ =
- let subst_kid kid typ = typ_subst_kid kid (lookup_generated_kid env kid) typ in
+ let subst_kid kid typ = subst_kid typ_subst kid (lookup_generated_kid env kid) typ in
KidSet.fold subst_kid (generated_kids typ) typ
let rec remove_p_typ = function
@@ -103,7 +102,7 @@ let rec remove_p_typ = function
| pat -> pat
let add_p_typ typ (P_aux (paux, annot) as pat) =
- let typ' = resolve_generated_kids (pat_env_of pat) typ in
+ let typ' = resolve_generated_kids (env_of_pat pat) typ in
if KidSet.is_empty (generated_kids typ') then
P_aux (P_typ (typ', remove_p_typ pat), annot)
else pat
@@ -295,16 +294,14 @@ let rewrite_exp rewriters (E_aux (exp,(l,annot)) as orig_exp) =
| E_vector_append (v1,v2) -> rewrap (E_vector_append (rewrite v1,rewrite v2))
| E_list exps -> rewrap (E_list (List.map rewrite exps))
| E_cons(h,t) -> rewrap (E_cons (rewrite h,rewrite t))
- | E_record (FES_aux (FES_Fexps(fexps, bool),fannot)) ->
+ | E_record fexps ->
rewrap (E_record
- (FES_aux (FES_Fexps
- (List.map (fun (FE_aux(FE_Fexp(id,e),fannot)) ->
- FE_aux(FE_Fexp(id,rewrite e),fannot)) fexps, bool), fannot)))
- | E_record_update (re,(FES_aux (FES_Fexps(fexps, bool),fannot))) ->
+ (List.map (fun (FE_aux(FE_Fexp(id,e),fannot)) ->
+ FE_aux(FE_Fexp(id,rewrite e),fannot)) fexps))
+ | E_record_update (re, fexps) ->
rewrap (E_record_update ((rewrite re),
- (FES_aux (FES_Fexps
- (List.map (fun (FE_aux(FE_Fexp(id,e),fannot)) ->
- FE_aux(FE_Fexp(id,rewrite e),fannot)) fexps, bool), fannot))))
+ (List.map (fun (FE_aux(FE_Fexp(id,e),fannot)) ->
+ FE_aux(FE_Fexp(id,rewrite e),fannot)) fexps)))
| E_field(exp,id) -> rewrap (E_field(rewrite exp,id))
| E_case (exp,pexps) ->
rewrap (E_case (rewrite exp, List.map (rewrite_pexp rewriters) pexps))
@@ -319,8 +316,8 @@ let rewrite_exp rewriters (E_aux (exp,(l,annot)) as orig_exp) =
| E_assert(e1,e2) -> rewrap (E_assert(rewrite e1,rewrite e2))
| E_var (lexp, e1, e2) ->
rewrap (E_var (rewriters.rewrite_lexp rewriters lexp, rewriters.rewrite_exp rewriters e1, rewriters.rewrite_exp rewriters e2))
- | E_internal_return _ -> raise (Reporting_basic.err_unreachable l __POS__ "Internal return found before it should have been introduced")
- | E_internal_plet _ -> raise (Reporting_basic.err_unreachable l __POS__ " Internal plet found before it should have been introduced")
+ | E_internal_return _ -> raise (Reporting.err_unreachable l __POS__ "Internal return found before it should have been introduced")
+ | E_internal_plet _ -> raise (Reporting.err_unreachable l __POS__ " Internal plet found before it should have been introduced")
| _ -> rewrap exp
let rewrite_let rewriters (LB_aux(letbind,(l,annot))) =
@@ -349,7 +346,14 @@ let rewrite_lexp rewriters (LEXP_aux(lexp,(l,annot))) =
let rewrite_fun rewriters (FD_aux (FD_function(recopt,tannotopt,effectopt,funcls),(l,fdannot))) =
let rewrite_funcl (FCL_aux (FCL_Funcl(id,pexp),(l,annot))) =
(FCL_aux (FCL_Funcl (id, rewrite_pexp rewriters pexp),(l,annot)))
- in FD_aux (FD_function(recopt,tannotopt,effectopt,List.map rewrite_funcl funcls),(l,fdannot))
+ in
+ let recopt = match recopt with
+ | Rec_aux (Rec_nonrec, l) -> Rec_aux (Rec_nonrec, l)
+ | Rec_aux (Rec_rec, l) -> Rec_aux (Rec_rec, l)
+ | Rec_aux (Rec_measure (pat,exp),l) ->
+ Rec_aux (Rec_measure (rewrite_pat rewriters pat, rewrite_exp rewriters exp),l)
+ in
+ FD_aux (FD_function(recopt,tannotopt,effectopt,List.map rewrite_funcl funcls),(l,fdannot))
let rewrite_def rewriters d = match d with
| DEF_reg_dec (DEC_aux (DEC_config (id, typ, exp), annot)) ->
@@ -358,7 +362,8 @@ let rewrite_def rewriters d = match d with
| DEF_fundef fdef -> DEF_fundef (rewriters.rewrite_fun rewriters fdef)
| DEF_internal_mutrec fdefs -> DEF_internal_mutrec (List.map (rewriters.rewrite_fun rewriters) fdefs)
| DEF_val letbind -> DEF_val (rewriters.rewrite_let rewriters letbind)
- | DEF_scattered _ -> raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__ "DEF_scattered survived to rewritter")
+ | DEF_pragma (pragma, arg, l) -> DEF_pragma (pragma, arg, l)
+ | DEF_scattered _ -> raise (Reporting.err_unreachable Parse_ast.Unknown __POS__ "DEF_scattered survived to rewritter")
let rewrite_defs_base rewriters (Defs defs) =
let rec rewrite ds = match ds with
@@ -474,9 +479,9 @@ let id_pat_alg : ('a,'a pat, 'a pat_aux, 'a fpat, 'a fpat_aux) pat_alg =
; fP_Fpat = (fun (id,pat) -> FP_Fpat (id,pat))
}
-type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
+type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,
'opt_default_aux,'opt_default,'pexp,'pexp_aux,'letbind_aux,'letbind,
- 'pat,'pat_aux,'fpat,'fpat_aux) exp_alg =
+ 'pat,'pat_aux,'fpat,'fpat_aux) exp_alg =
{ e_block : 'exp list -> 'exp_aux
; e_nondet : 'exp list -> 'exp_aux
; e_id : id -> 'exp_aux
@@ -497,8 +502,8 @@ type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
; e_vector_append : 'exp * 'exp -> 'exp_aux
; e_list : 'exp list -> 'exp_aux
; e_cons : 'exp * 'exp -> 'exp_aux
- ; e_record : 'fexps -> 'exp_aux
- ; e_record_update : 'exp * 'fexps -> 'exp_aux
+ ; e_record : 'fexp list -> 'exp_aux
+ ; e_record_update : 'exp * 'fexp list -> 'exp_aux
; e_field : 'exp * id -> 'exp_aux
; e_case : 'exp * 'pexp list -> 'exp_aux
; e_try : 'exp * 'pexp list -> 'exp_aux
@@ -527,8 +532,6 @@ type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
; lEXP_aux : 'lexp_aux * 'a annot -> 'lexp
; fE_Fexp : id * 'exp -> 'fexp_aux
; fE_aux : 'fexp_aux * 'a annot -> 'fexp
- ; fES_Fexps : 'fexp list * bool -> 'fexps_aux
- ; fES_aux : 'fexps_aux * 'a annot -> 'fexps
; def_val_empty : 'opt_default_aux
; def_val_dec : 'exp -> 'opt_default_aux
; def_val_aux : 'opt_default_aux * 'a annot -> 'opt_default
@@ -566,8 +569,8 @@ let rec fold_exp_aux alg = function
| E_vector_append (e1,e2) -> alg.e_vector_append (fold_exp alg e1, fold_exp alg e2)
| E_list es -> alg.e_list (List.map (fold_exp alg) es)
| E_cons (e1,e2) -> alg.e_cons (fold_exp alg e1, fold_exp alg e2)
- | E_record fexps -> alg.e_record (fold_fexps alg fexps)
- | E_record_update (e,fexps) -> alg.e_record_update (fold_exp alg e, fold_fexps alg fexps)
+ | E_record fexps -> alg.e_record (List.map (fold_fexp alg) fexps)
+ | E_record_update (e,fexps) -> alg.e_record_update (fold_exp alg e, List.map (fold_fexp alg) fexps)
| E_field (e,id) -> alg.e_field (fold_exp alg e, id)
| E_case (e,pexps) -> alg.e_case (fold_exp alg e, List.map (fold_pexp alg) pexps)
| E_try (e,pexps) -> alg.e_try (fold_exp alg e, List.map (fold_pexp alg) pexps)
@@ -601,8 +604,6 @@ and fold_lexp alg (LEXP_aux (lexp_aux,annot)) =
alg.lEXP_aux (fold_lexp_aux alg lexp_aux, annot)
and fold_fexp_aux alg (FE_Fexp (id,e)) = alg.fE_Fexp (id, fold_exp alg e)
and fold_fexp alg (FE_aux (fexp_aux,annot)) = alg.fE_aux (fold_fexp_aux alg fexp_aux,annot)
-and fold_fexps_aux alg (FES_Fexps (fexps,b)) = alg.fES_Fexps (List.map (fold_fexp alg) fexps, b)
-and fold_fexps alg (FES_aux (fexps_aux,annot)) = alg.fES_aux (fold_fexps_aux alg fexps_aux, annot)
and fold_opt_default_aux alg = function
| Def_val_empty -> alg.def_val_empty
| Def_val_dec e -> alg.def_val_dec (fold_exp alg e)
@@ -673,8 +674,6 @@ let id_exp_alg =
; lEXP_aux = (fun (lexp,annot) -> LEXP_aux (lexp,annot))
; fE_Fexp = (fun (id,e) -> FE_Fexp (id,e))
; fE_aux = (fun (fexp,annot) -> FE_aux (fexp,annot))
- ; fES_Fexps = (fun (fexps,b) -> FES_Fexps (fexps,b))
- ; fES_aux = (fun (fexp,annot) -> FES_aux (fexp,annot))
; def_val_empty = Def_val_empty
; def_val_dec = (fun e -> Def_val_dec e)
; def_val_aux = (fun (defval,aux) -> Def_val_aux (defval,aux))
@@ -741,8 +740,12 @@ let compute_exp_alg bot join =
; e_vector_append = (fun ((v1,e1),(v2,e2)) -> (join v1 v2, E_vector_append (e1,e2)))
; e_list = split_join (fun es -> E_list es)
; e_cons = (fun ((v1,e1),(v2,e2)) -> (join v1 v2, E_cons (e1,e2)))
- ; e_record = (fun (vs,fexps) -> (vs, E_record fexps))
- ; e_record_update = (fun ((v1,e1),(vf,fexp)) -> (join v1 vf, E_record_update (e1,fexp)))
+ ; e_record = (fun fexps ->
+ let vs, fexps = List.split fexps in
+ (join_list vs, E_record fexps))
+ ; e_record_update = (fun ((v1,e1),fexps) ->
+ let (vps,fexps) = List.split fexps in
+ (join_list (v1::vps), E_record_update (e1,fexps)))
; e_field = (fun ((v1,e1),id) -> (v1, E_field (e1,id)))
; e_case = (fun ((v1,e1),pexps) ->
let (vps,pexps) = List.split pexps in
@@ -782,10 +785,6 @@ let compute_exp_alg bot join =
; lEXP_aux = (fun ((vl,lexp),annot) -> (vl, LEXP_aux (lexp,annot)))
; fE_Fexp = (fun (id,(v,e)) -> (v, FE_Fexp (id,e)))
; fE_aux = (fun ((vf,fexp),annot) -> (vf, FE_aux (fexp,annot)))
- ; fES_Fexps = (fun (fexps,b) ->
- let (vs,fexps) = List.split fexps in
- (join_list vs, FES_Fexps (fexps,b)))
- ; fES_aux = (fun ((vf,fexp),annot) -> (vf, FES_aux (fexp,annot)))
; def_val_empty = (bot, Def_val_empty)
; def_val_dec = (fun (v,e) -> (v, Def_val_dec e))
; def_val_aux = (fun ((v,defval),aux) -> (v, Def_val_aux (defval,aux)))
@@ -842,8 +841,8 @@ let pure_exp_alg bot join =
; e_vector_append = (fun (v1,v2) -> join v1 v2)
; e_list = join_list
; e_cons = (fun (v1,v2) -> join v1 v2)
- ; e_record = (fun vs -> vs)
- ; e_record_update = (fun (v1,vf) -> join v1 vf)
+ ; e_record = (fun vs -> join_list vs)
+ ; e_record_update = (fun (v1,vf) -> join_list (v1::vf))
; e_field = (fun (v1,id) -> v1)
; e_case = (fun (v1,vps) -> join_list (v1::vps))
; e_try = (fun (v1,vps) -> join_list (v1::vps))
@@ -872,8 +871,6 @@ let pure_exp_alg bot join =
; lEXP_aux = (fun (vl,annot) -> vl)
; fE_Fexp = (fun (id,v) -> v)
; fE_aux = (fun (vf,annot) -> vf)
- ; fES_Fexps = (fun (vs,b) -> join_list vs)
- ; fES_aux = (fun (vf,annot) -> vf)
; def_val_empty = bot
; def_val_dec = (fun v -> v)
; def_val_aux = (fun (v,aux) -> v)
diff --git a/src/rewriter.mli b/src/rewriter.mli
index 15e704df..9da94a99 100644
--- a/src/rewriter.mli
+++ b/src/rewriter.mli
@@ -107,7 +107,7 @@ type ('a,'pat,'pat_aux,'fpat,'fpat_aux) pat_alg =
(* fold over pat_aux expressions *)
(* the type of interpretations of expressions *)
-type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
+type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,
'opt_default_aux,'opt_default,'pexp,'pexp_aux,'letbind_aux,'letbind,
'pat,'pat_aux,'fpat,'fpat_aux) exp_alg =
{ e_block : 'exp list -> 'exp_aux
@@ -130,8 +130,8 @@ type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
; e_vector_append : 'exp * 'exp -> 'exp_aux
; e_list : 'exp list -> 'exp_aux
; e_cons : 'exp * 'exp -> 'exp_aux
- ; e_record : 'fexps -> 'exp_aux
- ; e_record_update : 'exp * 'fexps -> 'exp_aux
+ ; e_record : 'fexp list -> 'exp_aux
+ ; e_record_update : 'exp * 'fexp list -> 'exp_aux
; e_field : 'exp * id -> 'exp_aux
; e_case : 'exp * 'pexp list -> 'exp_aux
; e_try : 'exp * 'pexp list -> 'exp_aux
@@ -160,8 +160,6 @@ type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
; lEXP_aux : 'lexp_aux * 'a annot -> 'lexp
; fE_Fexp : id * 'exp -> 'fexp_aux
; fE_aux : 'fexp_aux * 'a annot -> 'fexp
- ; fES_Fexps : 'fexp list * bool -> 'fexps_aux
- ; fES_aux : 'fexps_aux * 'a annot -> 'fexps
; def_val_empty : 'opt_default_aux
; def_val_dec : 'exp -> 'opt_default_aux
; def_val_aux : 'opt_default_aux * 'a annot -> 'opt_default
@@ -177,34 +175,34 @@ type ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
val fold_pat : ('a,'pat,'pat_aux,'fpat,'fpat_aux) pat_alg -> 'a pat -> 'pat
(* fold over expressions *)
-val fold_exp : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
+val fold_exp : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,
'opt_default_aux,'opt_default,'pexp,'pexp_aux,'letbind_aux,'letbind,
'pat,'pat_aux,'fpat,'fpat_aux) exp_alg -> 'a exp -> 'exp
-val fold_letbind : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
+val fold_letbind : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,
'opt_default_aux,'opt_default,'pexp,'pexp_aux,'letbind_aux,'letbind,
'pat,'pat_aux,'fpat,'fpat_aux) exp_alg -> 'a letbind -> 'letbind
-val fold_pexp : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
+val fold_pexp : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,
'opt_default_aux,'opt_default,'pexp,'pexp_aux,'letbind_aux,'letbind,
'pat,'pat_aux,'fpat,'fpat_aux) exp_alg -> 'a pexp -> 'pexp
-val fold_pexp : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
+val fold_pexp : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,
'opt_default_aux,'opt_default,'pexp,'pexp_aux,'letbind_aux,'letbind,
'pat,'pat_aux,'fpat,'fpat_aux) exp_alg -> 'a pexp -> 'pexp
-val fold_funcl : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
+val fold_funcl : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,
'opt_default_aux,'opt_default,'a pexp,'pexp_aux,'letbind_aux,'letbind,
'pat,'pat_aux,'fpat,'fpat_aux) exp_alg -> 'a funcl -> 'a funcl
-val fold_function : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux,
+val fold_function : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,
'opt_default_aux,'opt_default, 'a pexp,'pexp_aux,'letbind_aux,'letbind,
'pat,'pat_aux,'fpat,'fpat_aux) exp_alg -> 'a fundef -> 'a fundef
val id_pat_alg : ('a,'a pat, 'a pat_aux, 'a fpat, 'a fpat_aux) pat_alg
val id_exp_alg :
('a,'a exp,'a exp_aux,'a lexp,'a lexp_aux,'a fexp,
- 'a fexp_aux,'a fexps,'a fexps_aux,
+ 'a fexp_aux,
'a opt_default_aux,'a opt_default,'a pexp,'a pexp_aux,
'a letbind_aux,'a letbind,
'a pat,'a pat_aux,'a fpat,'a fpat_aux) exp_alg
@@ -214,7 +212,7 @@ val compute_pat_alg : 'b -> ('b -> 'b -> 'b) ->
val compute_exp_alg : 'b -> ('b -> 'b -> 'b) ->
('a,('b * 'a exp),('b * 'a exp_aux),('b * 'a lexp),('b * 'a lexp_aux),('b * 'a fexp),
- ('b * 'a fexp_aux),('b * 'a fexps),('b * 'a fexps_aux),
+ ('b * 'a fexp_aux),
('b * 'a opt_default_aux),('b * 'a opt_default),('b * 'a pexp),('b * 'a pexp_aux),
('b * 'a letbind_aux),('b * 'a letbind),
('b * 'a pat),('b * 'a pat_aux),('b * 'a fpat),('b * 'a fpat_aux)) exp_alg
@@ -224,7 +222,7 @@ val pure_pat_alg : 'b -> ('b -> 'b -> 'b) -> ('a,'b,'b,'b,'b) pat_alg
val pure_exp_alg : 'b -> ('b -> 'b -> 'b) ->
('a,'b,'b,'b,'b,'b,
'b,'b,'b,
- 'b,'b,'b,'b,
+ 'b,'b,
'b,'b,
'b,'b,'b,'b) exp_alg
@@ -248,6 +246,4 @@ val fix_eff_pexp : tannot pexp -> tannot pexp
val fix_eff_fexp : tannot fexp -> tannot fexp
-val fix_eff_fexps : tannot fexps -> tannot fexps
-
val fix_eff_opt_default : tannot opt_default -> tannot opt_default
diff --git a/src/rewrites.ml b/src/rewrites.ml
index f1d22720..10bc4f44 100644
--- a/src/rewrites.ml
+++ b/src/rewrites.ml
@@ -82,7 +82,7 @@ let fresh_id_pat pre ((l,annot)) =
let get_loc_exp (E_aux (_,(l,_))) = l
-let gen_vs (id, spec) = Initial_check.extern_of_string dec_ord (mk_id id) spec
+let gen_vs (id, spec) = Initial_check.extern_of_string (mk_id id) spec
let annot_exp_effect e_aux l env typ effect = E_aux (e_aux, (l, mk_tannot env typ effect))
let annot_exp e_aux l env typ = annot_exp_effect e_aux l env typ no_effect
@@ -169,16 +169,16 @@ let vector_string_to_bit_list l lit =
| 'D' -> ['1';'1';'0';'1']
| 'E' -> ['1';'1';'1';'0']
| 'F' -> ['1';'1';'1';'1']
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "hexchar_to_binlist given unrecognized character") in
+ | _ -> raise (Reporting.err_unreachable l __POS__ "hexchar_to_binlist given unrecognized character") in
let s_bin = match lit with
| L_hex s_hex -> List.flatten (List.map hexchar_to_binlist (explode (String.uppercase_ascii s_hex)))
| L_bin s_bin -> explode s_bin
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "s_bin given non vector literal") in
+ | _ -> raise (Reporting.err_unreachable l __POS__ "s_bin given non vector literal") in
List.map (function '0' -> L_aux (L_zero, gen_loc l)
| '1' -> L_aux (L_one, gen_loc l)
- | _ -> raise (Reporting_basic.err_unreachable (gen_loc l) __POS__ "binary had non-zero or one")) s_bin
+ | _ -> raise (Reporting.err_unreachable (gen_loc l) __POS__ "binary had non-zero or one")) s_bin
let find_used_vars exp =
(* Overapproximates the set of used identifiers, but for the use cases below
@@ -264,13 +264,15 @@ let rewrite_defs_nexp_ids, rewrite_typ_nexp_ids =
| Typ_app (id, targs) ->
Typ_aux (Typ_app (id, List.map (rewrite_typ_arg env) targs), l)
| _ -> typ_aux
- and rewrite_typ_arg env (Typ_arg_aux (targ, l) as targ_aux) = match targ with
- | Typ_arg_nexp nexp ->
- Typ_arg_aux (Typ_arg_nexp (rewrite_nexp_ids env nexp), l)
- | Typ_arg_typ typ ->
- Typ_arg_aux (Typ_arg_typ (rewrite_typ env typ), l)
- | Typ_arg_order ord ->
- Typ_arg_aux (Typ_arg_order ord, l)
+ and rewrite_typ_arg env (A_aux (targ, l) as targ_aux) = match targ with
+ | A_nexp nexp ->
+ A_aux (A_nexp (rewrite_nexp_ids env nexp), l)
+ | A_typ typ ->
+ A_aux (A_typ (rewrite_typ env typ), l)
+ | A_order ord ->
+ A_aux (A_order ord, l)
+ | A_bool nc ->
+ A_aux (A_bool nc, l)
in
let rewrite_annot (l, tannot) =
@@ -409,7 +411,7 @@ let rewrite_sizeof (Defs defs) =
| P_id id | P_as (_, id) ->
let (Typ_aux (typ,_) as typ_aux) = typ_of_annot annot in
(match typ with
- | Typ_app (atom, [Typ_arg_aux (Typ_arg_nexp nexp, _)])
+ | Typ_app (atom, [A_aux (A_nexp nexp, _)])
when string_of_id atom = "atom" ->
[nexp, E_id id]
| Typ_app (vector, _) when string_of_id vector = "vector" ->
@@ -461,7 +463,7 @@ let rewrite_sizeof (Defs defs) =
let inst =
try instantiation_of orig_exp with
| Type_error (l, err) ->
- raise (Reporting_basic.err_typ l (Type_error.string_of_type_error err)) in
+ raise (Reporting.err_typ l (Type_error.string_of_type_error err)) in
(* Rewrite the inst using orig_kid so that each type variable has it's
original name rather than a mangled typechecker name *)
let inst = KBindings.fold (fun kid uvar b -> KBindings.add (orig_kid kid) uvar b) inst KBindings.empty in
@@ -470,17 +472,17 @@ let rewrite_sizeof (Defs defs) =
assert (not (Str.string_match ex_regex (string_of_kid kid) 0));
let uvar = try Some (KBindings.find (orig_kid kid) inst) with Not_found -> None in
match uvar with
- | Some (U_nexp nexp) ->
+ | Some (A_aux (A_nexp nexp, _)) ->
let sizeof = E_aux (E_sizeof nexp, (l, mk_tannot env (atom_typ nexp) no_effect)) in
(try rewrite_trivial_sizeof_exp sizeof with
| Type_error (l, err) ->
- raise (Reporting_basic.err_typ l (Type_error.string_of_type_error err)))
+ raise (Reporting.err_typ l (Type_error.string_of_type_error err)))
(* If the type variable is Not_found then it was probably
introduced by a P_var pattern, so it likely exists as
a variable in scope. It can't be an existential because the assert rules that out. *)
| None -> annot_exp (E_id (id_of_kid (orig_kid kid))) l env (atom_typ (nvar (orig_kid kid)))
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
("failed to infer nexp for type variable " ^ string_of_kid kid ^
" of function " ^ string_of_id f))
end in
@@ -513,8 +515,8 @@ let rewrite_sizeof (Defs defs) =
; e_vector_append = (fun ((e1,e1'),(e2,e2')) -> (E_vector_append (e1,e2), E_vector_append (e1',e2')))
; e_list = (fun es -> let (es, es') = List.split es in (E_list es, E_list es'))
; e_cons = (fun ((e1,e1'),(e2,e2')) -> (E_cons (e1,e2), E_cons (e1',e2')))
- ; e_record = (fun (fexps, fexps') -> (E_record fexps, E_record fexps'))
- ; e_record_update = (fun ((e1,e1'),(fexp,fexp')) -> (E_record_update (e1,fexp), E_record_update (e1',fexp')))
+ ; e_record = (fun fexps -> let (fexps, fexps') = List.split fexps in (E_record fexps, E_record fexps'))
+ ; e_record_update = (fun ((e1,e1'),fexps) -> let (fexps, fexps') = List.split fexps in (E_record_update (e1,fexps), E_record_update (e1',fexps')))
; e_field = (fun ((e1,e1'),id) -> (E_field (e1,id), E_field (e1',id)))
; e_case = (fun ((e1,e1'),pexps) -> let (pexps, pexps') = List.split pexps in (E_case (e1,pexps), E_case (e1',pexps')))
; e_try = (fun ((e1,e1'),pexps) -> let (pexps, pexps') = List.split pexps in (E_try (e1,pexps), E_try (e1',pexps')))
@@ -543,8 +545,6 @@ let rewrite_sizeof (Defs defs) =
; lEXP_aux = (fun ((lexp,lexp'),annot) -> (LEXP_aux (lexp,annot), LEXP_aux (lexp',annot)))
; fE_Fexp = (fun (id,(e,e')) -> (FE_Fexp (id,e), FE_Fexp (id,e')))
; fE_aux = (fun ((fexp,fexp'),annot) -> (FE_aux (fexp,annot), FE_aux (fexp',annot)))
- ; fES_Fexps = (fun (fexps,b) -> let (fexps, fexps') = List.split fexps in (FES_Fexps (fexps,b), FES_Fexps (fexps',b)))
- ; fES_aux = (fun ((fexp,fexp'),annot) -> (FES_aux (fexp,annot), FES_aux (fexp',annot)))
; def_val_empty = (Def_val_empty, Def_val_empty)
; def_val_dec = (fun (e,e') -> (Def_val_dec e, Def_val_dec e'))
; def_val_aux = (fun ((defval,defval'),aux) -> (Def_val_aux (defval,aux), Def_val_aux (defval',aux)))
@@ -592,7 +592,7 @@ let rewrite_sizeof (Defs defs) =
let penv = env_of_annot pannot in
let peff = effect_of_annot (snd pannot) in
if KidSet.is_empty nvars then paux else
- match pat_typ_of paux with
+ match typ_of_pat paux with
| Typ_aux (Typ_tup typs, _) ->
let ptyp' = Typ_aux (Typ_tup (kid_typs @ typs), l) in
(match pat with
@@ -605,10 +605,10 @@ let rewrite_sizeof (Defs defs) =
| P_as (_, id) | P_id id ->
(* adding parameters here would change the type of id;
we should remove the P_as/P_id here and add a let-binding to the body *)
- raise (Reporting_basic.err_todo l
+ raise (Reporting.err_todo l
"rewriting as- or id-patterns for sizeof expressions not yet implemented")
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"unexpected pattern while rewriting function parameters for sizeof expressions"))
| ptyp ->
let ptyp' = Typ_aux (Typ_tup (kid_typs @ [ptyp]), l) in
@@ -649,6 +649,9 @@ let rewrite_sizeof (Defs defs) =
LB_val (pat, exp') in
(params_map, defs @ [DEF_val (LB_aux (lb', annot))])
end
+ | DEF_reg_dec (DEC_aux (DEC_config (id, typ, exp), annot)) ->
+ let exp' = fst (fold_exp { copy_exp_alg with e_aux = e_app_aux params_map } exp) in
+ (params_map, defs @ [DEF_reg_dec (DEC_aux (DEC_config (id, typ, exp'), annot))])
| def ->
(params_map, defs @ [def]) in
@@ -661,7 +664,7 @@ let rewrite_sizeof (Defs defs) =
| Typ_aux (Typ_fn (vtyp_args, vtyp_ret, declared_eff), vl) ->
Typ_aux (Typ_fn (kid_typs @ vtyp_args, vtyp_ret, declared_eff), vl)
| _ ->
- raise (Reporting_basic.err_typ l "val spec with non-function type") in
+ raise (Reporting.err_typ l "val spec with non-function type") in
TypSchm_aux (TypSchm_ts (tq, typ'), l)
else ts in
match def with
@@ -758,7 +761,7 @@ let remove_vector_concat_pat pat =
P_aux (P_app (id, List.map aux pats), a)
| _ ->
raise
- (Reporting_basic.err_unreachable
+ (Reporting.err_unreachable
l __POS__ "name_vector_concat_elements: Non-vector in vector-concat pattern") in
P_vector_concat (List.map aux pats) in
{id_pat_alg with p_vector_concat = p_vector_concat} in
@@ -806,7 +809,7 @@ let remove_vector_concat_pat pat =
then Big_int.sub (Big_int.add start length) (Big_int.of_int 1)
else Big_int.add (Big_int.sub start length) (Big_int.of_int 1))
| _ ->
- raise (Reporting_basic.err_unreachable (fst rannot') __POS__
+ raise (Reporting.err_unreachable (fst rannot') __POS__
("unname_vector_concat_elements: vector of unspecified length in vector-concat pattern"))) in
let rec aux typ_opt (pos,pat_acc,decl_acc) (P_aux (p,cannot),is_last) =
let ctyp = Env.base_typ_of (env_of_annot cannot) (typ_of_annot cannot) in
@@ -820,7 +823,7 @@ let remove_vector_concat_pat pat =
if is_last then (pos,last_idx)
else
raise
- (Reporting_basic.err_unreachable
+ (Reporting.err_unreachable
l __POS__ ("unname_vector_concat_elements: vector of unspecified length in vector-concat pattern")) in
(match p with
(* if we see a named vector pattern, remove the name and remember to
@@ -930,7 +933,7 @@ let remove_vector_concat_pat pat =
| _, _ ->
(*if is_last then*) acc @ [wild Big_int.zero]
else raise
- (Reporting_basic.err_unreachable l __POS__
+ (Reporting.err_unreachable l __POS__
("remove_vector_concats: Non-vector in vector-concat pattern " ^
string_of_typ (typ_of_annot annot))) in
@@ -1156,11 +1159,11 @@ let subst_id_exp exp (id1,id2) =
let rec pat_to_exp ((P_aux (pat,(l,annot))) as p_aux) =
let rewrap e = E_aux (e,(l,annot)) in
- let env = pat_env_of p_aux in
- let typ = pat_typ_of p_aux in
+ let env = env_of_pat p_aux in
+ let typ = typ_of_pat p_aux in
match pat with
| P_lit lit -> rewrap (E_lit lit)
- | P_wild -> raise (Reporting_basic.err_unreachable l __POS__
+ | P_wild -> raise (Reporting.err_unreachable l __POS__
"pat_to_exp given wildcard pattern")
| P_or(pat1, pat2) -> (* todo: insert boolean or *) pat_to_exp pat1
| P_not(pat) -> (* todo: insert boolean not *) pat_to_exp pat
@@ -1170,7 +1173,7 @@ let rec pat_to_exp ((P_aux (pat,(l,annot))) as p_aux) =
| P_id id -> rewrap (E_id id)
| P_app (id,pats) -> rewrap (E_app (id, List.map pat_to_exp pats))
| P_record (fpats,b) ->
- rewrap (E_record (FES_aux (FES_Fexps (List.map fpat_to_fexp fpats,b),(l,annot))))
+ rewrap (E_record (List.map fpat_to_fexp fpats))
| P_vector pats -> rewrap (E_vector (List.map pat_to_exp pats))
| P_vector_concat pats -> begin
let empty_vec = E_aux (E_vector [], (l,())) in
@@ -1248,7 +1251,7 @@ let rewrite_guarded_clauses l cs =
| ((pat,guard,body,annot) as c) :: cs ->
group_aux (remove_wildcards "g__" pat, [c], annot) [] cs
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"group given empty list in rewrite_guarded_clauses") in
let add_group cs groups = (if_pexp (groups @ fallthrough) cs) :: groups in
List.fold_right add_group groups []
@@ -1260,7 +1263,7 @@ let rewrite_guarded_clauses l cs =
let (Pat_aux (_,annot)) = pexp in
(pat, body, annot)
| [] ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"if_pexp given empty list in rewrite_guarded_clauses"))
and if_exp fallthrough current_pat = (function
| (pat,guard,body,annot) :: ((pat',guard',body',annot') as c') :: cs ->
@@ -1284,7 +1287,7 @@ let rewrite_guarded_clauses l cs =
fix_eff_exp (annot_exp (E_if (exp,body,else_exp)) (fst annot) (env_of exp) (typ_of body))
| _, _ -> body)
| [] ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"if_exp given empty list in rewrite_guarded_clauses")) in
group [] cs
@@ -1322,7 +1325,7 @@ let contains_bitvector_pexp = function
let remove_bitvector_pat (P_aux (_, (l, _)) as pat) =
- let env = try pat_env_of pat with _ -> Env.empty in
+ let env = try env_of_pat pat with _ -> Env.empty in
(* first introduce names for bitvector patterns *)
let name_bitvector_roots =
@@ -1360,7 +1363,7 @@ let remove_bitvector_pat (P_aux (_, (l, _)) as pat) =
} in
let pat, env = bind_pat_no_guard env
(strip_pat ((fold_pat name_bitvector_roots pat) false))
- (pat_typ_of pat) in
+ (typ_of_pat pat) in
(* Then collect guard expressions testing whether the literal bits of a
bitvector pattern match those of a given bitvector, and collect let
@@ -1419,7 +1422,7 @@ let remove_bitvector_pat (P_aux (_, (l, _)) as pat) =
let start_idx = match start with
| Nexp_aux (Nexp_constant s, _) -> s
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"guard_bitvector_pat called on pattern with non-constant start index") in
let add_bit_pat (idx, current, guards, dls) pat =
let idx' =
@@ -1607,7 +1610,7 @@ let rewrite_defs_remove_numeral_pats =
fold_pat { (compute_pat_alg None compose_guard_opt) with p_lit = p_lit outer_env } in
let pat_aux (pexp_aux, a) =
let pat,guard,exp,a = destruct_pexp (Pat_aux (pexp_aux, a)) in
- let guard',pat = guard_pat (pat_env_of pat) pat in
+ let guard',pat = guard_pat (env_of_pat pat) pat in
match compose_guard_opt guard guard' with
| Some g -> Pat_aux (Pat_when (pat, g, exp), a)
| None -> Pat_aux (Pat_exp (pat, exp), a) in
@@ -1725,17 +1728,18 @@ let rec rewrite_lexp_to_rhs ((LEXP_aux(lexp,((l,_) as annot))) as le) =
let env = env_of_annot lannot in
match Env.expand_synonyms env (typ_of_annot lannot) with
| Typ_aux (Typ_id rectyp_id, _) | Typ_aux (Typ_app (rectyp_id, _), _) when Env.is_record rectyp_id env ->
- let field_update exp = FES_aux (FES_Fexps ([FE_aux (FE_Fexp (id, exp), annot)], false), annot) in
- (lhs, (fun exp -> rhs (E_aux (E_record_update (lexp_to_exp lexp, field_update exp), lannot))))
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ ("Unsupported lexp: " ^ string_of_lexp le))
+ let field_update exp = FE_aux (FE_Fexp (id, exp), annot) in
+ (lhs, (fun exp -> rhs (E_aux (E_record_update (lexp_to_exp lexp, [field_update exp]), lannot))))
+ | _ -> raise (Reporting.err_unreachable l __POS__ ("Unsupported lexp: " ^ string_of_lexp le))
end
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ ("Unsupported lexp: " ^ string_of_lexp le))
+ | _ -> raise (Reporting.err_unreachable l __POS__ ("Unsupported lexp: " ^ string_of_lexp le))
let updates_vars exp =
let e_assign ((_, lexp), (u, exp)) =
(u || lexp_is_local lexp (env_of exp), E_assign (lexp, exp)) in
fst (fold_exp { (compute_exp_alg false (||)) with e_assign = e_assign } exp)
+
(*Expects to be called after rewrite_defs; thus the following should not appear:
internal_exp of any form
lit vectors in patterns or expressions
@@ -1759,72 +1763,18 @@ let rewrite_exp_lift_assign_intro rewriters ((E_aux (exp,((l,_) as annot))) as f
let effects = union_eff_exps exps' in
let block = E_aux (E_block exps', (gen_loc l, mk_tannot env unit_typ effects)) in
[fix_eff_exp (E_aux (E_var(le', e', block), annot))]
- (*| ((E_aux(E_if(c,t,e),(l,annot))) as exp)::exps ->
- let vars_t = introduced_variables t in
- let vars_e = introduced_variables e in
- let new_vars = Envmap.intersect vars_t vars_e in
- if Envmap.is_empty new_vars
- then (rewrite_base exp)::walker exps
- else
- let new_nmap = match nmap with
- | None -> Some(Nexpmap.empty,new_vars)
- | Some(nm,s) -> Some(nm, Envmap.union new_vars s) in
- let c' = rewrite_base c in
- let t' = rewriters.rewrite_exp rewriters new_nmap t in
- let e' = rewriters.rewrite_exp rewriters new_nmap e in
- let exps' = walker exps in
- fst ((Envmap.fold
- (fun (res,effects) i (t,e) ->
- let bitlit = E_aux (E_lit (L_aux(L_zero, Parse_ast.Generated l)),
- (Parse_ast.Generated l, simple_annot bit_t)) in
- let rangelit = E_aux (E_lit (L_aux (L_num 0, Parse_ast.Generated l)),
- (Parse_ast.Generated l, simple_annot nat_t)) in
- let set_exp =
- match t.t with
- | Tid "bit" | Tabbrev(_,{t=Tid "bit"}) -> bitlit
- | Tapp("range", _) | Tapp("atom", _) -> rangelit
- | Tapp("vector", [_;_;_;TA_typ ( {t=Tid "bit"} | {t=Tabbrev(_,{t=Tid "bit"})})])
- | Tapp(("reg"|"register"),[TA_typ ({t = Tapp("vector",
- [_;_;_;TA_typ ( {t=Tid "bit"}
- | {t=Tabbrev(_,{t=Tid "bit"})})])})])
- | Tabbrev(_,{t = Tapp("vector",
- [_;_;_;TA_typ ( {t=Tid "bit"}
- | {t=Tabbrev(_,{t=Tid "bit"})})])}) ->
- E_aux (E_vector_indexed([], Def_val_aux(Def_val_dec bitlit,
- (Parse_ast.Generated l,simple_annot bit_t))),
- (Parse_ast.Generated l, simple_annot t))
- | _ -> e in
- let unioneffs = union_effects effects (get_effsum_exp set_exp) in
- ([E_aux (E_var (LEXP_aux (LEXP_id (Id_aux (Id i, Parse_ast.Generated l)),
- (Parse_ast.Generated l, (tag_annot t Emp_intro))),
- set_exp,
- E_aux (E_block res, (Parse_ast.Generated l, (simple_annot_efr unit_t effects)))),
- (Parse_ast.Generated l, simple_annot_efr unit_t unioneffs))],unioneffs)))
- (E_aux(E_if(c',t',e'),(Parse_ast.Generated l, annot))::exps',eff_union_exps (c'::t'::e'::exps')) new_vars)*)
| e::exps -> (rewrite_rec e)::(walker exps)
in
- check_exp (env_of full_exp)
- (E_aux (E_block (List.map strip_exp (walker exps)), (l, ()))) (typ_of full_exp)
+ E_aux (E_block (walker exps), annot)
+
| E_assign(le,e)
when lexp_is_local_intro le (env_of full_exp) && not (lexp_is_effectful le) ->
let (le', re') = rewrite_lexp_to_rhs le in
let e' = re' (rewrite_base e) in
let block = annot_exp (E_block []) (gen_loc l) (env_of full_exp) unit_typ in
- check_exp (env_of full_exp)
- (strip_exp (E_aux (E_var(le', e', block), annot))) (typ_of full_exp)
- | _ -> rewrite_base full_exp
-
-(*let rewrite_lexp_lift_assign_intro rewriters ((LEXP_aux(lexp,annot)) as le) =
- let rewrap le = LEXP_aux(le,annot) in
- let rewrite_base = rewrite_lexp rewriters in
- match lexp, annot with
- | (LEXP_id id | LEXP_cast (_,id)), (l, Some (env, typ, eff)) ->
- (match Env.lookup_id id env with
- | Unbound | Local _ ->
- LEXP_aux (lexp, (l, Some (env, typ, union_effects eff (mk_effect [BE_lset]))))
- | _ -> rewrap lexp)
- | _ -> rewrite_base le*)
+ E_aux (E_var (le', e', block), annot)
+ | _ -> rewrite_base full_exp
let rewrite_defs_exp_lift_assign defs = rewrite_defs_base
{rewrite_exp = rewrite_exp_lift_assign_intro;
@@ -1866,56 +1816,6 @@ let rewrite_register_ref_writes (Defs defs) =
| [] -> [] in
Defs (rewrite (write_reg_spec @ defs))
- (* rewrite_defs_base { rewriters_base with rewrite_exp = rewrite_exp }
- (Defs (write_reg_spec @ defs)) *)
-
-
-(*let rewrite_exp_separate_ints rewriters ((E_aux (exp,((l,_) as annot))) as full_exp) =
- (*let tparms,t,tag,nexps,eff,cum_eff,bounds = match annot with
- | Base((tparms,t),tag,nexps,eff,cum_eff,bounds) -> tparms,t,tag,nexps,eff,cum_eff,bounds
- | _ -> [],unit_t,Emp_local,[],pure_e,pure_e,nob in*)
- let rewrap e = E_aux (e,annot) in
- (*let rewrap_effects e effsum =
- E_aux (e,(l,Base ((tparms,t),tag,nexps,eff,effsum,bounds))) in*)
- let rewrite_rec = rewriters.rewrite_exp rewriters in
- let rewrite_base = rewrite_exp rewriters in
- match exp with
- | E_lit (L_aux (((L_num _) as lit),_)) ->
- (match (is_within_machine64 t nexps) with
- | Yes -> let _ = Printf.eprintf "Rewriter of num_const, within 64bit int yes\n" in rewrite_base full_exp
- | Maybe -> let _ = Printf.eprintf "Rewriter of num_const, within 64bit int maybe\n" in rewrite_base full_exp
- | No -> let _ = Printf.eprintf "Rewriter of num_const, within 64bit int no\n" in E_aux(E_app(Id_aux (Id "integer_of_int",l),[rewrite_base full_exp]),
- (l, Base((tparms,t),External(None),nexps,eff,cum_eff,bounds))))
- | E_cast (typ, exp) -> rewrap (E_cast (typ, rewrite_rec exp))
- | E_app (id,exps) -> rewrap (E_app (id,List.map rewrite_rec exps))
- | E_app_infix(el,id,er) -> rewrap (E_app_infix(rewrite_rec el,id,rewrite_rec er))
- | E_for (id, e1, e2, e3, o, body) ->
- rewrap (E_for (id, rewrite_rec e1, rewrite_rec e2, rewrite_rec e3, o, rewrite_rec body))
- | E_vector_access (vec,index) -> rewrap (E_vector_access (rewrite_rec vec,rewrite_rec index))
- | E_vector_subrange (vec,i1,i2) ->
- rewrap (E_vector_subrange (rewrite_rec vec,rewrite_rec i1,rewrite_rec i2))
- | E_vector_update (vec,index,new_v) ->
- rewrap (E_vector_update (rewrite_rec vec,rewrite_rec index,rewrite_rec new_v))
- | E_vector_update_subrange (vec,i1,i2,new_v) ->
- rewrap (E_vector_update_subrange (rewrite_rec vec,rewrite_rec i1,rewrite_rec i2,rewrite_rec new_v))
- | E_case (exp ,pexps) ->
- rewrap (E_case (rewrite_rec exp,
- (List.map
- (fun (Pat_aux (Pat_exp(p,e),pannot)) ->
- Pat_aux (Pat_exp(rewriters.rewrite_pat rewriters nmap p,rewrite_rec e),pannot)) pexps)))
- | E_let (letbind,body) -> rewrap (E_let(rewriters.rewrite_let rewriters nmap letbind,rewrite_rec body))
- | E_var (lexp,exp,body) ->
- rewrap (E_var (rewriters.rewrite_lexp rewriters nmap lexp, rewrite_rec exp, rewrite_rec body))
- | _ -> rewrite_base full_exp
-
-let rewrite_defs_separate_numbs defs = rewrite_defs_base
- {rewrite_exp = rewrite_exp_separate_ints;
- rewrite_pat = rewrite_pat;
- rewrite_let = rewrite_let; (*will likely need a new one?*)
- rewrite_lexp = rewrite_lexp; (*will likely need a new one?*)
- rewrite_fun = rewrite_fun;
- rewrite_def = rewrite_def;
- rewrite_defs = rewrite_defs_base} defs*)
(* Remove redundant return statements, and translate remaining ones into an
(effectful) call to builtin function "early_return" (in the Lem shallow
@@ -2093,7 +1993,7 @@ let rewrite_defs_early_return (Defs defs) =
let swaptyp typ (l,tannot) = match destruct_tannot tannot with
| Some (env, typ', eff) -> (l, mk_tannot env typ eff)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "swaptyp called with empty type annotation")
+ | _ -> raise (Reporting.err_unreachable l __POS__ "swaptyp called with empty type annotation")
let is_funcl_rec (FCL_aux (FCL_Funcl (id, pexp), _)) =
let pat,guard,exp,pannot = destruct_pexp pexp in
@@ -2131,7 +2031,7 @@ let rewrite_split_fun_constr_pats fun_name (Defs defs) =
let pat, guard, exp, annot = destruct_pexp pexp in
match pat with
| P_aux (P_app (constr_id, args), pannot) ->
- let argstup_typ = tuple_typ (List.map pat_typ_of args) in
+ let argstup_typ = tuple_typ (List.map typ_of_pat args) in
let pannot' = swaptyp argstup_typ pannot in
let pat' =
match args with
@@ -2172,9 +2072,9 @@ let rewrite_split_fun_constr_pats fun_name (Defs defs) =
let env, args_typ, ret_typ = match funcls with
| FCL_aux (FCL_Funcl (_, pexp), _) :: _ ->
let pat, _, exp, _ = destruct_pexp pexp in
- env_of exp, pat_typ_of pat, typ_of exp
+ env_of exp, typ_of_pat pat, typ_of exp
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"rewrite_split_fun_constr_pats: empty auxiliary function")
in
let eff = List.fold_left
@@ -2196,7 +2096,7 @@ let rewrite_split_fun_constr_pats fun_name (Defs defs) =
let quant_tyvars = List.fold_left KidSet.union KidSet.empty (List.map tyvars_of_quant_item qis) in
let typ_tyvars = tyvars_of_typ fun_typ in
let new_tyvars = KidSet.diff typ_tyvars quant_tyvars in
- List.map (mk_qi_id BK_int) (KidSet.elements new_tyvars)
+ List.map (mk_qi_id K_int) (KidSet.elements new_tyvars)
in
let typquant = match typquant with
| TypQ_aux (TypQ_tq qis, l) ->
@@ -2208,7 +2108,7 @@ let rewrite_split_fun_constr_pats fun_name (Defs defs) =
in
TypQ_aux (TypQ_tq qis, l)
| _ ->
- TypQ_aux (TypQ_tq (List.map (mk_qi_id BK_int) (KidSet.elements (tyvars_of_typ fun_typ))), l)
+ TypQ_aux (TypQ_tq (List.map (mk_qi_id K_int) (KidSet.elements (tyvars_of_typ fun_typ))), l)
in
let val_spec =
VS_aux (VS_val_spec
@@ -2242,7 +2142,7 @@ let rewrite_fix_val_specs (Defs defs) =
begin
try Env.get_val_spec id env with
| _ ->
- raise (Reporting_basic.err_unreachable (Parse_ast.Unknown) __POS__
+ raise (Reporting.err_unreachable (Parse_ast.Unknown) __POS__
("No val spec found for " ^ string_of_id id))
end
in
@@ -2304,9 +2204,11 @@ let rewrite_fix_val_specs (Defs defs) =
(* Repeat once to cross-propagate effects between clauses *)
let (val_specs, funcls) = List.fold_left rewrite_funcl (val_specs, []) funcls in
let recopt =
- if List.exists is_funcl_rec funcls then
- Rec_aux (Rec_rec, Parse_ast.Unknown)
- else recopt
+ match recopt with
+ | Rec_aux ((Rec_rec | Rec_measure _), _) -> recopt
+ | _ when List.exists is_funcl_rec funcls ->
+ Rec_aux (Rec_rec, Parse_ast.Unknown)
+ | _ -> recopt
in
let tannotopt = match tannotopt, funcls with
| Typ_annot_opt_aux (Typ_annot_opt_some (typq, typ), l),
@@ -2402,9 +2304,10 @@ let rewrite_constraint =
let rewrite_type_union_typs rw_typ (Tu_aux (Tu_ty_id (typ, id), annot)) =
Tu_aux (Tu_ty_id (rw_typ typ, id), annot)
-let rewrite_type_def_typs rw_typ rw_typquant rw_typschm (TD_aux (td, annot)) =
+let rewrite_type_def_typs rw_typ rw_typquant (TD_aux (td, annot)) =
match td with
- | TD_abbrev (id, nso, typschm) -> TD_aux (TD_abbrev (id, nso, rw_typschm typschm), annot)
+ | TD_abbrev (id, typq, A_aux (A_typ typ, l)) ->
+ TD_aux (TD_abbrev (id, rw_typquant typq, A_aux (A_typ (rw_typ typ), l)), annot)
| TD_record (id, nso, typq, typ_ids, flag) ->
TD_aux (TD_record (id, nso, rw_typquant typq, List.map (fun (typ, id) -> (rw_typ typ, id)) typ_ids, flag), annot)
| TD_variant (id, nso, typq, tus, flag) ->
@@ -2456,8 +2359,8 @@ let rewrite_undefined_if_gen always_bitvector defs =
let rec simple_typ (Typ_aux (typ_aux, l) as typ) = Typ_aux (simple_typ_aux typ_aux, l)
and simple_typ_aux = function
| Typ_id id -> Typ_id id
- | Typ_app (id, [_; _; Typ_arg_aux (Typ_arg_typ typ, l)]) when Id.compare id (mk_id "vector") = 0 ->
- Typ_app (mk_id "list", [Typ_arg_aux (Typ_arg_typ (simple_typ typ), l)])
+ | Typ_app (id, [_; _; A_aux (A_typ typ, l)]) when Id.compare id (mk_id "vector") = 0 ->
+ Typ_app (mk_id "list", [A_aux (A_typ (simple_typ typ), l)])
| Typ_app (id, [_]) when Id.compare id (mk_id "atom") = 0 ->
Typ_id (mk_id "int")
| Typ_app (id, [_; _]) when Id.compare id (mk_id "range") = 0 ->
@@ -2467,9 +2370,9 @@ and simple_typ_aux = function
| Typ_tup typs -> Typ_tup (List.map simple_typ typs)
| Typ_exist (_, _, Typ_aux (typ, l)) -> simple_typ_aux typ
| typ_aux -> typ_aux
-and simple_typ_arg (Typ_arg_aux (typ_arg_aux, l)) =
+and simple_typ_arg (A_aux (typ_arg_aux, l)) =
match typ_arg_aux with
- | Typ_arg_typ typ -> [Typ_arg_aux (Typ_arg_typ (simple_typ typ), l)]
+ | A_typ typ -> [A_aux (A_typ (simple_typ typ), l)]
| _ -> []
(* This pass aims to remove all the Num quantifiers from the specification. *)
@@ -2498,7 +2401,7 @@ let rewrite_simple_types (Defs defs) =
in
let simple_def = function
| DEF_spec vs -> DEF_spec (simple_vs vs)
- | DEF_type td -> DEF_type (rewrite_type_def_typs simple_typ simple_typquant simple_typschm td)
+ | DEF_type td -> DEF_type (rewrite_type_def_typs simple_typ simple_typquant td)
| DEF_reg_dec ds -> DEF_reg_dec (rewrite_dec_spec_typs simple_typ ds)
| def -> def
in
@@ -2570,7 +2473,7 @@ let rewrite_vector_concat_assignments defs =
begin
try check_exp env e_aux unit_typ with
| Type_error (l, err) ->
- raise (Reporting_basic.err_typ l (Type_error.string_of_type_error err))
+ raise (Reporting.err_typ l (Type_error.string_of_type_error err))
end
else E_aux (e_aux, annot)
| _ -> E_aux (e_aux, annot)
@@ -2591,12 +2494,15 @@ let rewrite_tuple_assignments defs =
let (_, ids) = List.fold_left (fun (n, ids) _ -> (n + 1, ids @ [mk_id ("tup__" ^ string_of_int n)])) (0, []) lexps in
let block_assign i lexp = mk_exp (E_assign (strip_lexp lexp, mk_exp (E_id (mk_id ("tup__" ^ string_of_int i))))) in
let block = mk_exp (E_block (List.mapi block_assign lexps)) in
- let letbind = mk_letbind (mk_pat (P_tup (List.map (fun id -> mk_pat (P_id id)) ids))) (strip_exp exp) in
+ let letbind = mk_letbind (mk_pat (P_typ (Type_check.typ_of exp,
+ mk_pat (P_tup (List.map (fun id -> mk_pat (P_id id)) ids)))))
+ (strip_exp exp)
+ in
let let_exp = mk_exp (E_let (letbind, block)) in
begin
try check_exp env let_exp unit_typ with
| Type_error (l, err) ->
- raise (Reporting_basic.err_typ l (Type_error.string_of_type_error err))
+ raise (Reporting.err_typ l (Type_error.string_of_type_error err))
end
| _ -> E_aux (e_aux, annot)
in
@@ -2641,7 +2547,7 @@ let rewrite_defs_remove_blocks =
let e_aux = function
| (E_block es,(l,_)) -> f l es
| (e,annot) -> E_aux (e,annot) in
-
+
let alg = { id_exp_alg with e_aux = e_aux } in
rewrite_defs_base
@@ -2672,7 +2578,7 @@ let letbind (v : 'a exp) (body : 'a exp -> 'a exp) : 'a exp =
let body = body (annot_exp (E_id id) l env typ) in
fix_eff_exp (annot_exp (E_let (lb, body)) l env (typ_of body))
| None ->
- raise (Reporting_basic.err_unreachable l __POS__ "no type information")
+ raise (Reporting.err_unreachable l __POS__ "no type information")
let rec mapCont (f : 'b -> ('b -> 'a exp) -> 'a exp) (l : 'b list) (k : 'b list -> 'a exp) : 'a exp =
@@ -2687,7 +2593,7 @@ let rewrite_defs_letbind_effects =
and value_optdefault (Def_val_aux (o,_)) = match o with
| Def_val_empty -> true
| Def_val_dec e -> value e
- and value_fexps (FES_aux (FES_Fexps (fexps,_),_)) =
+ and value_fexps fexps =
List.fold_left (fun b (FE_aux (FE_Fexp (_,e),_)) -> b && value e) true fexps in
@@ -2718,11 +2624,6 @@ let rewrite_defs_letbind_effects =
and n_pexpL (newreturn : bool) (pexps : 'a pexp list) (k : 'a pexp list -> 'a exp) : 'a exp =
mapCont (n_pexp newreturn) pexps k
- and n_fexps (fexps : 'a fexps) (k : 'a fexps -> 'a exp) : 'a exp =
- let (FES_aux (FES_Fexps (fexps_aux,b),annot)) = fexps in
- n_fexpL fexps_aux (fun fexps_aux ->
- k (fix_eff_fexps (FES_aux (FES_Fexps (fexps_aux,b),annot))))
-
and n_opt_default (opt_default : 'a opt_default) (k : 'a opt_default -> 'a exp) : 'a exp =
let (Def_val_aux (opt_default,annot)) = opt_default in
match opt_default with
@@ -2871,11 +2772,11 @@ let rewrite_defs_letbind_effects =
n_exp_name exp2 (fun exp2 ->
k (rewrap (E_cons (exp1,exp2)))))
| E_record fexps ->
- n_fexps fexps (fun fexps ->
+ n_fexpL fexps (fun fexps ->
k (rewrap (E_record fexps)))
| E_record_update (exp1,fexps) ->
n_exp_name exp1 (fun exp1 ->
- n_fexps fexps (fun fexps ->
+ n_fexpL fexps (fun fexps ->
k (rewrap (E_record_update (exp1,fexps)))))
| E_field (exp1,id) ->
n_exp_name exp1 (fun exp1 ->
@@ -2968,7 +2869,7 @@ let rewrite_defs_internal_lets =
| LEXP_id id -> P_aux (P_id id, annot)
| LEXP_cast (typ, id) -> add_p_typ typ (P_aux (P_id id, annot))
| LEXP_tup lexps -> P_aux (P_tup (List.map pat_of_local_lexp lexps), annot)
- | _ -> raise (Reporting_basic.err_unreachable l __POS__ "unexpected local lexp") in
+ | _ -> raise (Reporting.err_unreachable l __POS__ "unexpected local lexp") in
let e_let (lb,body) =
match lb with
@@ -3032,13 +2933,13 @@ let rewrite_pexp_with_guards rewrite_pat (Pat_aux (pexp_aux, (annot: tannot anno
| [] -> pexp
| gs ->
let unchecked_pexp = mk_pexp (Pat_when (strip_pat pat, List.map strip_exp gs |> fold_guards, strip_exp exp)) in
- check_case (pat_env_of pat) (pat_typ_of pat) unchecked_pexp (typ_of exp)
+ check_case (env_of_pat pat) (typ_of_pat pat) unchecked_pexp (typ_of exp)
end
| Pat_when (pat, guard, exp) ->
begin
let pat = fold_pat { id_pat_alg with p_aux = rewrite_pat guards } pat in
let unchecked_pexp = mk_pexp (Pat_when (strip_pat pat, List.map strip_exp !guards |> fold_guards, strip_exp exp)) in
- check_case (pat_env_of pat) (pat_typ_of pat) unchecked_pexp (typ_of exp)
+ check_case (env_of_pat pat) (typ_of_pat pat) unchecked_pexp (typ_of exp)
end
@@ -3077,7 +2978,7 @@ let rec bindings_of_pat (P_aux (p_aux, p_annot) as pat) =
| P_record _ -> failwith "record patterns not yet implemented"
(* we assume the type-checker has already checked the two sides have the same bindings *)
| P_or (left, right) -> bindings_of_pat left
- | P_as (p, id) -> [annot_pat (P_id id) unk (pat_env_of p) (pat_typ_of p)]
+ | P_as (p, id) -> [annot_pat (P_id id) unk (env_of_pat p) (typ_of_pat p)]
| P_cons (left, right) -> bindings_of_pat left @ bindings_of_pat right
(* todo: is this right for negated patterns? *)
| P_not p
@@ -3093,11 +2994,11 @@ let rec bindings_of_pat (P_aux (p_aux, p_annot) as pat) =
let rec binding_typs_of_pat (P_aux (p_aux, p_annot) as pat) =
match p_aux with
| P_lit _ | P_wild -> []
- | P_id id -> [pat_typ_of pat]
+ | P_id id -> [typ_of_pat pat]
| P_record _ -> failwith "record patterns not yet implemented"
(* we assume the type-checker has already checked the two sides have the same bindings *)
| P_or (left, right) -> binding_typs_of_pat left
- | P_as (p, id) -> [pat_typ_of p]
+ | P_as (p, id) -> [typ_of_pat p]
| P_cons (left, right) -> binding_typs_of_pat left @ binding_typs_of_pat right
(* todo: is this right for negated patterns? *)
| P_not p
@@ -3113,7 +3014,7 @@ let rec binding_typs_of_pat (P_aux (p_aux, p_annot) as pat) =
let construct_toplevel_string_append_call env f_id bindings binding_typs guard expr =
(* s# if match f#(s#) { Some (bindings) => guard, _ => false) } => let Some(bindings) = f#(s#) in expr *)
let s_id = fresh_stringappend_id () in
- let option_typ = app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (match binding_typs with
+ let option_typ = app_typ (mk_id "option") [A_aux (A_typ (match binding_typs with
| [] -> unit_typ
| [typ] -> typ
| typs -> tuple_typ typs
@@ -3145,7 +3046,7 @@ let construct_toplevel_string_append_func env f_id pat =
else
bindings
in
- let option_typ = app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (match binding_typs with
+ let option_typ = app_typ (mk_id "option") [A_aux (A_typ (match binding_typs with
| [] -> unit_typ
| [typ] -> typ
| typs -> tuple_typ typs
@@ -3205,7 +3106,7 @@ let construct_toplevel_string_append_func env f_id pat =
in
let mapping_inner_typ =
match Env.get_val_spec (mk_id mapping_prefix_func) env with
- | (_, Typ_aux (Typ_fn (_, Typ_aux (Typ_app (_, [Typ_arg_aux (Typ_arg_typ typ, _)]), _), _), _)) -> typ
+ | (_, Typ_aux (Typ_fn (_, Typ_aux (Typ_app (_, [A_aux (A_typ typ, _)]), _), _), _)) -> typ
| _ -> typ_error Parse_ast.Unknown "mapping prefix func without correct function type?"
in
@@ -3222,11 +3123,11 @@ let construct_toplevel_string_append_func env f_id pat =
[annot_exp (E_id s_id) unk env string_typ]))
unk env mapping_inner_typ in
(* construct some pattern -- Some (n#, len#) *)
- let opt_typ = app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ mapping_inner_typ, unk)] in
+ let opt_typ = app_typ (mk_id "option") [A_aux (A_typ mapping_inner_typ, unk)] in
let tup_arg_pat = match arg_pats with
| [] -> assert false
| [arg_pat] -> arg_pat
- | arg_pats -> annot_pat (P_tup arg_pats) unk env (tuple_typ (List.map pat_typ_of arg_pats))
+ | arg_pats -> annot_pat (P_tup arg_pats) unk env (tuple_typ (List.map typ_of_pat arg_pats))
in
let some_pat = annot_pat (P_app (mk_id "Some",
@@ -3381,7 +3282,7 @@ let rec rewrite_defs_pat_string_append =
in
let mapping_inner_typ =
match Env.get_val_spec (mk_id mapping_prefix_func) env with
- | (_, Typ_aux (Typ_fn (_, Typ_aux (Typ_app (_, [Typ_arg_aux (Typ_arg_typ typ, _)]), _), _), _)) -> typ
+ | (_, Typ_aux (Typ_fn (_, Typ_aux (Typ_app (_, [A_aux (A_typ typ, _)]), _), _), _)) -> typ
| _ -> typ_error Parse_ast.Unknown "mapping prefix func without correct function type?"
in
@@ -3398,11 +3299,11 @@ let rec rewrite_defs_pat_string_append =
[annot_exp (E_id s_id) unk env string_typ]))
unk env mapping_inner_typ in
(* construct some pattern -- Some (n#, len#) *)
- let opt_typ = app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ mapping_inner_typ, unk)] in
+ let opt_typ = app_typ (mk_id "option") [A_aux (A_typ mapping_inner_typ, unk)] in
let tup_arg_pat = match arg_pats with
| [] -> assert false
| [arg_pat] -> arg_pat
- | arg_pats -> annot_pat (P_tup arg_pats) unk env (tuple_typ (List.map pat_typ_of arg_pats))
+ | arg_pats -> annot_pat (P_tup arg_pats) unk env (tuple_typ (List.map typ_of_pat arg_pats))
in
let some_pat = annot_pat (P_app (mk_id "Some",
@@ -3450,13 +3351,13 @@ let rec rewrite_defs_pat_string_append =
| [] -> assert false
| [arg_pat] -> annot_letbind
(P_tup [arg_pat; annot_pat (P_id len_id) unk env nat_typ], new_binding)
- unk env (tuple_typ [pat_typ_of arg_pat; nat_typ])
+ unk env (tuple_typ [typ_of_pat arg_pat; nat_typ])
| arg_pats -> annot_letbind
(P_tup
- [annot_pat (P_tup arg_pats) unk env (tuple_typ (List.map pat_typ_of arg_pats));
+ [annot_pat (P_tup arg_pats) unk env (tuple_typ (List.map typ_of_pat arg_pats));
annot_pat (P_id len_id) unk env nat_typ],
new_binding)
- unk env (tuple_typ [tuple_typ (List.map pat_typ_of arg_pats); nat_typ])
+ unk env (tuple_typ [tuple_typ (List.map typ_of_pat arg_pats); nat_typ])
in
let new_let = annot_exp (E_let (new_letbind, new_match)) unk env (typ_of expr) in
@@ -3562,7 +3463,7 @@ let rewrite_defs_mapping_patterns =
expr_ref := e;
p
in
- let env = pat_env_of pat in
+ let env = env_of_pat pat in
match pat with
(*
mapping(args) if g => expr ----> s# if mapping_matches(s#)
@@ -3769,10 +3670,10 @@ let rec rewrite_var_updates ((E_aux (expaux,((l,_) as annot))) as exp) =
let tuple_pat = function
| [] -> annot_pat P_wild l env unit_typ
| [pat] ->
- let typ = pat_typ_of pat in
+ let typ = typ_of_pat pat in
add_p_typ typ pat
| pats ->
- let typ = tuple_typ (List.map pat_typ_of pats) in
+ let typ = tuple_typ (List.map typ_of_pat pats) in
add_p_typ typ (annot_pat (P_tup pats) l env typ) in
let rec add_vars overwrite ((E_aux (expaux,annot)) as exp) vars =
@@ -3832,9 +3733,9 @@ let rec rewrite_var_updates ((E_aux (expaux,((l,_) as annot))) as exp) =
in
let exp4 = rewrite_var_updates (add_vars overwrite exp4 vars) in
let ord_exp, kids, constr, lower, upper, lower_exp, upper_exp =
- match destruct_numeric env (typ_of exp1), destruct_numeric env (typ_of exp2) with
+ match destruct_numeric (Env.expand_synonyms env (typ_of exp1)), destruct_numeric (Env.expand_synonyms env (typ_of exp2)) with
| None, _ | _, None ->
- raise (Reporting_basic.err_unreachable el __POS__ "Could not determine loop bounds")
+ raise (Reporting.err_unreachable el __POS__ "Could not determine loop bounds")
| Some (kids1, constr1, n1), Some (kids2, constr2, n2) ->
let kids = kids1 @ kids2 in
let constr = nc_and constr1 constr2 in
@@ -3848,7 +3749,7 @@ let rec rewrite_var_updates ((E_aux (expaux,((l,_) as annot))) as exp) =
(* Bind the loop variable in the body, annotated with constraints *)
let lvar_kid = mk_kid ("loop_" ^ string_of_id id) in
let lvar_nc = nc_and constr (nc_and (nc_lteq lower (nvar lvar_kid)) (nc_lteq (nvar lvar_kid) upper)) in
- let lvar_typ = mk_typ (Typ_exist (lvar_kid :: kids, lvar_nc, atom_typ (nvar lvar_kid))) in
+ let lvar_typ = mk_typ (Typ_exist (List.map (mk_kopt K_int) (lvar_kid :: kids), lvar_nc, atom_typ (nvar lvar_kid))) in
let lvar_pat = unaux_pat (add_p_typ lvar_typ (annot_pat (P_var (
annot_pat (P_id id) el env (atom_typ (nvar lvar_kid)),
TP_aux (TP_var lvar_kid, gen_loc el))) el env lvar_typ)) in
@@ -3940,7 +3841,7 @@ let rec rewrite_var_updates ((E_aux (expaux,((l,_) as annot))) as exp) =
let pannot = (l, mk_tannot (env_of exp) (typ_of exp) (effect_of exp)) in
Pat_aux (Pat_exp (pat, exp), pannot)
| Pat_when _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"Guarded patterns should have been rewritten already") in
let ps = List.map rewrite_pexp ps in
let expaux = if is_case then E_case (e1, ps) else E_try (e1, ps) in
@@ -3954,7 +3855,7 @@ let rec rewrite_var_updates ((E_aux (expaux,((l,_) as annot))) as exp) =
| Local (_, typ) ->
add_p_typ typ (annot_pat (P_id id) pl env typ)
| _ ->
- raise (Reporting_basic.err_unreachable pl __POS__
+ raise (Reporting.err_unreachable pl __POS__
("Failed to look up type of variable " ^ string_of_id id)) in
if effectful exp then
Same_vars (E_aux (E_assign (lexp,vexp),annot))
@@ -4000,7 +3901,7 @@ let rec rewrite_var_updates ((E_aux (expaux,((l,_) as annot))) as exp) =
| LEXP_aux (LEXP_cast (typ, id), _) ->
unaux_pat (add_p_typ typ (annot_pat (P_id id) l env (typ_of v))), typ
| _ ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"E_var with a lexp that is not a variable") in
let lb = fix_eff_lb (annot_letbind (paux, v) l env typ) in
let exp = fix_eff_exp (annot_exp (E_let (lb, body)) l env (typ_of body)) in
@@ -4029,14 +3930,14 @@ let remove_reference_types exp =
let rec rewrite_t (Typ_aux (t_aux,a)) = (Typ_aux (rewrite_t_aux t_aux,a))
and rewrite_t_aux t_aux = match t_aux with
- | Typ_app (Id_aux (Id "reg",_), [Typ_arg_aux (Typ_arg_typ (Typ_aux (t_aux2, _)), _)]) ->
+ | Typ_app (Id_aux (Id "reg",_), [A_aux (A_typ (Typ_aux (t_aux2, _)), _)]) ->
rewrite_t_aux t_aux2
| Typ_app (name,t_args) -> Typ_app (name,List.map rewrite_t_arg t_args)
| Typ_fn (arg_typs, ret_typ, eff) -> Typ_fn (List.map rewrite_t arg_typs, rewrite_t ret_typ, eff)
| Typ_tup ts -> Typ_tup (List.map rewrite_t ts)
| _ -> t_aux
and rewrite_t_arg t_arg = match t_arg with
- | Typ_arg_aux (Typ_arg_typ t, a) -> Typ_arg_aux (Typ_arg_typ (rewrite_t t), a)
+ | A_aux (A_typ t, a) -> A_aux (A_typ (rewrite_t t), a)
| _ -> t_arg in
let rec rewrite_annot (l, tannot) =
@@ -4081,6 +3982,56 @@ let rewrite_defs_remove_superfluous_letbinds =
; rewrite_defs = rewrite_defs_base
}
+(* FIXME: We shouldn't allow nested not-patterns *)
+let rewrite_defs_not_pats =
+ let rewrite_pexp (pexp_aux, annot) =
+ let rewrite_pexp' pat exp orig_guard =
+ let guards = ref [] in
+ let not_counter = ref 0 in
+ let rewrite_not_pat (pat_aux, annot) =
+ match pat_aux with
+ | P_not pat ->
+ incr not_counter;
+ let np_id = mk_id ("np#" ^ string_of_int !not_counter) in
+ let guard =
+ mk_exp (E_case (mk_exp (E_id np_id),
+ [mk_pexp (Pat_exp (strip_pat pat, mk_lit_exp L_false));
+ mk_pexp (Pat_exp (mk_pat P_wild, mk_lit_exp L_true))]))
+ in
+ guards := (np_id, typ_of_annot annot, guard) :: !guards;
+ P_aux (P_id np_id, annot)
+
+ | _ -> P_aux (pat_aux, annot)
+ in
+ let pat = fold_pat { id_pat_alg with p_aux = rewrite_not_pat } pat in
+ begin match !guards with
+ | [] ->
+ Pat_aux (pexp_aux, annot)
+ | guards ->
+ let guard_exp =
+ match orig_guard, guards with
+ | Some guard, _ ->
+ List.fold_left (fun exp1 (_, _, exp2) -> mk_exp (E_app_infix (exp1, mk_id "&", exp2))) guard guards
+ | None, (_, _, guard) :: guards ->
+ List.fold_left (fun exp1 (_, _, exp2) -> mk_exp (E_app_infix (exp1, mk_id "&", exp2))) guard guards
+ | _ -> raise (Reporting.err_unreachable (fst annot) __POS__ "Case in not-pattern re-writing should be unreachable")
+ in
+ (* We need to construct an environment to check the match guard in *)
+ let env = env_of_pat pat in
+ let env = List.fold_left (fun env (np_id, np_typ, _) -> Env.add_local np_id (Immutable, np_typ) env) env guards in
+ let guard_exp = Type_check.check_exp env guard_exp bool_typ in
+ Pat_aux (Pat_when (pat, guard_exp, exp), annot)
+ end
+ in
+ match pexp_aux with
+ | Pat_exp (pat, exp) ->
+ rewrite_pexp' pat exp None
+ | Pat_when (pat, guard, exp) ->
+ rewrite_pexp' pat exp (Some (strip_exp guard))
+ in
+ let rw_exp = { id_exp_alg with pat_aux = rewrite_pexp } in
+ rewrite_defs_base { rewriters_base with rewrite_exp = (fun _ -> fold_exp rw_exp) }
+
let rewrite_defs_remove_superfluous_returns =
let add_opt_cast typopt1 typopt2 annot exp =
@@ -4202,7 +4153,7 @@ and fexps_of_mfpats mfpats flag annot =
let fexp_of_mfpat (MFP_aux (MFP_mpat (id, mpat), annot)) =
FE_aux (FE_Fexp (id, exp_of_mpat mpat), annot)
in
- FES_aux (FES_Fexps (List.map fexp_of_mfpat mfpats, flag), annot)
+ List.map fexp_of_mfpat mfpats
and pat_of_mpat (MP_aux (mpat, annot)) =
match mpat with
@@ -4331,7 +4282,8 @@ let rewrite_defs_realise_mappings (Defs defs) =
let non_rec = (Rec_aux (Rec_nonrec, Parse_ast.Unknown)) in
let effect_pure = (Effect_opt_aux (Effect_opt_pure, Parse_ast.Unknown)) in
- let env = match mapcls with
+ (* We need to make sure we get the environment for the last mapping clause *)
+ let env = match List.rev mapcls with
| MCL_aux (_, mapcl_annot) :: _ -> env_of_annot mapcl_annot
| _ -> Type_check.typ_error l "mapping with no clauses?"
in
@@ -4381,7 +4333,7 @@ let rewrite_defs_realise_mappings (Defs defs) =
let prefix_wildcard = mk_pexp (Pat_exp (mk_pat P_wild, mk_exp (E_app (mk_id "None", [mk_exp (E_lit (mk_lit L_unit))])))) in
let string_defs =
begin if subtype_check env typ1 string_typ && subtype_check env string_typ typ1 then
- let forwards_prefix_typ = Typ_aux (Typ_fn ([typ1], app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (tuple_typ [typ2; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
+ let forwards_prefix_typ = Typ_aux (Typ_fn ([typ1], app_typ (mk_id "option") [A_aux (A_typ (tuple_typ [typ2; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
let forwards_prefix_spec = VS_aux (VS_val_spec (mk_typschm typq forwards_prefix_typ, prefix_id, [], false), (Parse_ast.Unknown,())) in
let forwards_prefix_spec, env = Type_check.check_val_spec env forwards_prefix_spec in
let forwards_prefix_match = mk_exp (E_case (arg_exp, ((List.map (fun mapcl -> strip_mapcl mapcl |> realise_prefix_mapcl true prefix_id) mapcls) |> List.flatten) @ [prefix_wildcard])) in
@@ -4391,7 +4343,7 @@ let rewrite_defs_realise_mappings (Defs defs) =
forwards_prefix_spec @ forwards_prefix_fun
else
if subtype_check env typ2 string_typ && subtype_check env string_typ typ2 then
- let backwards_prefix_typ = Typ_aux (Typ_fn ([typ2], app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (tuple_typ [typ1; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
+ let backwards_prefix_typ = Typ_aux (Typ_fn ([typ2], app_typ (mk_id "option") [A_aux (A_typ (tuple_typ [typ1; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
let backwards_prefix_spec = VS_aux (VS_val_spec (mk_typschm typq backwards_prefix_typ, prefix_id, [], false), (Parse_ast.Unknown,())) in
let backwards_prefix_spec, env = Type_check.check_val_spec env backwards_prefix_spec in
let backwards_prefix_match = mk_exp (E_case (arg_exp, ((List.map (fun mapcl -> strip_mapcl mapcl |> realise_prefix_mapcl false prefix_id) mapcls) |> List.flatten) @ [prefix_wildcard])) in
@@ -4553,7 +4505,7 @@ let rec remove_clause_from_pattern ctx (P_aux (rm_pat,ann)) res_pat =
in aux [] res_pats res_pats'
in
let inconsistent () =
- raise (Reporting_basic.err_unreachable (fst ann) __POS__
+ raise (Reporting.err_unreachable (fst ann) __POS__
("Inconsistency during exhaustiveness analysis with " ^
string_of_rp res_pat))
in
@@ -4637,12 +4589,12 @@ let rec remove_clause_from_pattern ctx (P_aux (rm_pat,ann)) res_pat =
rp' @ List.map (function [rp1;rp2] -> RP_cons (rp1,rp2) | _ -> assert false) res_pats
end
| P_record _ ->
- raise (Reporting_basic.err_unreachable (fst ann) __POS__
+ raise (Reporting.err_unreachable (fst ann) __POS__
"Record pattern not supported")
| P_vector _
| P_vector_concat _
| P_string_append _ ->
- raise (Reporting_basic.err_unreachable (fst ann) __POS__
+ raise (Reporting.err_unreachable (fst ann) __POS__
"Found pattern that should have been rewritten away in earlier stage")
(*in let _ = printprefix := String.sub (!printprefix) 0 (String.length !printprefix - 2)
@@ -4658,7 +4610,7 @@ let process_pexp env =
| Pat_aux (Pat_exp (p,_),_) ->
List.concat (List.map (remove_clause_from_pattern ctx p) rps)
| Pat_aux (Pat_when _,(l,_)) ->
- raise (Reporting_basic.err_unreachable l __POS__
+ raise (Reporting.err_unreachable l __POS__
"Guarded pattern should have been rewritten away")
(* We do some minimal redundancy checking to remove bogus wildcard patterns here *)
@@ -4666,7 +4618,7 @@ let check_cases process is_wild loc_of cases =
let rec aux rps acc = function
| [] -> acc, rps
| [p] when is_wild p && match rps with [] -> true | _ -> false ->
- let () = Reporting_basic.print_err false false
+ let () = Reporting.print_err false false
(loc_of p) "Match checking" "Redundant wildcard clause" in
acc, []
| h::t -> aux (process rps h) (h::acc) t
@@ -4706,7 +4658,7 @@ let rewrite_case (e,ann) =
let _ =
if !opt_coq_warn_nonexhaustive
- then Reporting_basic.print_err false false
+ then Reporting.print_err false false
(fst ann) "Non-exhaustive matching" ("Example: " ^ string_of_rp example) in
let l = Parse_ast.Generated Parse_ast.Unknown in
@@ -4726,7 +4678,7 @@ let rewrite_case (e,ann) =
| (example::_) ->
let _ =
if !opt_coq_warn_nonexhaustive
- then Reporting_basic.print_err false false
+ then Reporting.print_err false false
(fst ann) "Non-exhaustive let" ("Example: " ^ string_of_rp example) in
let l = Parse_ast.Generated Parse_ast.Unknown in
let p = P_aux (P_wild, (l, empty_tannot)) in
@@ -4742,7 +4694,7 @@ let rewrite_fun rewriters (FD_aux (FD_function (r,t,e,fcls),f_ann)) =
let id,fcl_ann =
match fcls with
| FCL_aux (FCL_Funcl (id,_),ann) :: _ -> id,ann
- | [] -> raise (Reporting_basic.err_unreachable (fst f_ann) __POS__
+ | [] -> raise (Reporting.err_unreachable (fst f_ann) __POS__
"Empty function")
in
let env = env_of_annot fcl_ann in
@@ -4756,7 +4708,7 @@ let rewrite_fun rewriters (FD_aux (FD_function (r,t,e,fcls),f_ann)) =
| (example::_) ->
let _ =
if !opt_coq_warn_nonexhaustive
- then Reporting_basic.print_err false false
+ then Reporting.print_err false false
(fst f_ann) "Non-exhaustive matching" ("Example: " ^ string_of_rp example) in
let l = Parse_ast.Generated Parse_ast.Unknown in
@@ -4801,7 +4753,7 @@ let minimise_recursive_functions (Defs defs) =
let rewrite_function (FD_aux (FD_function (recopt,topt,effopt,funcls),ann) as fd) =
match recopt with
| Rec_aux (Rec_nonrec, _) -> fd
- | Rec_aux (Rec_rec, l) ->
+ | Rec_aux ((Rec_rec | Rec_measure _), l) ->
if List.exists funcl_is_rec funcls
then fd
else FD_aux (FD_function (Rec_aux (Rec_nonrec, Generated l),topt,effopt,funcls),ann)
@@ -4811,7 +4763,150 @@ let minimise_recursive_functions (Defs defs) =
| d -> d
in Defs (List.map rewrite_def defs)
+(* Make recursive functions with a measure use the measure as an
+ explicit recursion limit, enforced by an assertion. *)
+let rewrite_explicit_measure (Defs defs) =
+ let scan_function measures = function
+ | FD_aux (FD_function (Rec_aux (Rec_measure (mpat,mexp),rl),topt,effopt,
+ FCL_aux (FCL_Funcl (id,_),_)::_),ann) ->
+ Bindings.add id (mpat,mexp) measures
+ | _ -> measures
+ in
+ let scan_def measures = function
+ | DEF_fundef fd -> scan_function measures fd
+ | _ -> measures
+ in
+ let measures = List.fold_left scan_def Bindings.empty defs in
+ let add_escape eff =
+ union_effects eff (mk_effect [BE_escape])
+ in
+ (* NB: the Coq backend relies on recognising the #rec# prefix *)
+ let rec_id = function
+ | Id_aux (Id id,l)
+ | Id_aux (DeIid id,l) -> Id_aux (Id ("#rec#" ^ id),Generated l)
+ in
+ let limit = mk_id "#reclimit" in
+ (* Add helper function with extra argument to spec *)
+ let rewrite_spec (VS_aux (VS_val_spec (typsch,id,extern,flag),ann) as vs) =
+ match Bindings.find id measures with
+ | _ -> begin
+ match typsch with
+ | TypSchm_aux (TypSchm_ts (tq,
+ Typ_aux (Typ_fn (args,res,eff),typl)),tsl) ->
+ [VS_aux (VS_val_spec (
+ TypSchm_aux (TypSchm_ts (tq,
+ Typ_aux (Typ_fn (args@[int_typ],res,add_escape eff),typl)),tsl)
+ ,rec_id id,extern,flag),ann);
+ VS_aux (VS_val_spec (
+ TypSchm_aux (TypSchm_ts (tq,
+ Typ_aux (Typ_fn (args,res,add_escape eff),typl)),tsl)
+ ,id,extern,flag),ann)]
+ | _ -> [vs] (* TODO warn *)
+ end
+ | exception Not_found -> [vs]
+ in
+ (* Add extra argument and assertion to each funcl, and rewrite recursive calls *)
+ let rewrite_funcl (FCL_aux (FCL_Funcl (id,pexp),ann) as fcl) =
+ let loc = Parse_ast.Generated (fst ann) in
+ let P_aux (pat,pann),guard,body,ann = destruct_pexp pexp in
+ let extra_pat = P_aux (P_id limit,(loc,empty_tannot)) in
+ let pat = match pat with
+ | P_tup pats -> P_tup (pats@[extra_pat])
+ | p -> P_tup [P_aux (p,pann);extra_pat]
+ in
+ let assert_exp =
+ E_aux (E_assert
+ (E_aux (E_app (mk_id "gteq_int",
+ [E_aux (E_id limit,(loc,empty_tannot));
+ E_aux (E_lit (L_aux (L_num Big_int.zero,loc)),(loc,empty_tannot))]),
+ (loc,empty_tannot)),
+ (E_aux (E_lit (L_aux (L_string "recursion limit reached",loc)),(loc,empty_tannot)))),
+ (loc,empty_tannot))
+ in
+ let tick =
+ E_aux (E_app (mk_id "sub_int",
+ [E_aux (E_id limit,(loc,empty_tannot));
+ E_aux (E_lit (L_aux (L_num (Big_int.of_int 1),loc)),(loc,empty_tannot))]),
+ (loc,empty_tannot))
+ in
+ let open Rewriter in
+ let body =
+ fold_exp { id_exp_alg with
+ e_app = (fun (f,args) ->
+ if Id.compare f id == 0
+ then E_app (rec_id id, args@[tick])
+ else E_app (f, args))
+ } body
+ in
+ let body = E_aux (E_block [assert_exp; body],(loc,empty_tannot)) in
+ FCL_aux (FCL_Funcl (rec_id id, construct_pexp (P_aux (pat,pann),guard,body,ann)),ann)
+ in
+ let rewrite_function (FD_aux (FD_function (r,t,e,fcls),ann) as fd) =
+ let loc = Parse_ast.Generated (fst ann) in
+ match fcls with
+ | FCL_aux (FCL_Funcl (id,_),fcl_ann)::_ -> begin
+ match Bindings.find id measures with
+ | (measure_pat, measure_exp) ->
+ let e = match e with
+ | Effect_opt_aux (Effect_opt_pure, _) ->
+ Effect_opt_aux (Effect_opt_effect (mk_effect [BE_escape]), loc)
+ | Effect_opt_aux (Effect_opt_effect eff,_) ->
+ Effect_opt_aux (Effect_opt_effect (add_escape eff), loc)
+ in
+ let arg_typs = match Env.get_val_spec id (env_of_annot fcl_ann) with
+ | _, Typ_aux (Typ_fn (args,_,_),_) -> args
+ | _, _ -> raise (Reporting.err_unreachable (fst ann) __POS__
+ "Function doesn't have function type")
+ in
+ let measure_pats = match arg_typs, measure_pat with
+ | [_], _ -> [measure_pat]
+ | _, P_aux (P_tup ps,_) -> ps
+ | _, _ -> [measure_pat]
+ in
+ let mk_wrap i (P_aux (p,(l,_))) =
+ let id =
+ match p with
+ | P_id id
+ | P_typ (_,(P_aux (P_id id,_))) -> id
+ | P_wild
+ | P_typ (_,(P_aux (P_wild,_))) ->
+ mk_id ("_arg" ^ string_of_int i)
+ | _ -> raise (Reporting.err_todo l "Measure patterns can only be identifiers or wildcards")
+ in
+ P_aux (P_id id,(loc,empty_tannot)),
+ E_aux (E_id id,(loc,empty_tannot))
+ in
+ let wpats,wexps = List.split (Util.list_mapi mk_wrap measure_pats) in
+ let wpat = match wpats with
+ | [wpat] -> wpat
+ | _ -> P_aux (P_tup wpats,(loc,empty_tannot))
+ in
+ let wbody = E_aux (E_app (rec_id id,wexps@[measure_exp]),(loc,empty_tannot)) in
+ let wrapper =
+ FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (wpat,wbody),(loc,empty_tannot))),(loc,empty_tannot))
+ in
+ let new_rec =
+ Rec_aux (Rec_measure (P_aux (P_tup (List.map (fun _ -> P_aux (P_wild,(loc,empty_tannot))) measure_pats @ [P_aux (P_id limit,(loc,empty_tannot))]),(loc,empty_tannot)), E_aux (E_id limit, (loc,empty_tannot))), loc)
+ in
+ [FD_aux (FD_function (new_rec,t,e,List.map rewrite_funcl fcls),ann);
+ FD_aux (FD_function (Rec_aux (Rec_nonrec,loc),t,e,[wrapper]),ann)]
+ | exception Not_found -> [fd]
+ end
+ | _ -> [fd]
+ in
+ let rewrite_def = function
+ | DEF_spec vs -> List.map (fun vs -> DEF_spec vs) (rewrite_spec vs)
+ | DEF_fundef fd -> List.map (fun f -> DEF_fundef f) (rewrite_function fd)
+ | d -> [d]
+ in
+ Defs (List.flatten (List.map rewrite_def defs))
+
let recheck_defs defs = fst (Type_error.check initial_env defs)
+let recheck_defs_without_effects defs =
+ let () = opt_no_effects := true in
+ let result,_ = Type_error.check initial_env defs in
+ let () = opt_no_effects := false in
+ result
let remove_mapping_valspecs (Defs defs) =
let allowed_def def =
@@ -4872,6 +4967,7 @@ let rewrite_defs_lem = [
("recheck_defs", if_mono recheck_defs);
("rewrite_undefined", rewrite_undefined_if_gen false);
("rewrite_defs_vector_string_pats_to_bit_list", rewrite_defs_vector_string_pats_to_bit_list);
+ ("remove_not_pats", rewrite_defs_not_pats);
("pat_lits", rewrite_defs_pat_lits rewrite_lit_lem);
("vector_concat_assignments", rewrite_vector_concat_assignments);
("tuple_assignments", rewrite_tuple_assignments);
@@ -4914,6 +5010,7 @@ let rewrite_defs_coq = [
("mapping_builtins", rewrite_defs_mapping_patterns);
("rewrite_undefined", rewrite_undefined_if_gen true);
("rewrite_defs_vector_string_pats_to_bit_list", rewrite_defs_vector_string_pats_to_bit_list);
+ ("remove_not_pats", rewrite_defs_not_pats);
("pat_lits", rewrite_defs_pat_lits rewrite_lit_lem);
("vector_concat_assignments", rewrite_vector_concat_assignments);
("tuple_assignments", rewrite_tuple_assignments);
@@ -4937,8 +5034,9 @@ let rewrite_defs_coq = [
("sizeof", rewrite_sizeof);
("early_return", rewrite_defs_early_return);
("make_cases_exhaustive", MakeExhaustive.rewrite);
+ ("rewrite_explicit_measure", rewrite_explicit_measure);
+ ("recheck_defs_without_effects", recheck_defs_without_effects);
("fix_val_specs", rewrite_fix_val_specs);
- ("recheck_defs", recheck_defs);
("remove_blocks", rewrite_defs_remove_blocks);
("letbind_effects", rewrite_defs_letbind_effects);
("remove_e_assign", rewrite_defs_remove_e_assign);
@@ -4962,6 +5060,7 @@ let rewrite_defs_ocaml = [
("vector_concat_assignments", rewrite_vector_concat_assignments);
("tuple_assignments", rewrite_tuple_assignments);
("simple_assignments", rewrite_simple_assignments);
+ ("remove_not_pats", rewrite_defs_not_pats);
("remove_vector_concat", rewrite_defs_remove_vector_concat);
("remove_bitvector_pats", rewrite_defs_remove_bitvector_pats);
("remove_numeral_pats", rewrite_defs_remove_numeral_pats);
@@ -4983,6 +5082,7 @@ let rewrite_defs_c = [
("mapping_builtins", rewrite_defs_mapping_patterns);
("rewrite_undefined", rewrite_undefined_if_gen false);
("rewrite_defs_vector_string_pats_to_bit_list", rewrite_defs_vector_string_pats_to_bit_list);
+ ("remove_not_pats", rewrite_defs_not_pats);
("pat_lits", rewrite_defs_pat_lits (fun _ -> true));
("vector_concat_assignments", rewrite_vector_concat_assignments);
("tuple_assignments", rewrite_tuple_assignments);
@@ -5021,16 +5121,16 @@ let rewrite_check_annot =
let typ1 = typ_of exp in
let typ2 = Env.expand_synonyms (env_of exp) (typ_of exp) in
(if not (alpha_equivalent (env_of exp) typ1 typ2)
- then raise (Reporting_basic.err_typ Parse_ast.Unknown
+ then raise (Reporting.err_typ Parse_ast.Unknown
("Found synonym in annotation " ^ string_of_typ typ1 ^ " vs " ^ string_of_typ typ2))
else ());
exp
with
- Type_error (l, err) -> raise (Reporting_basic.err_typ l (Type_error.string_of_type_error err))
+ Type_error (l, err) -> raise (Reporting.err_typ l (Type_error.string_of_type_error err))
in
let check_pat pat =
- prerr_endline ("CHECKING PAT: " ^ string_of_pat pat ^ " : " ^ string_of_typ (pat_typ_of pat));
- let _, _ = bind_pat_no_guard (pat_env_of pat) (strip_pat pat) (pat_typ_of pat) in
+ prerr_endline ("CHECKING PAT: " ^ string_of_pat pat ^ " : " ^ string_of_typ (typ_of_pat pat));
+ let _, _ = bind_pat_no_guard (env_of_pat pat) (strip_pat pat) (typ_of_pat pat) in
pat
in
diff --git a/src/sail.ml b/src/sail.ml
index 5deaa340..9f2c7310 100644
--- a/src/sail.ml
+++ b/src/sail.ml
@@ -64,6 +64,7 @@ let opt_print_ocaml = ref false
let opt_print_c = ref false
let opt_print_latex = ref false
let opt_print_coq = ref false
+let opt_print_cgen = ref false
let opt_memo_z3 = ref false
let opt_sanity = ref false
let opt_includes_c = ref ([]:string list)
@@ -110,7 +111,7 @@ let options = Arg.align ([
Arg.String (fun s -> opt_ocaml_generators := s::!opt_ocaml_generators),
"<types> produce random generators for the given types");
( "-latex",
- Arg.Set opt_print_latex,
+ Arg.Tuple [Arg.Set opt_print_latex; Arg.Clear Type_check.opt_expand_valspec ],
" pretty print the input to latex");
( "-marshal",
Arg.Set opt_marshal_defs,
@@ -132,17 +133,24 @@ let options = Arg.align ([
Arg.Set C_backend.optimize_hoist_allocations;
Arg.Set Initial_check.opt_fast_undefined;
Arg.Set Type_check.opt_no_effects;
- Arg.Set C_backend.optimize_struct_updates ],
+ Arg.Set C_backend.optimize_struct_updates;
+ Arg.Set C_backend.optimize_alias],
" turn on optimizations for C compilation");
( "-Oconstant_fold",
Arg.Set Constant_fold.optimize_constant_fold,
" Apply constant folding optimizations");
+ ( "-Oexperimental",
+ Arg.Set C_backend.optimize_experimental,
+ " turn on additional, experimental optimisations");
( "-static",
Arg.Set C_backend.opt_static,
" Make generated C functions static");
( "-trace",
Arg.Tuple [Arg.Set C_backend.opt_trace; Arg.Set Ocaml_backend.opt_trace_ocaml],
" Instrument ouput with tracing");
+ ( "-cgen",
+ Arg.Set opt_print_cgen,
+ " Generate CGEN source");
( "-lem",
Arg.Set opt_print_lem,
" output a Lem translated version of the input");
@@ -171,7 +179,7 @@ let options = Arg.align ([
Arg.String (fun f -> Pretty_print_coq.opt_debug_on := f::!Pretty_print_coq.opt_debug_on),
"<function> produce debug messages for Coq output on given function");
( "-latex_prefix",
- Arg.String (fun prefix -> Latex.opt_prefix_latex := prefix),
+ Arg.String (fun prefix -> Latex.opt_prefix := prefix),
" set a custom prefix for generated latex command (default sail)");
( "-mono_split",
Arg.String (fun s ->
@@ -190,6 +198,9 @@ let options = Arg.align ([
( "-enum_casts",
Arg.Set Initial_check.opt_enum_casts,
" allow enumerations to be automatically casted to numeric range types");
+ ( "-non_lexical_flow",
+ Arg.Set Nl_flow.opt_nl_flow,
+ " allow non-lexical flow typing");
( "-no_lexp_bounds_check",
Arg.Set Type_check.opt_no_lexp_bounds_check,
" turn off bounds checking for vector assignments in l-expressions");
@@ -227,7 +238,7 @@ let options = Arg.align ([
Arg.String (fun l -> opt_ddump_rewrite_ast := Some (l, 0)),
"<prefix> (debug) dump the ast after each rewriting step to <prefix>_<i>.lem");
( "-ddump_flow_graphs",
- Arg.Set C_backend.opt_ddump_flow_graphs,
+ Arg.Set C_backend.opt_debug_flow_graphs,
" (debug) dump flow analysis for Sail functions when compiling to C");
( "-dtc_verbose",
Arg.Int (fun verbosity -> Type_check.opt_tc_debug := verbosity),
@@ -241,9 +252,12 @@ let options = Arg.align ([
( "-dmagic_hash",
Arg.Set Initial_check.opt_magic_hash,
" (debug) allow special character # in identifiers");
- ( "-Xconstraint_synonyms",
- Arg.Set Type_check.opt_constraint_synonyms,
- " (extension) allow constraint synonyms");
+ ( "-dfunction",
+ Arg.String (fun f -> C_backend.opt_debug_function := f),
+ " (debug) print debugging output for a single function");
+ ( "-dprofile",
+ Arg.Set Profile.opt_profile,
+ " (debug) provides basic profiling information for rewriting passes within Sail");
( "-v",
Arg.Set opt_print_version,
" print version");
@@ -266,15 +280,20 @@ let interactive_env = ref Type_check.initial_env
let load_files type_envs files =
if !opt_memo_z3 then Constraint.load_digests () else ();
+ let t = Profile.start () in
let parsed = List.map (fun f -> (f, parse_file f)) files in
let ast =
List.fold_right (fun (_, Parse_ast.Defs ast_nodes) (Parse_ast.Defs later_nodes)
-> Parse_ast.Defs (ast_nodes@later_nodes)) parsed (Parse_ast.Defs []) in
let ast = Process_file.preprocess_ast options ast in
let ast = convert_ast Ast_util.inc_ord ast in
+ Profile.finish "parsing" t;
+ let t = Profile.start () in
let (ast, type_envs) = check_ast type_envs ast in
+ Profile.finish "type checking" t;
+ let ast = Scattered.descatter ast in
let ast = rewrite_ast type_envs ast in
let out_name = match !opt_file_out with
@@ -344,6 +363,9 @@ let main() =
Util.opt_warnings := true;
C_backend.compile_ast (C_backend.initial_ctx type_envs) (!opt_includes_c) ast_c
else ());
+ (if !(opt_print_cgen)
+ then Cgen_backend.output type_envs ast
+ else ());
(if !(opt_print_lem)
then
let mwords = !Pretty_print_lem.opt_mwords in
@@ -360,15 +382,19 @@ let main() =
(if !(opt_print_latex)
then
begin
+ Util.opt_warnings := true;
let latex_dir = match !opt_file_out with None -> "sail_latex" | Some s -> s in
- try
- if not (Sys.is_directory latex_dir) then begin
- prerr_endline ("Failure: latex output directory exists but is not a directory: " ^ latex_dir);
- exit 1
- end
- with Sys_error(_) -> Unix.mkdir latex_dir 0o755;
+ begin
+ try
+ if not (Sys.is_directory latex_dir) then begin
+ prerr_endline ("Failure: latex output directory exists but is not a directory: " ^ latex_dir);
+ exit 1
+ end
+ with Sys_error(_) -> Unix.mkdir latex_dir 0o755
+ end;
+ Latex.opt_directory := latex_dir;
let chan = open_out (Filename.concat latex_dir "commands.tex") in
- output_string chan (Pretty_print_sail.to_string (Latex.latex_defs latex_dir ast));
+ output_string chan (Pretty_print_sail.to_string (Latex.defs ast));
close_out chan
end
else ());
@@ -389,6 +415,6 @@ let main() =
let _ = try
begin
try ignore(main ())
- with Failure(s) -> raise (Reporting_basic.err_general Parse_ast.Unknown ("Failure "^s))
+ with Failure(s) -> raise (Reporting.err_general Parse_ast.Unknown ("Failure "^s))
end
- with Reporting_basic.Fatal_error e -> Reporting_basic.report_error e
+ with Reporting.Fatal_error e -> Reporting.report_error e
diff --git a/src/sail_lib.ml b/src/sail_lib.ml
index a718e6d5..c0bf80fa 100644
--- a/src/sail_lib.ml
+++ b/src/sail_lib.ml
@@ -160,6 +160,8 @@ let update_subrange (xs, n, m, ys) =
let vector_truncate (xs, n) = List.rev (take (Big_int.to_int n) (List.rev xs))
+let vector_truncateLSB (xs, n) = take (Big_int.to_int n) xs
+
let length xs = Big_int.of_int (List.length xs)
let big_int_of_bit = function
@@ -359,6 +361,14 @@ let int_of_bit = function
| B0 -> 0
| B1 -> 1
+let bool_of_bit = function
+ | B0 -> false
+ | B1 -> true
+
+let bit_of_bool = function
+ | false -> B0
+ | true -> B1
+
let bigint_of_bit b = Big_int.of_int (int_of_bit b)
let string_of_hex = function
@@ -578,20 +588,49 @@ let gteq_real (x, y) = Rational.geq x y
let to_real x = Rational.of_int (Big_int.to_int x) (* FIXME *)
let negate_real x = Rational.neg x
-let print_real (str, r) = print_string "REAL\n"
-let prerr_real (str, r) = prerr_string "REAL\n"
+let string_of_real x =
+ if Big_int.equal (Rational.den x) (Big_int.of_int 1) then
+ Big_int.to_string (Rational.num x)
+ else
+ Big_int.to_string (Rational.num x) ^ "/" ^ Big_int.to_string (Rational.den x)
+
+let print_real (str, r) = print_endline (str ^ string_of_real r)
+let prerr_real (str, r) = prerr_endline (str ^ string_of_real r)
-let round_down x = Rational.floor x (* Num.big_int_of_num (Num.floor_num x) *)
-let round_up x = Rational.ceiling x (* Num.big_int_of_num (Num.ceiling_num x) *)
+let round_down x = Rational.floor x
+let round_up x = Rational.ceiling x
let quotient_real (x, y) = Rational.div x y
-let mult_real (x, y) = Rational.mul x y (* Num.mult_num x y *)
-let real_power (x, y) = failwith "real_power" (* Num.power_num x (Num.num_of_big_int y) *)
+let div_real (x, y) = Rational.div x y
+let mult_real (x, y) = Rational.mul x y
+let real_power (x, y) = failwith "real_power"
let int_power (x, y) = Big_int.pow_int x (Big_int.to_int y)
let add_real (x, y) = Rational.add x y
let sub_real (x, y) = Rational.sub x y
let abs_real x = Rational.abs x
+let sqrt_real x =
+ let precision = 30 in
+ let s = Big_int.sqrt (Rational.num x) in
+ if Big_int.equal (Rational.den x) (Big_int.of_int 1) && Big_int.equal (Big_int.mul s s) (Rational.num x) then
+ to_real s
+ else
+ let p = ref (to_real (Big_int.sqrt (Big_int.div (Rational.num x) (Rational.den x)))) in
+ let n = ref (Rational.of_int 0) in
+ let convergence = ref (Rational.div (Rational.of_int 1) (Rational.of_big_int (Big_int.pow_int_positive 10 precision))) in
+ let quit_loop = ref false in
+ while not !quit_loop do
+ n := Rational.div (Rational.add !p (Rational.div x !p)) (Rational.of_int 2);
+
+ if Rational.lt (Rational.abs (Rational.sub !p !n)) !convergence then
+ quit_loop := true
+ else
+ p := !n
+ done;
+ !n
+
+let random_real () = Rational.div (Rational.of_int (Random.bits ())) (Rational.of_int (Random.bits()))
+
let lt (x, y) = Big_int.less x y
let gt (x, y) = Big_int.greater x y
let lteq (x, y) = Big_int.less_equal x y
@@ -620,9 +659,6 @@ let real_of_string str =
| [whole] -> Rational.of_int (int_of_string str)
| _ -> failwith "invalid real literal"
-(* Not a very good sqrt implementation *)
-let sqrt_real x = failwith "sqrt_real" (* real_of_string (string_of_float (sqrt (Num.float_of_num x))) *)
-
let print str = Pervasives.print_string str
let prerr str = Pervasives.prerr_string str
@@ -1112,7 +1148,7 @@ let rand_zvector (g : 'generators) (size : int) (order : bool) (elem_gen : 'gene
Util.list_init size (fun _ -> elem_gen g)
let rand_zbit (g : 'generators) : bit =
- if Random.bool() then B0 else B1
+ bit_of_bool (Random.bool())
let rand_zbool (g : 'generators) : bool =
Random.bool()
diff --git a/src/scattered.ml b/src/scattered.ml
new file mode 100644
index 00000000..be304dc8
--- /dev/null
+++ b/src/scattered.ml
@@ -0,0 +1,141 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast
+open Ast_util
+
+let funcl_id (FCL_aux (FCL_Funcl (id, _), _)) = id
+
+let rec last_scattered_funcl id = function
+ | DEF_scattered (SD_aux (SD_funcl funcl, _)) :: _
+ when Id.compare (funcl_id funcl) id = 0 -> false
+ | _ :: defs -> last_scattered_funcl id defs
+ | [] -> true
+
+let rec last_scattered_mapcl id = function
+ | DEF_scattered (SD_aux (SD_mapcl (mid, _), _)) :: _
+ when Id.compare mid id = 0 -> false
+ | _ :: defs -> last_scattered_mapcl id defs
+ | [] -> true
+
+(* Nothing cares about these and the AST should be changed *)
+let fake_effect_opt l = Effect_opt_aux (Effect_opt_pure, gen_loc l)
+let fake_rec_opt l = Rec_aux (Rec_rec, gen_loc l)
+
+let no_tannot_opt l = Typ_annot_opt_aux (Typ_annot_opt_none, gen_loc l)
+
+let rec get_union_clauses id = function
+ | DEF_scattered (SD_aux (SD_unioncl (uid, tu), _)) :: defs when Id.compare id uid = 0 ->
+ tu :: get_union_clauses id defs
+ | def :: defs ->
+ get_union_clauses id defs
+ | [] -> []
+
+let rec filter_union_clauses id = function
+ | DEF_scattered (SD_aux (SD_unioncl (uid, tu), _)) :: defs when Id.compare id uid = 0 ->
+ filter_union_clauses id defs
+ | def :: defs ->
+ def :: filter_union_clauses id defs
+ | [] -> []
+
+let rec descatter' funcls mapcls = function
+ (* For scattered functions we collect all the seperate function
+ clauses until we find the last one, then we turn that function
+ clause into a DEF_fundef containing all the clauses. *)
+ | DEF_scattered (SD_aux (SD_funcl funcl, (l, _))) :: defs
+ when last_scattered_funcl (funcl_id funcl) defs ->
+ let clauses = match Bindings.find_opt (funcl_id funcl) funcls with
+ | Some clauses -> List.rev (funcl :: clauses)
+ | None -> [funcl]
+ in
+ DEF_fundef (FD_aux (FD_function (fake_rec_opt l, no_tannot_opt l, fake_effect_opt l, clauses),
+ (gen_loc l, Type_check.empty_tannot)))
+ :: descatter' funcls mapcls defs
+
+ | DEF_scattered (SD_aux (SD_funcl funcl, _)) :: defs ->
+ let id = funcl_id funcl in
+ begin match Bindings.find_opt id funcls with
+ | Some clauses -> descatter' (Bindings.add id (funcl :: clauses) funcls) mapcls defs
+ | None -> descatter' (Bindings.add id [funcl] funcls) mapcls defs
+ end
+
+ (* Scattered mappings are handled the same way as scattered functions *)
+ | DEF_scattered (SD_aux (SD_mapcl (id, mapcl), (l, tannot))) :: defs
+ when last_scattered_mapcl id defs ->
+ let clauses = match Bindings.find_opt id mapcls with
+ | Some clauses -> List.rev (mapcl :: clauses)
+ | None -> [mapcl]
+ in
+ DEF_mapdef (MD_aux (MD_mapping (id, no_tannot_opt l, clauses),
+ (gen_loc l, tannot)))
+ :: descatter' funcls mapcls defs
+
+ | DEF_scattered (SD_aux (SD_mapcl (id, mapcl), _)) :: defs ->
+ begin match Bindings.find_opt id mapcls with
+ | Some clauses -> descatter' funcls (Bindings.add id (mapcl :: clauses) mapcls) defs
+ | None -> descatter' funcls (Bindings.add id [mapcl] mapcls) defs
+ end
+
+ (* For scattered unions, when we find a union declaration we
+ immediately grab all the future clauses and turn it into a
+ regular union declaration. *)
+ | DEF_scattered (SD_aux (SD_variant (id, namescm, typq), (l, _))) :: defs ->
+ let tus = get_union_clauses id defs in
+ DEF_type (TD_aux (TD_variant (id, namescm, typq, tus, false), (gen_loc l, Type_check.empty_tannot)))
+ :: descatter' funcls mapcls (filter_union_clauses id defs)
+
+ (* Therefore we should never see SD_unioncl... *)
+ | DEF_scattered (SD_aux (SD_unioncl _, (l, _))) :: defs ->
+ raise (Reporting.err_unreachable l __POS__ "Found union clause during de-scattering")
+
+ | def :: defs -> def :: descatter' funcls mapcls defs
+ | [] -> []
+
+let descatter (Defs defs) = Defs (descatter' Bindings.empty Bindings.empty defs)
diff --git a/src/spec_analysis.ml b/src/spec_analysis.ml
index 56c488ff..940fbfe5 100644
--- a/src/spec_analysis.ml
+++ b/src/spec_analysis.ml
@@ -94,14 +94,14 @@ let rec free_type_names_t consider_var (Typ_aux (t, l)) = match t with
(free_type_names_t consider_var t2)
| Typ_tup ts -> free_type_names_ts consider_var ts
| Typ_app (name,targs) -> Nameset.add (string_of_id name) (free_type_names_t_args consider_var targs)
- | Typ_exist (kids,_,t') -> List.fold_left (fun s kid -> Nameset.remove (string_of_kid kid) s) (free_type_names_t consider_var t') kids
+ | Typ_exist (kopts,_,t') -> List.fold_left (fun s kopt -> Nameset.remove (string_of_kid (kopt_kid kopt)) s) (free_type_names_t consider_var t') kopts
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
and free_type_names_ts consider_var ts = nameset_bigunion (List.map (free_type_names_t consider_var) ts)
and free_type_names_maybe_t consider_var = function
| Some t -> free_type_names_t consider_var t
| None -> mt
and free_type_names_t_arg consider_var = function
- | Typ_arg_aux (Typ_arg_typ t, _) -> free_type_names_t consider_var t
+ | A_aux (A_typ t, _) -> free_type_names_t consider_var t
| _ -> mt
and free_type_names_t_args consider_var targs =
nameset_bigunion (List.map (free_type_names_t_arg consider_var) targs)
@@ -126,12 +126,15 @@ let rec fv_of_typ consider_var bound used (Typ_aux (t,l)) : Nameset.t =
| Typ_tup ts -> List.fold_right (fun t n -> fv_of_typ consider_var bound n t) ts used
| Typ_app(id,targs) ->
List.fold_right (fun ta n -> fv_of_targ consider_var bound n ta) targs (conditional_add_typ bound used id)
- | Typ_exist (kids,_,t') -> fv_of_typ consider_var (List.fold_left (fun b (Kid_aux (Var v,_)) -> Nameset.add v b) bound kids) used t'
+ | Typ_exist (kopts,_,t') ->
+ fv_of_typ consider_var
+ (List.fold_left (fun b (KOpt_aux (KOpt_kind (_, (Kid_aux (Var v,_))), _)) -> Nameset.add v b) bound kopts)
+ used t'
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and fv_of_targ consider_var bound used (Ast.Typ_arg_aux(targ,_)) : Nameset.t = match targ with
- | Typ_arg_typ t -> fv_of_typ consider_var bound used t
- | Typ_arg_nexp n -> fv_of_nexp consider_var bound used n
+and fv_of_targ consider_var bound used (Ast.A_aux(targ,_)) : Nameset.t = match targ with
+ | A_typ t -> fv_of_typ consider_var bound used t
+ | A_nexp n -> fv_of_nexp consider_var bound used n
| _ -> used
and fv_of_nexp consider_var bound used (Ast.Nexp_aux(n,_)) = match n with
@@ -151,7 +154,6 @@ let typq_bindings (TypQ_aux(tq,_)) = match tq with
match qi with
| QI_id (KOpt_aux(k,_)) ->
(match k with
- | KOpt_none (Kid_aux (Var s,_)) -> Nameset.add s bounds
| KOpt_kind (_, Kid_aux (Var s,_)) -> Nameset.add s bounds)
| _ -> bounds) quants mt
| TypQ_no_forall -> mt
@@ -210,11 +212,11 @@ let rec fv_of_exp consider_var bound used set (E_aux (e,(_,tannot))) : (Nameset.
| E_vector_update(v,i,e) -> list_fv bound used set [v;i;e]
| E_vector_update_subrange(v,i1,i2,e) -> list_fv bound used set [v;i1;i2;e]
| E_vector_append(e1,e2) | E_cons(e1,e2) -> list_fv bound used set [e1;e2]
- | E_record (FES_aux(FES_Fexps(fexps,_),_)) ->
+ | E_record fexps ->
let used = Nameset.union (free_type_names_tannot consider_var tannot) used in
List.fold_right
(fun (FE_aux(FE_Fexp(_,e),_)) (b,u,s) -> fv_of_exp consider_var b u s e) fexps (bound,used,set)
- | E_record_update(e,(FES_aux(FES_Fexps(fexps,_),_))) ->
+ | E_record_update(e, fexps) ->
let b,u,s = fv_of_exp consider_var bound used set e in
List.fold_right
(fun (FE_aux(FE_Fexp(_,e),_)) (b,u,s) -> fv_of_exp consider_var b u s e) fexps (b,u,s)
@@ -282,6 +284,10 @@ and fv_of_lexp consider_var bound used set (LEXP_aux(lexp,(_,tannot))) =
(fun e (b,u,s) ->
fv_of_exp consider_var b u s e) args (bound,used,set) in
bound,Nameset.add (string_of_id id) used,set
+ | LEXP_vector_concat(args) ->
+ List.fold_right
+ (fun e (b,u,s) ->
+ fv_of_lexp consider_var b u s e) args (bound,used,set)
| LEXP_field(lexp,_) -> fv_of_lexp consider_var bound used set lexp
| LEXP_vector(lexp,exp) ->
let bound_l,used,set = fv_of_lexp consider_var bound used set lexp in
@@ -304,8 +310,13 @@ let typ_variants consider_var bound tunions =
let fv_of_kind_def consider_var (KD_aux(k,_)) = match k with
| KD_nabbrev(_,id,_,nexp) -> init_env (string_of_id id), fv_of_nexp consider_var mt mt nexp
+let fv_of_abbrev consider_var bound used typq typ_arg =
+ let ts_bound = if consider_var then typq_bindings typq else mt in
+ ts_bound, fv_of_targ consider_var (Nameset.union bound ts_bound) used typ_arg
+
let fv_of_type_def consider_var (TD_aux(t,_)) = match t with
- | TD_abbrev(id,_,typschm) -> init_env (string_of_id id), snd (fv_of_typschm consider_var mt mt typschm)
+ | TD_abbrev(id,typq,typ_arg) ->
+ init_env (string_of_id id), snd (fv_of_abbrev consider_var mt mt typq typ_arg)
| TD_record(id,_,typq,tids,_) ->
let binds = init_env (string_of_id id) in
let bounds = if consider_var then typq_bindings typq else mt in
@@ -382,17 +393,17 @@ let rec find_scattered_of name = function
| [] -> []
| DEF_scattered (SD_aux(sda,_) as sd):: defs ->
(match sda with
- | SD_scattered_function(_,_,_,id)
- | SD_scattered_funcl(FCL_aux(FCL_Funcl(id,_),_))
- | SD_scattered_unioncl(id,_) ->
+ | SD_function(_,_,_,id)
+ | SD_funcl(FCL_aux(FCL_Funcl(id,_),_))
+ | SD_unioncl(id,_) ->
if name = string_of_id id
then [sd] else []
| _ -> [])@
(find_scattered_of name defs)
| _::defs -> find_scattered_of name defs
-let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd,_)) = match sd with
- | SD_scattered_function(_,tannot_opt,_,id) ->
+let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd,(l, _))) = match sd with
+ | SD_function(_,tannot_opt,_,id) ->
let b,ns = (match tannot_opt with
| Typ_annot_opt_aux(Typ_annot_opt_some (typq, typ),_) ->
let bindings = if consider_var then typq_bindings typq else mt in
@@ -400,7 +411,7 @@ let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd
| Typ_annot_opt_aux(Typ_annot_opt_none, _) ->
mt, mt) in
init_env (string_of_id id),ns
- | SD_scattered_funcl (FCL_aux(FCL_Funcl(id,pexp),_)) ->
+ | SD_funcl (FCL_aux(FCL_Funcl(id,pexp),_)) ->
begin
match pexp with
| Pat_aux(Pat_exp (pat,exp),_) ->
@@ -419,7 +430,7 @@ let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd
| _ -> mt in
scattered_binds, exp_ns
end
- | SD_scattered_variant (id,_,_) ->
+ | SD_variant (id,_,_) ->
let name = string_of_id id in
let uses =
if consider_scatter_as_one
@@ -431,12 +442,12 @@ let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd
Nameset.remove name pieces_uses
else mt in
init_env name, uses
- | SD_scattered_unioncl(id, type_union) ->
+ | SD_unioncl(id, type_union) ->
let typ_name = string_of_id id in
let b = init_env typ_name in
let (b,r) = typ_variants consider_var b [type_union] in
(Nameset.remove typ_name b, Nameset.add typ_name r)
- | SD_scattered_end id ->
+ | SD_end id ->
let name = string_of_id id in
let uses = if consider_scatter_as_one
(*Note: if this is a function ending, the dec is included *)
@@ -446,16 +457,28 @@ let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd
(List.map (fv_of_scattered consider_var false []) scattered_defs) (init_env name)
else init_env name in
init_env (name ^ "/end"), uses
-
-let fv_of_rd consider_var (DEC_aux (d,_)) = match d with
- | DEC_reg(t,id) ->
- init_env (string_of_id id), fv_of_typ consider_var mt mt t
- | DEC_config(id,t,exp) ->
- init_env (string_of_id id), fv_of_typ consider_var mt mt t
- | DEC_alias(id,alias) ->
- init_env (string_of_id id),mt
- | DEC_typ_alias(t,id,alias) ->
- init_env (string_of_id id), mt
+ | _ -> raise (Reporting.err_unreachable l __POS__ "Tried to find free variables for scattered mapping clause")
+
+let fv_of_rd consider_var (DEC_aux (d, annot)) =
+ (* When we get the free variables of a register, we have to ensure
+ that we expand all synonyms so we can pick up dependencies with
+ undefined_type function, even when type is indirected through a
+ synonym. *)
+ let open Type_check in
+ let env = env_of_annot annot in
+ match d with
+ | DEC_reg(t, id) ->
+ let t' = Env.expand_synonyms env t in
+ init_env (string_of_id id),
+ Nameset.union (fv_of_typ consider_var mt mt t) (fv_of_typ consider_var mt mt t')
+ | DEC_config(id, t, exp) ->
+ let t' = Env.expand_synonyms env t in
+ init_env (string_of_id id),
+ Nameset.union (fv_of_typ consider_var mt mt t) (fv_of_typ consider_var mt mt t')
+ | DEC_alias(id, alias) ->
+ init_env (string_of_id id), mt
+ | DEC_typ_alias(t, id, alias) ->
+ init_env (string_of_id id), mt
let fv_of_def consider_var consider_scatter_as_one all_defs = function
| DEF_kind kdef -> fv_of_kind_def consider_var kdef
@@ -475,6 +498,7 @@ let fv_of_def consider_var consider_scatter_as_one all_defs = function
List.fold_left Nameset.union Nameset.empty (List.map snd fvs)
| DEF_scattered sdef -> fv_of_scattered consider_var consider_scatter_as_one all_defs sdef
| DEF_reg_dec rdec -> fv_of_rd consider_var rdec
+ | DEF_pragma _ -> mt,mt
let group_defs consider_scatter_as_one (Ast.Defs defs) =
List.map (fun d -> (fv_of_def false consider_scatter_as_one defs d,d)) defs
@@ -549,6 +573,15 @@ let scc ?(original_order : string list option) (g : graph) =
let add_def_to_graph (prelude, original_order, defset, graph) d =
let bound, used = fv_of_def false true [] d in
+ let used = match d with
+ | DEF_reg_dec _ ->
+ (* For a register, we need to ensure that any undefined_type
+ functions for types used by the register are placed before
+ the register declaration. *)
+ let undefineds = Nameset.map (fun name -> "undefined_" ^ name) used in
+ Nameset.union undefineds used
+ | _ -> used
+ in
try
(* A definition may bind multiple identifiers, e.g. "let (x, y) = ...".
We add all identifiers to the dependency graph as a cycle. The actual
@@ -598,7 +631,7 @@ let def_of_component graph defset comp =
| DEF_fundef fundef -> [fundef]
| DEF_internal_mutrec fundefs -> fundefs
| _ ->
- raise (Reporting_basic.err_unreachable (def_loc def) __POS__
+ raise (Reporting.err_unreachable (def_loc def) __POS__
"Trying to merge non-function definition with mutually recursive functions") in
let fundefs = List.concat (List.map get_fundefs defs) in
print_dot graph (List.map (fun fd -> string_of_id (id_of_fundef fd)) fundefs);
diff --git a/src/specialize.ml b/src/specialize.ml
index 4d7a997f..1ba57bd0 100644
--- a/src/specialize.ml
+++ b/src/specialize.ml
@@ -54,8 +54,8 @@ open Rewriter
open Extra_pervasives
let is_typ_ord_uvar = function
- | Type_check.U_typ _ -> true
- | Type_check.U_order _ -> true
+ | A_aux (A_typ _, _) -> true
+ | A_aux (A_order _, _) -> true
| _ -> false
let rec nexp_simp_typ (Typ_aux (typ_aux, l)) =
@@ -71,24 +71,20 @@ let rec nexp_simp_typ (Typ_aux (typ_aux, l)) =
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
in
Typ_aux (typ_aux, l)
-and nexp_simp_typ_arg (Typ_arg_aux (typ_arg_aux, l)) =
+and nexp_simp_typ_arg (A_aux (typ_arg_aux, l)) =
let typ_arg_aux = match typ_arg_aux with
- | Typ_arg_nexp n -> Typ_arg_nexp (nexp_simp n)
- | Typ_arg_typ typ -> Typ_arg_typ (nexp_simp_typ typ)
- | Typ_arg_order ord -> Typ_arg_order ord
+ | A_nexp n -> A_nexp (nexp_simp n)
+ | A_typ typ -> A_typ (nexp_simp_typ typ)
+ | A_order ord -> A_order ord
+ | A_bool nc -> A_bool (constraint_simp nc)
in
- Typ_arg_aux (typ_arg_aux, l)
-
-let nexp_simp_uvar = function
- | Type_check.U_nexp nexp -> (prerr_endline ("Simp nexp " ^ string_of_nexp nexp); Type_check.U_nexp (nexp_simp nexp))
- | Type_check.U_typ typ -> Type_check.U_typ (nexp_simp_typ typ)
- | uvar -> uvar
+ A_aux (typ_arg_aux, l)
(* We have to be careful about whether the typechecker has renamed anything returned by instantiation_of.
This part of the typechecker API is a bit ugly. *)
let fix_instantiation instantiation =
- let instantiation = KBindings.bindings (KBindings.filter (fun _ uvar -> is_typ_ord_uvar uvar) instantiation) in
- let instantiation = List.map (fun (kid, uvar) -> Type_check.orig_kid kid, nexp_simp_uvar uvar) instantiation in
+ let instantiation = KBindings.bindings (KBindings.filter (fun _ arg -> is_typ_ord_uvar arg) instantiation) in
+ let instantiation = List.map (fun (kid, arg) -> Type_check.orig_kid kid, nexp_simp_typ_arg arg) instantiation in
List.fold_left (fun m (k, v) -> KBindings.add k v m) KBindings.empty instantiation
let rec polymorphic_functions is_kopt (Defs defs) =
@@ -104,13 +100,13 @@ let rec polymorphic_functions is_kopt (Defs defs) =
let string_of_instantiation instantiation =
let open Type_check in
- let kid_names = ref KBindings.empty in
+ let kid_names = ref KOptMap.empty in
let kid_counter = ref 0 in
let kid_name kid =
- try KBindings.find kid !kid_names with
+ try KOptMap.find kid !kid_names with
| Not_found -> begin
let n = string_of_int !kid_counter in
- kid_names := KBindings.add kid n !kid_names;
+ kid_names := KOptMap.add kid n !kid_names;
incr kid_counter;
n
end
@@ -121,7 +117,7 @@ let string_of_instantiation instantiation =
| Nexp_aux (nexp, _) -> string_of_nexp_aux nexp
and string_of_nexp_aux = function
| Nexp_id id -> string_of_id id
- | Nexp_var kid -> kid_name kid
+ | Nexp_var kid -> kid_name (mk_kopt K_int kid)
| Nexp_constant c -> Big_int.to_string c
| Nexp_times (n1, n2) -> "(" ^ string_of_nexp n1 ^ " * " ^ string_of_nexp n2 ^ ")"
| Nexp_sum (n1, n2) -> "(" ^ string_of_nexp n1 ^ " + " ^ string_of_nexp n2 ^ ")"
@@ -135,7 +131,7 @@ let string_of_instantiation instantiation =
| Typ_aux (typ, l) -> string_of_typ_aux typ
and string_of_typ_aux = function
| Typ_id id -> string_of_id id
- | Typ_var kid -> kid_name kid
+ | Typ_var kid -> kid_name (mk_kopt K_type kid)
| Typ_tup typs -> "(" ^ Util.string_of_list ", " string_of_typ typs ^ ")"
| Typ_app (id, args) -> string_of_id id ^ "(" ^ Util.string_of_list ", " string_of_typ_arg args ^ ")"
| Typ_fn (arg_typs, ret_typ, eff) ->
@@ -146,11 +142,12 @@ let string_of_instantiation instantiation =
"exist " ^ Util.string_of_list " " kid_name kids ^ ", " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ
| Typ_internal_unknown -> "UNKNOWN"
and string_of_typ_arg = function
- | Typ_arg_aux (typ_arg, l) -> string_of_typ_arg_aux typ_arg
+ | A_aux (typ_arg, l) -> string_of_typ_arg_aux typ_arg
and string_of_typ_arg_aux = function
- | Typ_arg_nexp n -> string_of_nexp n
- | Typ_arg_typ typ -> string_of_typ typ
- | Typ_arg_order o -> string_of_order o
+ | A_nexp n -> string_of_nexp n
+ | A_typ typ -> string_of_typ typ
+ | A_order o -> string_of_order o
+ | A_bool nc -> string_of_n_constraint nc
and string_of_n_constraint = function
| NC_aux (NC_equal (n1, n2), _) -> string_of_nexp n1 ^ " = " ^ string_of_nexp n2
| NC_aux (NC_not_equal (n1, n2), _) -> string_of_nexp n1 ^ " != " ^ string_of_nexp n2
@@ -161,18 +158,12 @@ let string_of_instantiation instantiation =
| NC_aux (NC_and (nc1, nc2), _) ->
"(" ^ string_of_n_constraint nc1 ^ " & " ^ string_of_n_constraint nc2 ^ ")"
| NC_aux (NC_set (kid, ns), _) ->
- kid_name kid ^ " in {" ^ Util.string_of_list ", " Big_int.to_string ns ^ "}"
+ kid_name (mk_kopt K_int kid) ^ " in {" ^ Util.string_of_list ", " Big_int.to_string ns ^ "}"
| NC_aux (NC_true, _) -> "true"
| NC_aux (NC_false, _) -> "false"
in
- let string_of_uvar = function
- | U_nexp n -> string_of_nexp n
- | U_order o -> string_of_order o
- | U_typ typ -> string_of_typ typ
- in
-
- let string_of_binding (kid, uvar) = string_of_kid kid ^ " => " ^ string_of_uvar uvar in
+ let string_of_binding (kid, arg) = string_of_kid kid ^ " => " ^ string_of_typ_arg arg in
Util.zencode_string (Util.string_of_list ", " string_of_binding (KBindings.bindings instantiation))
let id_of_instantiation id instantiation =
@@ -182,7 +173,7 @@ let id_of_instantiation id instantiation =
let rec variant_generic_typ id (Defs defs) =
match defs with
| DEF_type (TD_aux (TD_variant (id', _, typq, _, _), _)) :: _ when Id.compare id id' = 0 ->
- mk_typ (Typ_app (id', List.map (fun kopt -> mk_typ_arg (Typ_arg_typ (mk_typ (Typ_var (kopt_kid kopt))))) (quant_kopts typq)))
+ mk_typ (Typ_app (id', List.map (fun kopt -> mk_typ_arg (A_typ (mk_typ (Typ_var (kopt_kid kopt))))) (quant_kopts typq)))
| _ :: defs -> variant_generic_typ id (Defs defs)
| [] -> failwith ("No variant with id " ^ string_of_id id)
@@ -207,9 +198,10 @@ let rec instantiations_of id ast =
begin match Type_check.typ_of_annot annot with
| Typ_aux (Typ_app (variant_id, _), _) as typ ->
let open Type_check in
- let instantiation, _, _ = unify (fst annot) (env_of_annot annot)
- (variant_generic_typ variant_id ast)
- typ
+ let instantiation = unify (fst annot) (env_of_annot annot)
+ (tyvars_of_typ (variant_generic_typ variant_id ast))
+ (variant_generic_typ variant_id ast)
+ typ
in
instantiations := fix_instantiation instantiation :: !instantiations;
pat
@@ -257,16 +249,16 @@ let rec typ_frees ?exs:(exs=KidSet.empty) (Typ_aux (typ_aux, l)) =
| Typ_var kid -> KidSet.singleton kid
| Typ_tup typs -> List.fold_left KidSet.union KidSet.empty (List.map (typ_frees ~exs:exs) typs)
| Typ_app (f, args) -> List.fold_left KidSet.union KidSet.empty (List.map (typ_arg_frees ~exs:exs) args)
- | Typ_exist (kids, nc, typ) -> typ_frees ~exs:(KidSet.of_list kids) typ
+ | Typ_exist (kopts, nc, typ) -> typ_frees ~exs:(KidSet.of_list (List.map kopt_kid kopts)) typ
| Typ_fn (arg_typs, ret_typ, _) ->
List.fold_left KidSet.union (typ_frees ~exs:exs ret_typ) (List.map (typ_frees ~exs:exs) arg_typs)
| Typ_bidir (t1, t2) -> KidSet.union (typ_frees ~exs:exs t1) (typ_frees ~exs:exs t2)
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and typ_arg_frees ?exs:(exs=KidSet.empty) (Typ_arg_aux (typ_arg_aux, l)) =
+and typ_arg_frees ?exs:(exs=KidSet.empty) (A_aux (typ_arg_aux, l)) =
match typ_arg_aux with
- | Typ_arg_nexp n -> KidSet.empty
- | Typ_arg_typ typ -> typ_frees ~exs:exs typ
- | Typ_arg_order ord -> KidSet.empty
+ | A_nexp n -> KidSet.empty
+ | A_typ typ -> typ_frees ~exs:exs typ
+ | A_order ord -> KidSet.empty
let rec typ_int_frees ?exs:(exs=KidSet.empty) (Typ_aux (typ_aux, l)) =
match typ_aux with
@@ -274,25 +266,16 @@ let rec typ_int_frees ?exs:(exs=KidSet.empty) (Typ_aux (typ_aux, l)) =
| Typ_var kid -> KidSet.empty
| Typ_tup typs -> List.fold_left KidSet.union KidSet.empty (List.map (typ_int_frees ~exs:exs) typs)
| Typ_app (f, args) -> List.fold_left KidSet.union KidSet.empty (List.map (typ_arg_int_frees ~exs:exs) args)
- | Typ_exist (kids, nc, typ) -> typ_int_frees ~exs:(KidSet.of_list kids) typ
+ | Typ_exist (kopts, nc, typ) -> typ_int_frees ~exs:(KidSet.of_list (List.map kopt_kid kopts)) typ
| Typ_fn (arg_typs, ret_typ, _) ->
List.fold_left KidSet.union (typ_int_frees ~exs:exs ret_typ) (List.map (typ_int_frees ~exs:exs) arg_typs)
| Typ_bidir (t1, t2) -> KidSet.union (typ_int_frees ~exs:exs t1) (typ_int_frees ~exs:exs t2)
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and typ_arg_int_frees ?exs:(exs=KidSet.empty) (Typ_arg_aux (typ_arg_aux, l)) =
+and typ_arg_int_frees ?exs:(exs=KidSet.empty) (A_aux (typ_arg_aux, l)) =
match typ_arg_aux with
- | Typ_arg_nexp n -> KidSet.diff (tyvars_of_nexp n) exs
- | Typ_arg_typ typ -> KidSet.empty
- | Typ_arg_order ord -> KidSet.empty
-
-let uvar_int_frees = function
- | Type_check.U_nexp n -> tyvars_of_nexp n
- | Type_check.U_typ typ -> typ_int_frees typ
- | _ -> KidSet.empty
-
-let uvar_typ_frees = function
- | Type_check.U_typ typ -> typ_frees typ
- | _ -> KidSet.empty
+ | A_nexp n -> KidSet.diff (tyvars_of_nexp n) exs
+ | A_typ typ -> typ_int_frees ~exs:exs typ
+ | A_order ord -> KidSet.empty
let specialize_id_valspec instantiations id ast =
match split_defs (is_valspec id) ast with
@@ -313,14 +296,14 @@ let specialize_id_valspec instantiations id ast =
(* Collect any new type variables introduced by the instantiation *)
let collect_kids kidsets = KidSet.elements (List.fold_left KidSet.union KidSet.empty kidsets) in
- let typ_frees = KBindings.bindings instantiation |> List.map snd |> List.map uvar_typ_frees |> collect_kids in
- let int_frees = KBindings.bindings instantiation |> List.map snd |> List.map uvar_int_frees |> collect_kids in
+ let typ_frees = KBindings.bindings instantiation |> List.map snd |> List.map typ_arg_frees |> collect_kids in
+ let int_frees = KBindings.bindings instantiation |> List.map snd |> List.map typ_arg_int_frees |> collect_kids in
(* Remove type variables from the type quantifier. *)
let kopts, constraints = quant_split typq in
let kopts = List.filter (fun kopt -> not (is_typ_kopt kopt || is_order_kopt kopt)) kopts in
- let typq = mk_typquant (List.map (mk_qi_id BK_type) typ_frees
- @ List.map (mk_qi_id BK_int) int_frees
+ let typq = mk_typquant (List.map (mk_qi_id K_type) typ_frees
+ @ List.map (mk_qi_id K_int) int_frees
@ List.map mk_qi_kopt kopts
@ List.map mk_qi_nc constraints) in
let typschm = mk_typschm typq typ in
diff --git a/src/specialize.mli b/src/specialize.mli
index 87533e9b..f2c94a48 100644
--- a/src/specialize.mli
+++ b/src/specialize.mli
@@ -68,6 +68,6 @@ val polymorphic_functions : (kinded_id -> bool) -> 'a defs -> IdSet.t
which case specialize returns the AST unmodified. *)
val specialize : tannot defs -> Env.t -> tannot defs * Env.t
-val instantiations_of : id -> tannot defs -> uvar KBindings.t list
+val instantiations_of : id -> tannot defs -> typ_arg KBindings.t list
-val string_of_instantiation : uvar KBindings.t -> string
+val string_of_instantiation : typ_arg KBindings.t -> string
diff --git a/src/state.ml b/src/state.ml
index 70e53a52..c9a47b06 100644
--- a/src/state.ml
+++ b/src/state.ml
@@ -102,12 +102,12 @@ let generate_initial_regstate defs =
if string_of_id id = "unit" then "()" else
Bindings.find id vals []
| Typ_app (id, _) when string_of_id id = "list" -> "[||]"
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp nexp, _)]) when string_of_id id = "atom" ->
+ | Typ_app (id, [A_aux (A_nexp nexp, _)]) when string_of_id id = "atom" ->
string_of_nexp nexp
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp nexp, _); _]) when string_of_id id = "range" ->
+ | Typ_app (id, [A_aux (A_nexp nexp, _); _]) when string_of_id id = "range" ->
string_of_nexp nexp
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant len, _)), _); _ ;
- Typ_arg_aux (Typ_arg_typ etyp, _)])
+ | Typ_app (id, [A_aux (A_nexp (Nexp_aux (Nexp_constant len, _)), _); _ ;
+ A_aux (A_typ etyp, _)])
when string_of_id id = "vector" ->
(* Output a list of initial values of the vector elements, or a
literal binary zero value if this is a bitvector and the
@@ -127,15 +127,9 @@ let generate_initial_regstate defs =
| Typ_exist (_, _, typ) -> lookup_init_val vals typ
| _ -> raise Not_found
in
- (* Helper functions to instantiate type arguments *)
- let typ_subst_targ kid (Typ_arg_aux (arg, _)) typ = match arg with
- | Typ_arg_nexp (Nexp_aux (nexp, _)) -> typ_subst_nexp kid nexp typ
- | Typ_arg_typ (Typ_aux (typ', _)) -> typ_subst_typ kid typ' typ
- | Typ_arg_order (Ord_aux (ord, _)) -> typ_subst_order kid ord typ
- in
let typ_subst_quant_item typ (QI_aux (qi, _)) arg = match qi with
- | QI_id (KOpt_aux ((KOpt_none kid | KOpt_kind (_, kid)), _)) ->
- typ_subst_targ kid arg typ
+ | QI_id (KOpt_aux (KOpt_kind (_, kid), _)) ->
+ typ_subst kid arg typ
| _ -> typ
in
let typ_subst_typquant tq args typ =
@@ -152,7 +146,7 @@ let generate_initial_regstate defs =
string_of_id id1 ^ " (" ^ lookup_init_val vals typ1 ^ ")"
in
Bindings.add id init_val vals
- | TD_abbrev (id, _, TypSchm_aux (TypSchm_ts (tq, typ), _)) ->
+ | TD_abbrev (id, tq, A_aux (A_typ typ, _)) ->
let init_val args = lookup_init_val vals (typ_subst_typquant tq args typ) in
Bindings.add id init_val vals
| TD_record (id, _, tq, fields, _) ->
@@ -180,19 +174,19 @@ let generate_initial_regstate defs =
let rec regval_constr_id mwords (Typ_aux (t, l) as typ) = match t with
| Typ_id id -> id
| Typ_app (id, args) ->
- let name_arg (Typ_arg_aux (targ, _)) = match targ with
- | Typ_arg_typ targ -> string_of_id (regval_constr_id mwords targ)
- | Typ_arg_nexp nexp when is_nexp_constant (nexp_simp nexp) ->
+ let name_arg (A_aux (targ, _)) = match targ with
+ | A_typ targ -> string_of_id (regval_constr_id mwords targ)
+ | A_nexp nexp when is_nexp_constant (nexp_simp nexp) ->
string_of_nexp (nexp_simp nexp)
- | Typ_arg_order (Ord_aux (Ord_inc, _)) -> "inc"
- | Typ_arg_order (Ord_aux (Ord_dec, _)) -> "dec"
+ | A_order (Ord_aux (Ord_inc, _)) -> "inc"
+ | A_order (Ord_aux (Ord_dec, _)) -> "dec"
| _ ->
- raise (Reporting_basic.err_typ l "Unsupported register type")
+ raise (Reporting.err_typ l "Unsupported register type")
in
let builtins = IdSet.of_list (List.map mk_id ["vector"; "list"; "option"]) in
if IdSet.mem id builtins && not (mwords && is_bitvector_typ typ) then id else
append_id id (String.concat "_" ("" :: List.map name_arg args))
- | _ -> raise (Reporting_basic.err_typ l "Unsupported register type")
+ | _ -> raise (Reporting.err_typ l "Unsupported register type")
let register_base_types mwords typs =
let rec add_base_typs typs (Typ_aux (t, _) as typ) =
@@ -200,9 +194,9 @@ let register_base_types mwords typs =
match t with
| Typ_app (id, args)
when IdSet.mem id builtins && not (mwords && is_bitvector_typ typ) ->
- let add_typ_arg base_typs (Typ_arg_aux (targ, _)) =
+ let add_typ_arg base_typs (A_aux (targ, _)) =
match targ with
- | Typ_arg_typ typ -> add_base_typs typs typ
+ | A_typ typ -> add_base_typs typs typ
| _ -> typs
in
List.fold_left add_typ_arg typs args
@@ -249,12 +243,12 @@ let rec regval_convs_lem mwords (Typ_aux (t, _) as typ) = match t with
let etyp_of, of_etyp = regval_convs_lem mwords etyp in
"(fun v -> vector_of_regval " ^ etyp_of ^ " v)",
"(fun v -> regval_of_vector " ^ of_etyp ^ " " ^ size ^ " " ^ is_inc ^ " v)"
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ etyp, _)])
+ | Typ_app (id, [A_aux (A_typ etyp, _)])
when string_of_id id = "list" ->
let etyp_of, of_etyp = regval_convs_lem mwords etyp in
"(fun v -> list_of_regval " ^ etyp_of ^ " v)",
"(fun v -> regval_of_list " ^ of_etyp ^ " v)"
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ etyp, _)])
+ | Typ_app (id, [A_aux (A_typ etyp, _)])
when string_of_id id = "option" ->
let etyp_of, of_etyp = regval_convs_lem mwords etyp in
"(fun v -> option_of_regval " ^ etyp_of ^ " v)",
@@ -413,12 +407,12 @@ let rec regval_convs_coq (Typ_aux (t, _) as typ) = match t with
let etyp_of, of_etyp = regval_convs_coq etyp in
"(fun v => vector_of_regval " ^ size ^ " " ^ etyp_of ^ " v)",
"(fun v => regval_of_vector " ^ of_etyp ^ " " ^ size ^ " " ^ is_inc ^ " v)"
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ etyp, _)])
+ | Typ_app (id, [A_aux (A_typ etyp, _)])
when string_of_id id = "list" ->
let etyp_of, of_etyp = regval_convs_coq etyp in
"(fun v => list_of_regval " ^ etyp_of ^ " v)",
"(fun v => regval_of_list " ^ of_etyp ^ " v)"
- | Typ_app (id, [Typ_arg_aux (Typ_arg_typ etyp, _)])
+ | Typ_app (id, [A_aux (A_typ etyp, _)])
when string_of_id id = "option" ->
let etyp_of, of_etyp = regval_convs_coq etyp in
"(fun v => option_of_regval " ^ etyp_of ^ " v)",
diff --git a/src/type_check.ml b/src/type_check.ml
index 88d33569..63f03c81 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -69,9 +69,9 @@ let opt_no_effects = ref false
assignments in l-expressions *)
let opt_no_lexp_bounds_check = ref false
-(* opt_constraint_synonyms allows constraint synonyms as toplevel
- definitions *)
-let opt_constraint_synonyms = ref false
+(* opt_expand_valspec expands typedefs in valspecs during type check.
+ We prefer not to do it for latex output but it is otherwise a good idea. *)
+let opt_expand_valspec = ref true
let depth = ref 0
@@ -82,7 +82,7 @@ let rec indent n = match n with
(* Lazily evaluate debugging message. This can make a big performance
difference; for example, repeated calls to string_of_exp can be costly for
deeply nested expressions, e.g. with long sequences of monadic binds. *)
-let typ_debug m = if !opt_tc_debug > 1 then prerr_endline (indent !depth ^ Lazy.force m) else ()
+let typ_debug ?level:(level=1) m = if !opt_tc_debug > level then prerr_endline (indent !depth ^ Lazy.force m) else ()
let typ_print m = if !opt_tc_debug > 0 then prerr_endline (indent !depth ^ Lazy.force m) else ()
@@ -92,10 +92,11 @@ type type_error =
coercions *)
| Err_no_casts of unit exp * typ * typ * type_error * type_error list
| Err_no_overloading of id * (id * type_error) list
- | Err_unresolved_quants of id * quant_item list
+ | Err_unresolved_quants of id * quant_item list * (mut * typ) Bindings.t * n_constraint list
| Err_subtype of typ * typ * n_constraint list * Ast.l KBindings.t
| Err_no_num_ident of id
| Err_other of string
+ | Err_because of type_error * type_error
exception Type_error of l * type_error;;
@@ -125,7 +126,7 @@ let orig_kid (Kid_aux (Var v, l) as kid) =
let is_list (Typ_aux (typ_aux, _)) =
match typ_aux with
- | Typ_app (f, [Typ_arg_aux (Typ_arg_typ typ, _)])
+ | Typ_app (f, [A_aux (A_typ typ, _)])
when string_of_id f = "list" -> Some typ
| _ -> None
@@ -167,17 +168,19 @@ and strip_n_constraint_aux = function
| NC_set (kid, nums) -> NC_set (strip_kid kid, nums)
| NC_or (nc1, nc2) -> NC_or (strip_n_constraint nc1, strip_n_constraint nc2)
| NC_and (nc1, nc2) -> NC_and (strip_n_constraint nc1, strip_n_constraint nc2)
- | NC_app (id, nexps) -> NC_app (strip_id id, List.map strip_nexp nexps)
+ | NC_var kid -> NC_var (strip_kid kid)
+ | NC_app (id, args) -> NC_app (strip_id id, List.map strip_typ_arg args)
| NC_true -> NC_true
| NC_false -> NC_false
and strip_n_constraint = function
| NC_aux (nc_aux, _) -> NC_aux (strip_n_constraint_aux nc_aux, Parse_ast.Unknown)
and strip_typ_arg = function
- | Typ_arg_aux (typ_arg_aux, _) -> Typ_arg_aux (strip_typ_arg_aux typ_arg_aux, Parse_ast.Unknown)
+ | A_aux (typ_arg_aux, _) -> A_aux (strip_typ_arg_aux typ_arg_aux, Parse_ast.Unknown)
and strip_typ_arg_aux = function
- | Typ_arg_nexp nexp -> Typ_arg_nexp (strip_nexp nexp)
- | Typ_arg_typ typ -> Typ_arg_typ (strip_typ typ)
- | Typ_arg_order ord -> Typ_arg_order (strip_order ord)
+ | A_nexp nexp -> A_nexp (strip_nexp nexp)
+ | A_typ typ -> A_typ (strip_typ typ)
+ | A_order ord -> A_order (strip_order ord)
+ | A_bool nc -> A_bool (strip_n_constraint nc)
and strip_order = function
| Ord_aux (ord_aux, _) -> Ord_aux (strip_order_aux ord_aux, Parse_ast.Unknown)
and strip_order_aux = function
@@ -191,7 +194,8 @@ and strip_typ_aux : typ_aux -> typ_aux = function
| Typ_fn (arg_typs, ret_typ, effect) -> Typ_fn (List.map strip_typ arg_typs, strip_typ ret_typ, strip_effect effect)
| Typ_bidir (typ1, typ2) -> Typ_bidir (strip_typ typ1, strip_typ typ2)
| Typ_tup typs -> Typ_tup (List.map strip_typ typs)
- | Typ_exist (kids, constr, typ) -> Typ_exist ((List.map strip_kid kids), strip_n_constraint constr, strip_typ typ)
+ | Typ_exist (kopts, constr, typ) ->
+ Typ_exist ((List.map strip_kinded_id kopts), strip_n_constraint constr, strip_typ typ)
| Typ_app (id, args) -> Typ_app (strip_id id, List.map strip_typ_arg args)
and strip_typ : typ -> typ = function
| Typ_aux (typ_aux, _) -> Typ_aux (strip_typ_aux typ_aux, Parse_ast.Unknown)
@@ -207,145 +211,63 @@ and strip_qi_aux = function
and strip_kinded_id = function
| KOpt_aux (kinded_id_aux, _) -> KOpt_aux (strip_kinded_id_aux kinded_id_aux, Parse_ast.Unknown)
and strip_kinded_id_aux = function
- | KOpt_none kid -> KOpt_none (strip_kid kid)
| KOpt_kind (kind, kid) -> KOpt_kind (strip_kind kind, strip_kid kid)
and strip_kind = function
- | K_aux (k_aux, _) -> K_aux (strip_kind_aux k_aux, Parse_ast.Unknown)
-and strip_kind_aux = function
- | K_kind base_kinds -> K_kind (List.map strip_base_kind base_kinds)
-and strip_base_kind = function
- | BK_aux (bk_aux, _) -> BK_aux (bk_aux, Parse_ast.Unknown)
+ | K_aux (k_aux, _) -> K_aux (k_aux, Parse_ast.Unknown)
+let ex_counter = ref 0
-(**************************************************************************)
-(* 1. Substitutions *)
-(**************************************************************************)
-
-let rec nexp_subst sv subst (Nexp_aux (nexp, l)) = Nexp_aux (nexp_subst_aux sv subst nexp, l)
-and nexp_subst_aux sv subst = function
- | Nexp_id v -> Nexp_id v
- | Nexp_var kid -> if Kid.compare kid sv = 0 then subst else Nexp_var kid
- | Nexp_constant c -> Nexp_constant c
- | Nexp_times (nexp1, nexp2) -> Nexp_times (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
- | Nexp_sum (nexp1, nexp2) -> Nexp_sum (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
- | Nexp_minus (nexp1, nexp2) -> Nexp_minus (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
- | Nexp_app (id, nexps) -> Nexp_app (id, List.map (nexp_subst sv subst) nexps)
- | Nexp_exp nexp -> Nexp_exp (nexp_subst sv subst nexp)
- | Nexp_neg nexp -> Nexp_neg (nexp_subst sv subst nexp)
-
-let rec nexp_set_to_or l subst = function
- | [] -> typ_error l "Cannot substitute into empty nexp set"
- | [int] -> NC_equal (subst, nconstant int)
- | (int :: ints) -> NC_or (mk_nc (NC_equal (subst, nconstant int)), mk_nc (nexp_set_to_or l subst ints))
-
-let rec nc_subst_nexp sv subst (NC_aux (nc, l)) = NC_aux (nc_subst_nexp_aux l sv subst nc, l)
-and nc_subst_nexp_aux l sv subst = function
- | NC_equal (n1, n2) -> NC_equal (nexp_subst sv subst n1, nexp_subst sv subst n2)
- | NC_bounded_ge (n1, n2) -> NC_bounded_ge (nexp_subst sv subst n1, nexp_subst sv subst n2)
- | NC_bounded_le (n1, n2) -> NC_bounded_le (nexp_subst sv subst n1, nexp_subst sv subst n2)
- | NC_not_equal (n1, n2) -> NC_not_equal (nexp_subst sv subst n1, nexp_subst sv subst n2)
- | NC_set (kid, ints) as set_nc ->
- if Kid.compare kid sv = 0
- then nexp_set_to_or l (mk_nexp subst) ints
- else set_nc
- | NC_or (nc1, nc2) -> NC_or (nc_subst_nexp sv subst nc1, nc_subst_nexp sv subst nc2)
- | NC_and (nc1, nc2) -> NC_and (nc_subst_nexp sv subst nc1, nc_subst_nexp sv subst nc2)
- | NC_app (id, nexps) -> NC_app (id, List.map (nexp_subst sv subst) nexps)
- | NC_false -> NC_false
- | NC_true -> NC_true
-
-let rec typ_subst_nexp sv subst (Typ_aux (typ, l)) = Typ_aux (typ_subst_nexp_aux sv subst typ, l)
-and typ_subst_nexp_aux sv subst = function
- | Typ_internal_unknown -> Typ_internal_unknown
- | Typ_id v -> Typ_id v
- | Typ_var kid -> Typ_var kid
- | Typ_fn (arg_typs, ret_typ, effs) -> Typ_fn (List.map (typ_subst_nexp sv subst) arg_typs, typ_subst_nexp sv subst ret_typ, effs)
- | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst_nexp sv subst typ1, typ_subst_nexp sv subst typ2)
- | Typ_tup typs -> Typ_tup (List.map (typ_subst_nexp sv subst) typs)
- | Typ_app (f, args) -> Typ_app (f, List.map (typ_subst_arg_nexp sv subst) args)
- | Typ_exist (kids, nc, typ) when KidSet.mem sv (KidSet.of_list kids) -> Typ_exist (kids, nc, typ)
- | Typ_exist (kids, nc, typ) -> Typ_exist (kids, nc_subst_nexp sv subst nc, typ_subst_nexp sv subst typ)
-and typ_subst_arg_nexp sv subst (Typ_arg_aux (arg, l)) = Typ_arg_aux (typ_subst_arg_nexp_aux sv subst arg, l)
-and typ_subst_arg_nexp_aux sv subst = function
- | Typ_arg_nexp nexp -> Typ_arg_nexp (nexp_subst sv subst nexp)
- | Typ_arg_typ typ -> Typ_arg_typ (typ_subst_nexp sv subst typ)
- | Typ_arg_order ord -> Typ_arg_order ord
-
-let rec typ_subst_typ sv subst (Typ_aux (typ, l)) = Typ_aux (typ_subst_typ_aux sv subst typ, l)
-and typ_subst_typ_aux sv subst = function
- | Typ_internal_unknown -> Typ_internal_unknown
- | Typ_id v -> Typ_id v
- | Typ_var kid -> if Kid.compare kid sv = 0 then subst else Typ_var kid
- | Typ_fn (arg_typs, ret_typ, effs) -> Typ_fn (List.map (typ_subst_typ sv subst) arg_typs, typ_subst_typ sv subst ret_typ, effs)
- | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst_typ sv subst typ1, typ_subst_typ sv subst typ2)
- | Typ_tup typs -> Typ_tup (List.map (typ_subst_typ sv subst) typs)
- | Typ_app (f, args) -> Typ_app (f, List.map (typ_subst_arg_typ sv subst) args)
- | Typ_exist (kids, nc, typ) -> Typ_exist (kids, nc, typ_subst_typ sv subst typ)
-and typ_subst_arg_typ sv subst (Typ_arg_aux (arg, l)) = Typ_arg_aux (typ_subst_arg_typ_aux sv subst arg, l)
-and typ_subst_arg_typ_aux sv subst = function
- | Typ_arg_nexp nexp -> Typ_arg_nexp nexp
- | Typ_arg_typ typ -> Typ_arg_typ (typ_subst_typ sv subst typ)
- | Typ_arg_order ord -> Typ_arg_order ord
-
-let order_subst_aux sv subst = function
- | Ord_var kid -> if Kid.compare kid sv = 0 then subst else Ord_var kid
- | Ord_inc -> Ord_inc
- | Ord_dec -> Ord_dec
+let fresh_existential ?name:(n="") k =
+ let fresh = Kid_aux (Var ("'ex" ^ string_of_int !ex_counter ^ "#" ^ n), Parse_ast.Unknown) in
+ incr ex_counter; mk_kopt k fresh
-let order_subst sv subst (Ord_aux (ord, l)) = Ord_aux (order_subst_aux sv subst ord, l)
+let destruct_exist_plain typ =
+ match typ with
+ | Typ_aux (Typ_exist (kopts, nc, typ), _) ->
+ let fresh_kopts =
+ List.map (fun kopt -> (kopt_kid kopt,
+ fresh_existential ~name:(string_of_id (id_of_kid (kopt_kid kopt))) (unaux_kind (kopt_kind kopt))))
+ kopts
+ in
+ let nc = List.fold_left (fun nc (kid, fresh) -> constraint_subst kid (arg_kopt fresh) nc) nc fresh_kopts in
+ let typ = List.fold_left (fun typ (kid, fresh) -> typ_subst kid (arg_kopt fresh) typ) typ fresh_kopts in
+ Some (List.map snd fresh_kopts, nc, typ)
+ | _ -> None
-let rec typ_subst_order sv subst (Typ_aux (typ, l)) = Typ_aux (typ_subst_order_aux sv subst typ, l)
-and typ_subst_order_aux sv subst = function
- | Typ_internal_unknown -> Typ_internal_unknown
- | Typ_id v -> Typ_id v
- | Typ_var kid -> Typ_var kid
- | Typ_fn (arg_typs, ret_typ, effs) -> Typ_fn (List.map (typ_subst_order sv subst) arg_typs, typ_subst_order sv subst ret_typ, effs)
- | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst_order sv subst typ1, typ_subst_order sv subst typ2)
- | Typ_tup typs -> Typ_tup (List.map (typ_subst_order sv subst) typs)
- | Typ_app (f, args) -> Typ_app (f, List.map (typ_subst_arg_order sv subst) args)
- | Typ_exist (kids, nc, typ) -> Typ_exist (kids, nc, typ_subst_order sv subst typ)
-and typ_subst_arg_order sv subst (Typ_arg_aux (arg, l)) = Typ_arg_aux (typ_subst_arg_order_aux sv subst arg, l)
-and typ_subst_arg_order_aux sv subst = function
- | Typ_arg_nexp nexp -> Typ_arg_nexp nexp
- | Typ_arg_typ typ -> Typ_arg_typ (typ_subst_order sv subst typ)
- | Typ_arg_order ord -> Typ_arg_order (order_subst sv subst ord)
-
-let rec typ_subst_kid sv subst (Typ_aux (typ, l)) = Typ_aux (typ_subst_kid_aux sv subst typ, l)
-and typ_subst_kid_aux sv subst = function
- | Typ_internal_unknown -> Typ_internal_unknown
- | Typ_id v -> Typ_id v
- | Typ_var kid -> if Kid.compare kid sv = 0 then Typ_var subst else Typ_var kid
- | Typ_fn (arg_typs, ret_typ, effs) -> Typ_fn (List.map (typ_subst_kid sv subst) arg_typs, typ_subst_kid sv subst ret_typ, effs)
- | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst_kid sv subst typ1, typ_subst_kid sv subst typ2)
- | Typ_tup typs -> Typ_tup (List.map (typ_subst_kid sv subst) typs)
- | Typ_app (f, args) -> Typ_app (f, List.map (typ_subst_arg_kid sv subst) args)
- | Typ_exist (kids, nc, typ) when KidSet.mem sv (KidSet.of_list kids) -> Typ_exist (kids, nc, typ)
- | Typ_exist (kids, nc, typ) -> Typ_exist (kids, nc_subst_nexp sv (Nexp_var subst) nc, typ_subst_kid sv subst typ)
-and typ_subst_arg_kid sv subst (Typ_arg_aux (arg, l)) = Typ_arg_aux (typ_subst_arg_kid_aux sv subst arg, l)
-and typ_subst_arg_kid_aux sv subst = function
- | Typ_arg_nexp nexp -> Typ_arg_nexp (nexp_subst sv (Nexp_var subst) nexp)
- | Typ_arg_typ typ -> Typ_arg_typ (typ_subst_kid sv subst typ)
- | Typ_arg_order ord -> Typ_arg_order (order_subst sv (Ord_var subst) ord)
-
-let quant_item_subst_kid_aux sv subst = function
- | QI_id (KOpt_aux (KOpt_none kid, l)) as qid ->
- if Kid.compare kid sv = 0 then QI_id (KOpt_aux (KOpt_none subst, l)) else qid
- | QI_id (KOpt_aux (KOpt_kind (k, kid), l)) as qid ->
- if Kid.compare kid sv = 0 then QI_id (KOpt_aux (KOpt_kind (k, subst), l)) else qid
- | QI_const nc -> QI_const (nc_subst_nexp sv (Nexp_var subst) nc)
-
-let quant_item_subst_kid sv subst (QI_aux (quant, l)) = QI_aux (quant_item_subst_kid_aux sv subst quant, l)
-
-let typquant_subst_kid_aux sv subst = function
- | TypQ_tq quants -> TypQ_tq (List.map (quant_item_subst_kid sv subst) quants)
- | TypQ_no_forall -> TypQ_no_forall
+(** Destructure and canonicalise a numeric type into a list of type
+ variables, a constraint on those type variables, and an
+ N-expression that represents that numeric type in the
+ environment. For example:
+ - {'n, 'n <= 10. atom('n)} => ['n], 'n <= 10, 'n
+ - int => ['n], true, 'n (where x is fresh)
+ - atom('n) => [], true, 'n
+**)
+let destruct_numeric typ =
+ match destruct_exist_plain typ, typ with
+ | Some (kids, nc, Typ_aux (Typ_app (id, [A_aux (A_nexp nexp, _)]), _)), _ when string_of_id id = "atom" ->
+ Some (List.map kopt_kid kids, nc, nexp)
+ | None, Typ_aux (Typ_app (id, [A_aux (A_nexp nexp, _)]), _) when string_of_id id = "atom" ->
+ Some ([], nc_true, nexp)
+ | None, Typ_aux (Typ_app (id, [A_aux (A_nexp lo, _); A_aux (A_nexp hi, _)]), _) when string_of_id id = "range" ->
+ let kid = kopt_kid (fresh_existential K_int) in
+ Some ([kid], nc_and (nc_lteq lo (nvar kid)) (nc_lteq (nvar kid) hi), nvar kid)
+ | None, Typ_aux (Typ_id id, _) when string_of_id id = "nat" ->
+ let kid = kopt_kid (fresh_existential K_int) in
+ Some ([kid], nc_lteq (nint 0) (nvar kid), nvar kid)
+ | None, Typ_aux (Typ_id id, _) when string_of_id id = "int" ->
+ let kid = kopt_kid (fresh_existential K_int) in
+ Some ([kid], nc_true, nvar kid)
+ | _, _ -> None
-let typquant_subst_kid sv subst (TypQ_aux (typq, l)) = TypQ_aux (typquant_subst_kid_aux sv subst typq, l)
+let destruct_exist typ =
+ match destruct_numeric typ with
+ | Some (kids, nc, nexp) -> Some (List.map (mk_kopt K_int) kids, nc, atom_typ nexp)
+ | None -> destruct_exist_plain typ
let adding = Util.("Adding " |> darkgray |> clear)
(**************************************************************************)
-(* 2. Environment *)
+(* 1. Environment *)
(**************************************************************************)
module Env : sig
@@ -366,24 +288,27 @@ module Env : sig
val add_local : id -> mut * typ -> t -> t
val get_locals : t -> (mut * typ) Bindings.t
val add_variant : id -> typquant * type_union list -> t -> t
+ val add_scattered_variant : id -> typquant -> t -> t
+ val add_variant_clause : id -> type_union -> t -> t
+ val get_variant : id -> t -> typquant * type_union list
val add_mapping : id -> typquant * typ * typ -> t -> t
val add_union_id : id -> typquant * typ -> t -> t
+ val get_union_id : id -> t -> typquant * typ
val is_register : id -> t -> bool
val get_register : id -> t -> effect * effect * typ
val add_register : id -> effect -> effect -> typ -> t -> t
val is_mutable : id -> t -> bool
val get_constraints : t -> n_constraint list
val add_constraint : n_constraint -> t -> t
- val get_typ_var : kid -> t -> base_kind_aux
+ val get_typ_var : kid -> t -> kind_aux
val get_typ_var_loc : kid -> t -> Ast.l
- val get_typ_vars : t -> base_kind_aux KBindings.t
+ val get_typ_vars : t -> kind_aux KBindings.t
val get_typ_var_locs : t -> Ast.l KBindings.t
- val add_typ_var : l -> kid -> base_kind_aux -> t -> t
+ val add_typ_var : l -> kinded_id -> t -> t
val get_ret_typ : t -> typ option
val add_ret_typ : typ -> t -> t
- val add_typ_synonym : id -> (t -> typ_arg list -> typ) -> t -> t
- val get_typ_synonym : id -> t -> t -> typ_arg list -> typ
- val add_constraint_synonym : id -> kid list -> n_constraint -> t -> t
+ val add_typ_synonym : id -> (t -> typ_arg list -> typ_arg) -> t -> t
+ val get_typ_synonym : id -> t -> t -> typ_arg list -> typ_arg
val add_num_def : id -> nexp -> t -> t
val get_num_def : id -> t -> nexp
val add_overloads : id -> id list -> t -> t
@@ -406,16 +331,9 @@ module Env : sig
val polymorphic_undefineds : t -> bool
val lookup_id : ?raw:bool -> id -> t -> typ lvar
val fresh_kid : ?kid:kid -> t -> kid
-
val expand_synonyms : t -> typ -> typ
val expand_constraint_synonyms : t -> n_constraint -> n_constraint
- val expand_typquant_synonyms : t -> typquant -> typquant
-
- val canonicalize : t -> typ -> typ
val base_typ_of : t -> typ -> typ
- val add_smt_op : id -> string -> t -> t
- val get_smt_op : id -> t -> string
- val have_smt_op : id -> t -> bool
val allow_unknowns : t -> bool
val set_allow_unknowns : bool -> t -> t
@@ -448,16 +366,14 @@ end = struct
registers : (effect * effect * typ) Bindings.t;
variants : (typquant * type_union list) Bindings.t;
mappings : (typquant * typ * typ) Bindings.t;
- typ_vars : (Ast.l * base_kind_aux) KBindings.t;
- typ_synonyms : (t -> typ_arg list -> typ) Bindings.t;
+ typ_vars : (Ast.l * kind_aux) KBindings.t;
+ typ_synonyms : (t -> typ_arg list -> typ_arg) Bindings.t;
num_defs : nexp Bindings.t;
overloads : (id list) Bindings.t;
enums : IdSet.t Bindings.t;
records : (typquant * (typ * id) list) Bindings.t;
accessors : (typquant * typ) Bindings.t;
externs : (string * string) list Bindings.t;
- smt_ops : string Bindings.t;
- constraint_synonyms : (kid list * n_constraint) Bindings.t;
casts : id list;
allow_casts : bool;
allow_bindings : bool;
@@ -485,8 +401,6 @@ end = struct
records = Bindings.empty;
accessors = Bindings.empty;
externs = Bindings.empty;
- smt_ops = Bindings.empty;
- constraint_synonyms = Bindings.empty;
casts = [];
allow_bindings = true;
allow_casts = true;
@@ -514,26 +428,27 @@ end = struct
let get_typ_vars env = KBindings.map snd env.typ_vars
let get_typ_var_locs env = KBindings.map fst env.typ_vars
- let bk_counter = ref 0
- let bk_name () = let kid = mk_kid ("bk#" ^ string_of_int !bk_counter) in incr bk_counter; kid
+ let k_counter = ref 0
+ let k_name () = let kid = mk_kid ("k#" ^ string_of_int !k_counter) in incr k_counter; kid
- let kinds_typq kinds = mk_typquant (List.map (fun k -> mk_qi_id k (bk_name ())) kinds)
+ let kinds_typq kinds = mk_typquant (List.map (fun k -> mk_qi_id k (k_name ())) kinds)
let builtin_typs =
List.fold_left (fun m (name, kinds) -> Bindings.add (mk_id name) (kinds_typq kinds) m) Bindings.empty
- [ ("range", [BK_int; BK_int]);
- ("atom", [BK_int]);
- ("vector", [BK_int; BK_order; BK_type]);
- ("register", [BK_type]);
+ [ ("range", [K_int; K_int]);
+ ("atom", [K_int]);
+ ("vector", [K_int; K_order; K_type]);
+ ("register", [K_type]);
("bit", []);
("unit", []);
("int", []);
("nat", []);
("bool", []);
("real", []);
- ("list", [BK_type]);
+ ("list", [K_type]);
("string", []);
- ("itself", [BK_int])
+ ("itself", [K_int]);
+ ("atom_bool", [K_bool])
]
let builtin_mappings =
@@ -559,21 +474,6 @@ end = struct
let existing = try Bindings.find id env.overloads with Not_found -> [] in
{ env with overloads = Bindings.add id (existing @ ids) env.overloads }
- let add_smt_op id str env =
- typ_print (lazy (adding ^ "smt binding " ^ string_of_id id ^ " to " ^ str));
- { env with smt_ops = Bindings.add id str env.smt_ops }
-
- let get_smt_op (Id_aux (_, l) as id) env =
- let rec first_smt_op = function
- | id :: ids -> (try Bindings.find id env.smt_ops with Not_found -> first_smt_op ids)
- | [] -> typ_error l ("No SMT op for " ^ string_of_id id)
- in
- try Bindings.find id env.smt_ops with
- | Not_found -> first_smt_op (get_overloads id env)
-
- let have_smt_op id env =
- try ignore(get_smt_op id env); true with Type_error _ -> false
-
let rec infer_kind env id =
if Bindings.mem id builtin_typs then
Bindings.find id builtin_typs
@@ -592,14 +492,16 @@ end = struct
let kopts, ncs = quant_split typq in
let rec subst_args kopts args =
match kopts, args with
- | kopt :: kopts, Typ_arg_aux (Typ_arg_nexp arg, _) :: args when is_nat_kopt kopt ->
- List.map (nc_subst_nexp (kopt_kid kopt) (unaux_nexp arg)) (subst_args kopts args)
- | kopt :: kopts, Typ_arg_aux (Typ_arg_typ arg, _) :: args when is_typ_kopt kopt ->
+ | kopt :: kopts, (A_aux (A_nexp _, _) as arg) :: args when is_nat_kopt kopt ->
+ List.map (constraint_subst (kopt_kid kopt) arg) (subst_args kopts args)
+ | kopt :: kopts, A_aux (A_typ arg, _) :: args when is_typ_kopt kopt ->
+ subst_args kopts args
+ | kopt :: kopts, A_aux (A_order arg, _) :: args when is_order_kopt kopt ->
subst_args kopts args
- | kopt :: kopts, Typ_arg_aux (Typ_arg_order arg, _) :: args when is_order_kopt kopt ->
+ | kopt :: kopts, A_aux (A_bool arg, _) :: args when is_bool_kopt kopt ->
subst_args kopts args
| [], [] -> ncs
- | _, Typ_arg_aux (_, l) :: _ -> typ_error l ("Error when processing type quantifer arguments " ^ string_of_typquant typq)
+ | _, A_aux (_, l) :: _ -> typ_error l ("Error when processing type quantifer arguments " ^ string_of_typquant typq)
| _, _ -> typ_error Parse_ast.Unknown ("Error when processing type quantifer arguments " ^ string_of_typquant typq)
in
let ncs = subst_args kopts args in
@@ -607,50 +509,43 @@ end = struct
then ()
else typ_error (id_loc id) ("Could not prove " ^ string_of_list ", " string_of_n_constraint ncs ^ " for type constructor " ^ string_of_id id)
- let rec expand_constraint_synonyms env (NC_aux (nc_aux, l) as nc) =
- let expand = expand_constraint_synonyms env in
- match nc_aux with
- | NC_app (id, nexps) ->
- begin
- try
- let kids, nc = Bindings.find id env.constraint_synonyms in
- let nc = List.fold_left2 (fun nc kid nexp -> nc_subst_nexp kid (unaux_nexp nexp) nc) nc kids nexps in
- expand nc
- with Not_found -> typ_error l ("Could not expand constraint synonym in " ^ string_of_n_constraint nc)
- end
- | NC_and (nc1, nc2) -> NC_aux (NC_and (expand nc1, expand nc2), l)
- | NC_or (nc1, nc2) -> NC_aux (NC_or (expand nc1, expand nc2), l)
- | NC_true | NC_false | NC_set _ | NC_equal _ | NC_not_equal _ | NC_bounded_le _ | NC_bounded_ge _ -> nc
-
- let expand_quant_item_synonyms env = function
- | QI_aux (QI_id kopt, l) -> QI_aux (QI_id kopt, l)
- | QI_aux (QI_const nc, l) -> QI_aux (QI_const (expand_constraint_synonyms env nc), l)
-
- let expand_typquant_synonyms env = quant_map_items (expand_quant_item_synonyms env)
+ let rec expand_constraint_synonyms env (NC_aux (aux, l) as nc) =
+ typ_debug ~level:2 (lazy ("Expanding " ^ string_of_n_constraint nc));
+ match aux with
+ | NC_or (nc1, nc2) -> NC_aux (NC_or (expand_constraint_synonyms env nc1, expand_constraint_synonyms env nc2), l)
+ | NC_and (nc1, nc2) -> NC_aux (NC_and (expand_constraint_synonyms env nc1, expand_constraint_synonyms env nc2), l)
+ | NC_app (id, args) ->
+ (try
+ begin match Bindings.find id env.typ_synonyms env args with
+ | A_aux (A_bool nc, _) -> expand_constraint_synonyms env nc
+ | arg -> typ_error l ("Expected Bool when expanding synonym " ^ string_of_id id ^ " got " ^ string_of_typ_arg arg)
+ end
+ with Not_found -> NC_aux (NC_app (id, List.map (expand_synonyms_arg env) args), l))
+ | NC_true | NC_false | NC_equal _ | NC_not_equal _ | NC_bounded_le _ | NC_bounded_ge _ | NC_var _ | NC_set _ -> nc
- let rec expand_synonyms env (Typ_aux (typ, l) as t) =
+ and expand_synonyms env (Typ_aux (typ, l) as t) =
match typ with
| Typ_internal_unknown -> Typ_aux (Typ_internal_unknown, l)
| Typ_tup typs -> Typ_aux (Typ_tup (List.map (expand_synonyms env) typs), l)
| Typ_fn (arg_typs, ret_typ, effs) -> Typ_aux (Typ_fn (List.map (expand_synonyms env) arg_typs, expand_synonyms env ret_typ, effs), l)
| Typ_bidir (typ1, typ2) -> Typ_aux (Typ_bidir (expand_synonyms env typ1, expand_synonyms env typ2), l)
| Typ_app (id, args) ->
- begin
- try
- let synonym = Bindings.find id env.typ_synonyms in
- expand_synonyms env (synonym env args)
- with
- | Not_found -> Typ_aux (Typ_app (id, List.map (expand_synonyms_arg env) args), l)
- end
+ (try
+ begin match Bindings.find id env.typ_synonyms env args with
+ | A_aux (A_typ typ, _) -> expand_synonyms env typ
+ | _ -> typ_error l ("Expected Type when expanding synonym " ^ string_of_id id)
+ end
+ with
+ | Not_found -> Typ_aux (Typ_app (id, List.map (expand_synonyms_arg env) args), l))
| Typ_id id ->
- begin
- try
- let synonym = Bindings.find id env.typ_synonyms in
- expand_synonyms env (synonym env [])
- with
- | Not_found -> Typ_aux (Typ_id id, l)
- end
- | Typ_exist (kids, nc, typ) ->
+ (try
+ begin match Bindings.find id env.typ_synonyms env [] with
+ | A_aux (A_typ typ, _) -> expand_synonyms env typ
+ | _ -> typ_error l ("Expected Type when expanding synonym " ^ string_of_id id)
+ end
+ with
+ | Not_found -> Typ_aux (Typ_id id, l))
+ | Typ_exist (kopts, nc, typ) ->
(* When expanding an existential synonym we need to take care
to add the type variables and constraints to the
environment, so we can check constraints attached to type
@@ -659,29 +554,33 @@ end = struct
scope while doing this. *)
let rebindings = ref [] in
- let rename_kid kid = if KBindings.mem kid env.typ_vars then prepend_kid "syn#" kid else kid in
- let add_typ_var env kid =
+ let rename_kopt (KOpt_aux (KOpt_kind (k, kid), l) as kopt) =
+ if KBindings.mem kid env.typ_vars then
+ KOpt_aux (KOpt_kind (k, prepend_kid "syn#" kid), l)
+ else kopt
+ in
+ let add_typ_var env (KOpt_aux (KOpt_kind (k, kid), l) as kopt) =
try
let (l, _) = KBindings.find kid env.typ_vars in
rebindings := kid :: !rebindings;
- { env with typ_vars = KBindings.add (prepend_kid "syn#" kid) (l, BK_int) env.typ_vars }
+ { env with typ_vars = KBindings.add (prepend_kid "syn#" kid) (l, unaux_kind k) env.typ_vars }
with
| Not_found ->
- { env with typ_vars = KBindings.add kid (l, BK_int) env.typ_vars }
+ { env with typ_vars = KBindings.add kid (l, unaux_kind k) env.typ_vars }
in
- let env = List.fold_left add_typ_var env kids in
- let kids = List.map rename_kid kids in
- let nc = List.fold_left (fun nc kid -> nc_subst_nexp kid (Nexp_var (prepend_kid "syn#" kid)) nc) nc !rebindings in
- let typ = List.fold_left (fun typ kid -> typ_subst_nexp kid (Nexp_var (prepend_kid "syn#" kid)) typ) typ !rebindings in
- typ_debug (lazy ("Synonym existential: {" ^ string_of_list " " string_of_kid kids ^ ", " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ ^ "}"));
+ let env = List.fold_left add_typ_var env kopts in
+ let kopts = List.map rename_kopt kopts in
+ let nc = List.fold_left (fun nc kid -> constraint_subst kid (arg_nexp (nvar (prepend_kid "syn#" kid))) nc) nc !rebindings in
+ let typ = List.fold_left (fun typ kid -> typ_subst kid (arg_nexp (nvar (prepend_kid "syn#" kid))) typ) typ !rebindings in
let env = { env with constraints = nc :: env.constraints } in
- Typ_aux (Typ_exist (kids, nc, expand_synonyms env typ), l)
+ Typ_aux (Typ_exist (kopts, nc, expand_synonyms env typ), l)
| Typ_var v -> Typ_aux (Typ_var v, l)
- and expand_synonyms_arg env (Typ_arg_aux (typ_arg, l)) =
+ and expand_synonyms_arg env (A_aux (typ_arg, l)) =
match typ_arg with
- | Typ_arg_typ typ -> Typ_arg_aux (Typ_arg_typ (expand_synonyms env typ), l)
- | arg -> Typ_arg_aux (arg, l)
+ | A_typ typ -> A_aux (A_typ (expand_synonyms env typ), l)
+ | A_bool nc -> A_aux (A_bool (expand_constraint_synonyms env nc), l)
+ | arg -> A_aux (arg, l)
(** Map over all nexps in a type - excluding those in existential constraints **)
let rec map_nexps f (Typ_aux (typ_aux, l) as typ) =
@@ -693,62 +592,18 @@ end = struct
| Typ_tup typs -> Typ_aux (Typ_tup (List.map (map_nexps f) typs), l)
| Typ_exist (kids, nc, typ) -> Typ_aux (Typ_exist (kids, nc, map_nexps f typ), l)
| Typ_app (id, args) -> Typ_aux (Typ_app (id, List.map (map_nexps_arg f) args), l)
- and map_nexps_arg f (Typ_arg_aux (arg_aux, l) as arg) =
+ and map_nexps_arg f (A_aux (arg_aux, l) as arg) =
match arg_aux with
- | Typ_arg_order _ | Typ_arg_typ _ -> arg
- | Typ_arg_nexp n -> Typ_arg_aux (Typ_arg_nexp (f n), l)
-
- let canonical env typ =
- let typ = expand_synonyms env typ in
- let counter = ref 0 in
- let complex_nexps = ref KBindings.empty in
- let simplify_nexp (Nexp_aux (nexp_aux, l) as nexp) =
- match nexp_aux with
- | Nexp_constant _ -> nexp (* Check this ? *)
- | _ ->
- let kid = Kid_aux (Var ("'c#" ^ string_of_int !counter), l) in
- complex_nexps := KBindings.add kid nexp !complex_nexps;
- incr counter;
- Nexp_aux (Nexp_var kid, l)
- in
- let typ = map_nexps (fun nexp -> simplify_nexp (nexp_simp nexp)) typ in
- let existentials = KBindings.bindings !complex_nexps |> List.map fst in
- let constrs = List.fold_left (fun ncs (kid, nexp) -> nc_eq (nvar kid) nexp :: ncs) [] (KBindings.bindings !complex_nexps) in
- existentials, constrs, typ
-
- let is_canonical env typ =
- let typ = expand_synonyms env typ in
- let counter = ref 0 in
- let simplify_nexp (Nexp_aux (nexp_aux, l) as nexp) =
- match nexp_aux with
- | Nexp_constant _ -> nexp
- | _ -> (incr counter; nexp)
- in
- let typ = map_nexps simplify_nexp typ in
- not (!counter > 0)
+ | A_order _ | A_typ _ | A_bool _ -> arg
+ | A_nexp n -> A_aux (A_nexp (f n), l)
- let rec canonicalize env typ =
- match typ with
- | Typ_aux (Typ_fn (arg_typs, ret_typ, effects), l) when List.for_all (is_canonical env) arg_typs ->
- Typ_aux (Typ_fn (arg_typs, canonicalize env ret_typ, effects), l)
- | Typ_aux (Typ_fn _, l) -> typ_error l ("Function type " ^ string_of_typ typ ^ " is not canonical")
- | _ ->
- let existentials, constrs, (Typ_aux (typ_aux, l) as typ) = canonical env typ in
- if existentials = [] then
- typ
- else
- let typ_aux = match typ_aux with
- | Typ_tup _ | Typ_app _ -> Typ_exist (existentials, List.fold_left nc_and (List.hd constrs) (List.tl constrs), typ)
- | Typ_exist (kids, nc, typ) -> Typ_exist (kids @ existentials, List.fold_left nc_and nc constrs, typ)
- | Typ_fn _ | Typ_bidir _ | Typ_id _ | Typ_var _ -> assert false (* These must be simple *)
- | Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
- in
- Typ_aux (typ_aux, l)
+ let wf_debug str f x exs =
+ typ_debug ~level:2 (lazy ("wf_" ^ str ^ ": " ^ f x ^ " exs: " ^ Util.string_of_list ", " string_of_kid (KidSet.elements exs)))
(* Check if a type, order, n-expression or constraint is
well-formed. Throws a type error if the type is badly formed. *)
let rec wf_typ ?exs:(exs=KidSet.empty) env typ =
- typ_debug (lazy ("well-formed " ^ string_of_typ typ));
+ wf_debug "typ" string_of_typ typ exs;
let (Typ_aux (typ_aux, l)) = expand_synonyms env typ in
match typ_aux with
| Typ_id id when bound_typ_id env id ->
@@ -759,9 +614,9 @@ end = struct
| Typ_id id -> typ_error l ("Undefined type " ^ string_of_id id)
| Typ_var kid -> begin
match KBindings.find kid env.typ_vars with
- | (_, BK_type) -> ()
+ | (_, K_type) -> ()
| (_, k) -> typ_error l ("Kind identifier " ^ string_of_kid kid ^ " in type " ^ string_of_typ typ
- ^ " is " ^ string_of_base_kind_aux k ^ " rather than Type")
+ ^ " is " ^ string_of_kind_aux k ^ " rather than Type")
| exception Not_found ->
typ_error l ("Unbound kind identifier " ^ string_of_kid kid ^ " in type " ^ string_of_typ typ)
end
@@ -775,71 +630,75 @@ end = struct
check_args_typquant id env args (infer_kind env id)
| Typ_app (id, _) -> typ_error l ("Undefined type " ^ string_of_id id)
| Typ_exist ([], _, _) -> typ_error l ("Existential must have some type variables")
- | Typ_exist (kids, nc, typ) when KidSet.is_empty exs ->
- wf_constraint ~exs:(KidSet.of_list kids) env nc;
- wf_typ ~exs:(KidSet.of_list kids) { env with constraints = nc :: env.constraints } typ
+ | Typ_exist (kopts, nc, typ) when KidSet.is_empty exs ->
+ wf_constraint ~exs:(KidSet.of_list (List.map kopt_kid kopts)) env nc;
+ wf_typ ~exs:(KidSet.of_list (List.map kopt_kid kopts)) { env with constraints = nc :: env.constraints } typ
| Typ_exist (_, _, _) -> typ_error l ("Nested existentials are not allowed")
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
- and wf_typ_arg ?exs:(exs=KidSet.empty) env (Typ_arg_aux (typ_arg_aux, _)) =
+ and wf_typ_arg ?exs:(exs=KidSet.empty) env (A_aux (typ_arg_aux, _)) =
match typ_arg_aux with
- | Typ_arg_nexp nexp -> wf_nexp ~exs:exs env nexp
- | Typ_arg_typ typ -> wf_typ ~exs:exs env typ
- | Typ_arg_order ord -> wf_order env ord
+ | A_nexp nexp -> wf_nexp ~exs:exs env nexp
+ | A_typ typ -> wf_typ ~exs:exs env typ
+ | A_order ord -> wf_order env ord
+ | A_bool nc -> wf_constraint ~exs:exs env nc
and wf_nexp ?exs:(exs=KidSet.empty) env (Nexp_aux (nexp_aux, l) as nexp) =
- typ_debug (lazy ("well-formed nexp " ^ string_of_nexp nexp));
+ wf_debug "nexp" string_of_nexp nexp exs;
match nexp_aux with
| Nexp_id _ -> ()
| Nexp_var kid when KidSet.mem kid exs -> ()
| Nexp_var kid ->
begin
match get_typ_var kid env with
- | BK_int -> ()
+ | K_int -> ()
| kind -> typ_error l ("Constraint is badly formed, "
^ string_of_kid kid ^ " has kind "
- ^ string_of_base_kind_aux kind ^ " but should have kind Int")
+ ^ string_of_kind_aux kind ^ " but should have kind Int")
end
| Nexp_constant _ -> ()
| Nexp_app (id, nexps) ->
- let _ = get_smt_op id env in
List.iter (fun n -> wf_nexp ~exs:exs env n) nexps
| Nexp_times (nexp1, nexp2) -> wf_nexp ~exs:exs env nexp1; wf_nexp ~exs:exs env nexp2
| Nexp_sum (nexp1, nexp2) -> wf_nexp ~exs:exs env nexp1; wf_nexp ~exs:exs env nexp2
| Nexp_minus (nexp1, nexp2) -> wf_nexp ~exs:exs env nexp1; wf_nexp ~exs:exs env nexp2
| Nexp_exp nexp -> wf_nexp ~exs:exs env nexp (* MAYBE: Could put restrictions on what is allowed here *)
| Nexp_neg nexp -> wf_nexp ~exs:exs env nexp
- and wf_order env (Ord_aux (ord_aux, l)) =
+ and wf_order env (Ord_aux (ord_aux, l) as ord) =
match ord_aux with
| Ord_var kid ->
begin
match get_typ_var kid env with
- | BK_order -> ()
+ | K_order -> ()
| kind -> typ_error l ("Order is badly formed, "
^ string_of_kid kid ^ " has kind "
- ^ string_of_base_kind_aux kind ^ " but should have kind Order")
+ ^ string_of_kind_aux kind ^ " but should have kind Order")
end
| Ord_inc | Ord_dec -> ()
and wf_constraint ?exs:(exs=KidSet.empty) env (NC_aux (nc_aux, l) as nc) =
- typ_debug (lazy ("well-formed constraint " ^ string_of_n_constraint nc));
+ wf_debug "constraint" string_of_n_constraint nc exs;
match nc_aux with
| NC_equal (n1, n2) -> wf_nexp ~exs:exs env n1; wf_nexp ~exs:exs env n2
| NC_not_equal (n1, n2) -> wf_nexp ~exs:exs env n1; wf_nexp ~exs:exs env n2
| NC_bounded_ge (n1, n2) -> wf_nexp ~exs:exs env n1; wf_nexp ~exs:exs env n2
| NC_bounded_le (n1, n2) -> wf_nexp ~exs:exs env n1; wf_nexp ~exs:exs env n2
| NC_set (kid, _) when KidSet.mem kid exs -> ()
- | NC_set (kid, _) -> begin
- match get_typ_var kid env with
- | BK_int -> ()
- | kind -> typ_error l ("Set constraint is badly formed, "
- ^ string_of_kid kid ^ " has kind "
- ^ string_of_base_kind_aux kind ^ " but should have kind Int")
- end
+ | NC_set (kid, _) ->
+ begin match get_typ_var kid env with
+ | K_int -> ()
+ | kind -> typ_error l ("Set constraint is badly formed, "
+ ^ string_of_kid kid ^ " has kind "
+ ^ string_of_kind_aux kind ^ " but should have kind Int")
+ end
| NC_or (nc1, nc2) -> wf_constraint ~exs:exs env nc1; wf_constraint ~exs:exs env nc2
| NC_and (nc1, nc2) -> wf_constraint ~exs:exs env nc1; wf_constraint ~exs:exs env nc2
- | NC_app (id, nexps) ->
- if not (Bindings.mem id env.constraint_synonyms) then
- typ_error l ("Constraint synonym " ^ string_of_id id ^ " is not defined")
- else ();
- List.iter (wf_nexp ~exs:exs env) nexps
+ | NC_app (id, args) -> List.iter (wf_typ_arg ~exs:exs env) args
+ | NC_var kid when KidSet.mem kid exs -> ()
+ | NC_var kid ->
+ begin match get_typ_var kid env with
+ | K_bool -> ()
+ | kind -> typ_error l ("Set constraint is badly formed, "
+ ^ string_of_kid kid ^ " has kind "
+ ^ string_of_kind_aux kind ^ " but should have kind Bool")
+ end
| NC_true | NC_false -> ()
let counter = ref 0
@@ -852,7 +711,7 @@ end = struct
let freshen_kid env kid (typq, typ) =
let fresh = fresh_kid ~kid:kid env in
if KidSet.mem kid (KidSet.of_list (List.map kopt_kid (quant_kopts typq))) then
- (typquant_subst_kid kid fresh typq, typ_subst_kid kid fresh typ)
+ (typquant_subst_kid kid fresh typq, subst_kid typ_subst kid fresh typ)
else
(typq, typ)
@@ -868,28 +727,59 @@ end = struct
let get_val_spec id env =
try
let bind = Bindings.find id env.top_val_specs in
- typ_debug (lazy ("get_val_spec: Env has " ^ string_of_list ", " (fun (kid, (_, bk)) -> string_of_kid kid ^ " => " ^ string_of_base_kind_aux bk) (KBindings.bindings env.typ_vars)));
+ typ_debug (lazy ("get_val_spec: Env has " ^ string_of_list ", " (fun (kid, (_, k)) -> string_of_kid kid ^ " => " ^ string_of_kind_aux k) (KBindings.bindings env.typ_vars)));
let bind' = List.fold_left (fun bind (kid, _) -> freshen_kid env kid bind) bind (KBindings.bindings env.typ_vars) in
typ_debug (lazy ("get_val_spec: freshened to " ^ string_of_bind bind'));
bind'
with
| Not_found -> typ_error (id_loc id) ("No val spec found for " ^ string_of_id id)
+ let add_union_id id bind env =
+ typ_print (lazy (adding ^ "union identifier " ^ string_of_id id ^ " : " ^ string_of_bind bind));
+ { env with union_ids = Bindings.add id bind env.union_ids }
+
+ let get_union_id id env =
+ try
+ let bind = Bindings.find id env.union_ids in
+ List.fold_left (fun bind (kid, _) -> freshen_kid env kid bind) bind (KBindings.bindings env.typ_vars)
+ with
+ | Not_found -> typ_error (id_loc id) ("No union constructor found for " ^ string_of_id id)
+
let rec update_val_spec id (typq, typ) env =
- begin
- let typ = expand_synonyms env typ in
- let typq = expand_typquant_synonyms env typq in
- typ_print (lazy (adding ^ "val spec " ^ string_of_id id ^ " : " ^ string_of_bind (typq, typ)));
- let env = match typ with
- | Typ_aux (Typ_bidir (typ1, typ2), _) -> add_mapping id (typq, typ1, typ2) env
- | _ -> env
- in
- { env with top_val_specs = Bindings.add id (typq, typ) env.top_val_specs }
+ begin match expand_synonyms env typ with
+ | Typ_aux (Typ_fn (arg_typs, ret_typ, effect), l) ->
+ (* We perform some canonicalisation for function types where existentials appear on the left, so
+ ({'n, 'n >= 2, int('n)}, foo) -> bar
+ would become
+ forall 'n, 'n >= 2. (int('n), foo) -> bar
+ this enforces the invariant that all things on the left of functions are 'base types' (i.e. without existentials)
+ *)
+ let base_args = List.map (fun typ -> destruct_exist (expand_synonyms env typ)) arg_typs in
+ let existential_arg typq = function
+ | None -> typq
+ | Some (exs, nc, _) ->
+ List.fold_left (fun typq kopt -> quant_add (mk_qi_kopt kopt) typq) (quant_add (mk_qi_nc nc) typq) exs
+ in
+ let typq = List.fold_left existential_arg typq base_args in
+ let arg_typs = List.map2 (fun typ -> function Some (_, _, typ) -> typ | None -> typ) arg_typs base_args in
+ let typ = Typ_aux (Typ_fn (arg_typs, ret_typ, effect), l) in
+ typ_print (lazy (adding ^ "val " ^ string_of_id id ^ " : " ^ string_of_bind (typq, typ)));
+ { env with top_val_specs = Bindings.add id (typq, typ) env.top_val_specs }
+
+ | Typ_aux (Typ_bidir (typ1, typ2), l) ->
+ let env = add_mapping id (typq, typ1, typ2) env in
+ typ_print (lazy (adding ^ "mapping " ^ string_of_id id ^ " : " ^ string_of_bind (typq, typ)));
+ { env with top_val_specs = Bindings.add id (typq, typ) env.top_val_specs }
+
+ | _ -> typ_error (id_loc id) "val definition must have a mapping or function type"
end
+
and add_val_spec id (bind_typq, bind_typ) env =
if not (Bindings.mem id env.top_val_specs)
then update_val_spec id (bind_typq, bind_typ) env
else
+ env
+ (*
let (existing_typq, existing_typ) = Bindings.find id env.top_val_specs in
let existing_cmp = (strip_typq existing_typq, strip_typ existing_typ) in
let bind_cmp = (strip_typq bind_typq, strip_typ bind_typ) in
@@ -897,35 +787,34 @@ end = struct
typ_error (id_loc id) ("Identifier " ^ string_of_id id ^ " is already bound as " ^ string_of_bind (existing_typq, existing_typ) ^ ", cannot rebind as " ^ string_of_bind (bind_typq, bind_typ))
else
env
+ *)
+
and add_mapping id (typq, typ1, typ2) env =
- begin
- typ_print (lazy (adding ^ "mapping " ^ string_of_id id));
- let forwards_id = mk_id (string_of_id id ^ "_forwards") in
- let forwards_matches_id = mk_id (string_of_id id ^ "_forwards_matches") in
- let backwards_id = mk_id (string_of_id id ^ "_backwards") in
- let backwards_matches_id = mk_id (string_of_id id ^ "_backwards_matches") in
- let forwards_typ = Typ_aux (Typ_fn ([typ1], typ2, no_effect), Parse_ast.Unknown) in
- let forwards_matches_typ = Typ_aux (Typ_fn ([typ1], bool_typ, no_effect), Parse_ast.Unknown) in
- let backwards_typ = Typ_aux (Typ_fn ([typ2], typ1, no_effect), Parse_ast.Unknown) in
- let backwards_matches_typ = Typ_aux (Typ_fn ([typ2], bool_typ, no_effect), Parse_ast.Unknown) in
- let env =
- { env with mappings = Bindings.add id (typq, typ1, typ2) env.mappings }
- |> add_val_spec forwards_id (typq, forwards_typ)
- |> add_val_spec backwards_id (typq, backwards_typ)
- |> add_val_spec forwards_matches_id (typq, forwards_matches_typ)
- |> add_val_spec backwards_matches_id (typq, backwards_matches_typ)
- in
- let prefix_id = mk_id (string_of_id id ^ "_matches_prefix") in
- begin if strip_typ typ1 = string_typ then
- let forwards_prefix_typ = Typ_aux (Typ_fn ([typ1], app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (tuple_typ [typ2; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
- add_val_spec prefix_id (typq, forwards_prefix_typ) env
- else if strip_typ typ2 = string_typ then
- let backwards_prefix_typ = Typ_aux (Typ_fn ([typ2], app_typ (mk_id "option") [Typ_arg_aux (Typ_arg_typ (tuple_typ [typ1; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
- add_val_spec prefix_id (typq, backwards_prefix_typ) env
- else
- env
- end
- end
+ typ_print (lazy (adding ^ "mapping " ^ string_of_id id));
+ let forwards_id = mk_id (string_of_id id ^ "_forwards") in
+ let forwards_matches_id = mk_id (string_of_id id ^ "_forwards_matches") in
+ let backwards_id = mk_id (string_of_id id ^ "_backwards") in
+ let backwards_matches_id = mk_id (string_of_id id ^ "_backwards_matches") in
+ let forwards_typ = Typ_aux (Typ_fn ([typ1], typ2, no_effect), Parse_ast.Unknown) in
+ let forwards_matches_typ = Typ_aux (Typ_fn ([typ1], bool_typ, no_effect), Parse_ast.Unknown) in
+ let backwards_typ = Typ_aux (Typ_fn ([typ2], typ1, no_effect), Parse_ast.Unknown) in
+ let backwards_matches_typ = Typ_aux (Typ_fn ([typ2], bool_typ, no_effect), Parse_ast.Unknown) in
+ let env =
+ { env with mappings = Bindings.add id (typq, typ1, typ2) env.mappings }
+ |> add_val_spec forwards_id (typq, forwards_typ)
+ |> add_val_spec backwards_id (typq, backwards_typ)
+ |> add_val_spec forwards_matches_id (typq, forwards_matches_typ)
+ |> add_val_spec backwards_matches_id (typq, backwards_matches_typ)
+ in
+ let prefix_id = mk_id (string_of_id id ^ "_matches_prefix") in
+ if strip_typ typ1 = string_typ then
+ let forwards_prefix_typ = Typ_aux (Typ_fn ([typ1], app_typ (mk_id "option") [A_aux (A_typ (tuple_typ [typ2; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
+ add_val_spec prefix_id (typq, forwards_prefix_typ) env
+ else if strip_typ typ2 = string_typ then
+ let backwards_prefix_typ = Typ_aux (Typ_fn ([typ2], app_typ (mk_id "option") [A_aux (A_typ (tuple_typ [typ1; nat_typ]), Parse_ast.Unknown)], no_effect), Parse_ast.Unknown) in
+ add_val_spec prefix_id (typq, backwards_prefix_typ) env
+ else
+ env
let define_val_spec id env =
if IdSet.mem id env.defined_val_specs
@@ -979,11 +868,11 @@ end = struct
let rec record_typ_args = function
| [] -> []
| ((QI_aux (QI_id kopt, _)) :: qis) when is_nat_kopt kopt ->
- mk_typ_arg (Typ_arg_nexp (nvar (kopt_kid kopt))) :: record_typ_args qis
+ mk_typ_arg (A_nexp (nvar (kopt_kid kopt))) :: record_typ_args qis
| ((QI_aux (QI_id kopt, _)) :: qis) when is_typ_kopt kopt ->
- mk_typ_arg (Typ_arg_typ (mk_typ (Typ_var (kopt_kid kopt)))) :: record_typ_args qis
+ mk_typ_arg (A_typ (mk_typ (Typ_var (kopt_kid kopt)))) :: record_typ_args qis
| ((QI_aux (QI_id kopt, _)) :: qis) when is_order_kopt kopt ->
- mk_typ_arg (Typ_arg_order (mk_ord (Ord_var (kopt_kid kopt)))) :: record_typ_args qis
+ mk_typ_arg (A_order (mk_ord (Ord_var (kopt_kid kopt)))) :: record_typ_args qis
| (_ :: qis) -> record_typ_args qis
in
let rectyp = match record_typ_args (quant_items typq) with
@@ -1037,16 +926,22 @@ end = struct
end
let add_variant id variant env =
- begin
- typ_print (lazy (adding ^ "variant " ^ string_of_id id));
- { env with variants = Bindings.add id variant env.variants }
- end
+ typ_print (lazy (adding ^ "variant " ^ string_of_id id));
+ { env with variants = Bindings.add id variant env.variants }
- let add_union_id id bind env =
- begin
- typ_print (lazy (adding ^ "union identifier " ^ string_of_id id ^ " : " ^ string_of_bind bind));
- { env with union_ids = Bindings.add id bind env.union_ids }
- end
+ let add_scattered_variant id typq env =
+ typ_print (lazy (adding ^ "scattered variant " ^ string_of_id id));
+ { env with variants = Bindings.add id (typq, []) env.variants }
+
+ let add_variant_clause id tu env =
+ match Bindings.find_opt id env.variants with
+ | Some (typq, tus) -> { env with variants = Bindings.add id (typq, tus @ [tu]) env.variants }
+ | None -> typ_error (id_loc id) ("scattered union " ^ string_of_id id ^ " not found")
+
+ let get_variant id env =
+ match Bindings.find_opt id env.variants with
+ | Some (typq, tus) -> typq, tus
+ | None -> typ_error (id_loc id) ("union " ^ string_of_id id ^ " not found")
let is_register id env =
Bindings.mem id env.registers
@@ -1102,12 +997,12 @@ end = struct
with
| Not_found -> Unbound
- let add_typ_var l kid k env =
+ let add_typ_var l (KOpt_aux (KOpt_kind (K_aux (k, _), kid), _) as kopt) env =
if KBindings.mem kid env.typ_vars
- then typ_error (kid_loc kid) ("type variable " ^ string_of_kid kid ^ " is already bound")
+ then typ_error (kid_loc kid) ("type variable " ^ string_of_kinded_id kopt ^ " is already bound")
else
begin
- typ_print (lazy (adding ^ "type variable " ^ string_of_kid kid ^ " : " ^ string_of_base_kind_aux k));
+ typ_print (lazy (adding ^ "type variable " ^ string_of_kid kid ^ " : " ^ string_of_kind_aux k));
{ env with typ_vars = KBindings.add kid (l, k) env.typ_vars }
end
@@ -1126,12 +1021,12 @@ end = struct
let get_constraints env = env.constraints
- let add_constraint (NC_aux (nc_aux, l) as constr) env =
+ let add_constraint constr env =
wf_constraint env constr;
+ let (NC_aux (nc_aux, l) as constr) = expand_constraint_synonyms env constr in
match nc_aux with
| NC_true -> env
| _ ->
- let constr = expand_constraint_synonyms env constr in
typ_print (lazy (adding ^ "constraint " ^ string_of_n_constraint constr));
{ env with constraints = constr :: env.constraints }
@@ -1161,16 +1056,6 @@ end = struct
let get_typ_synonym id env = Bindings.find id env.typ_synonyms
- let add_constraint_synonym id kids nc env =
- if Bindings.mem id env.constraint_synonyms
- then typ_error (id_loc id) ("Constraint synonym " ^ string_of_id id ^ " already exists")
- else
- begin
- typ_print (lazy (adding ^ "constraint synonym " ^ string_of_id id));
- wf_constraint ~exs:(KidSet.of_list kids) env nc;
- { env with constraint_synonyms = Bindings.add id (kids, nc) env.constraint_synonyms }
- end
-
let get_default_order env =
match env.default_order with
| None -> typ_error Parse_ast.Unknown ("No default order has been set")
@@ -1192,15 +1077,15 @@ end = struct
rewrap (Typ_fn (List.map aux arg_typs, aux ret_typ, eff))
| Typ_tup ts ->
rewrap (Typ_tup (List.map aux ts))
- | Typ_app (r, [Typ_arg_aux (Typ_arg_typ rtyp,_)]) when string_of_id r = "register" ->
+ | Typ_app (r, [A_aux (A_typ rtyp,_)]) when string_of_id r = "register" ->
aux rtyp
| Typ_app (id, targs) ->
rewrap (Typ_app (id, List.map aux_arg targs))
| t -> rewrap t
- and aux_arg (Typ_arg_aux (targ,a)) =
- let rewrap targ = Typ_arg_aux (targ,a) in
+ and aux_arg (A_aux (targ,a)) =
+ let rewrap targ = A_aux (targ,a) in
match targ with
- | Typ_arg_typ typ -> rewrap (Typ_arg_typ (aux typ))
+ | A_typ typ -> rewrap (A_typ (aux typ))
| targ -> rewrap targ in
aux (expand_synonyms env typ)
@@ -1221,17 +1106,14 @@ let add_typquant l (quant : typquant) (env : Env.t) : Env.t =
| QI_aux (qi, _) -> add_quant_item_aux env qi
and add_quant_item_aux env = function
| QI_const constr -> Env.add_constraint constr env
- | QI_id (KOpt_aux (KOpt_none kid, _)) -> Env.add_typ_var l kid BK_int env
- | QI_id (KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (k, _)], _), kid), _)) -> Env.add_typ_var l kid k env
- | QI_id (KOpt_aux (_, l)) -> typ_error l "Type variable had non base kinds!"
+ | QI_id kopt -> Env.add_typ_var l kopt env
in
match quant with
| TypQ_aux (TypQ_no_forall, _) -> env
| TypQ_aux (TypQ_tq quants, _) -> List.fold_left add_quant_item env quants
let expand_bind_synonyms l env (typq, typ) =
- Env.expand_typquant_synonyms env typq, Env.expand_synonyms (add_typquant l typq env) typ
-
+ typq, Env.expand_synonyms (add_typquant l typq env) typ
(* Create vectors with the default order from the environment *)
@@ -1240,92 +1122,49 @@ let default_order_error_string =
let dvector_typ env n typ = vector_typ n (Env.get_default_order env) typ
-let ex_counter = ref 0
-
-let fresh_existential ?name:(n="") () =
- let fresh = Kid_aux (Var ("'ex" ^ string_of_int !ex_counter ^ "#" ^ n), Parse_ast.Unknown) in
- incr ex_counter; fresh
-
-let destruct_exist env typ =
- match Env.expand_synonyms env typ with
- | Typ_aux (Typ_exist (kids, nc, typ), _) ->
- let fresh_kids = List.map (fun kid -> (kid, fresh_existential ~name:(string_of_id (id_of_kid kid)) ())) kids in
- let nc = List.fold_left (fun nc (kid, fresh) -> nc_subst_nexp kid (Nexp_var fresh) nc) nc fresh_kids in
- let typ = List.fold_left (fun typ (kid, fresh) -> typ_subst_nexp kid (Nexp_var fresh) typ) typ fresh_kids in
- Some (List.map snd fresh_kids, nc, typ)
- | _ -> None
-
-let add_existential l kids nc env =
- let env = List.fold_left (fun env kid -> Env.add_typ_var l kid BK_int env) env kids in
+let add_existential l kopts nc env =
+ let env = List.fold_left (fun env kopt -> Env.add_typ_var l kopt env) env kopts in
Env.add_constraint nc env
-let add_typ_vars l kids env = List.fold_left (fun env kid -> Env.add_typ_var l kid BK_int env) env kids
+let add_typ_vars l kopts env = List.fold_left (fun env kopt -> Env.add_typ_var l kopt env) env kopts
let is_exist = function
| Typ_aux (Typ_exist (_, _, _), _) -> true
| _ -> false
let exist_typ constr typ =
- let fresh_kid = fresh_existential () in
- mk_typ (Typ_exist ([fresh_kid], constr fresh_kid, typ fresh_kid))
-
-(** Destructure and canonicalise a numeric type into a list of type
- variables, a constraint on those type variables, and an
- N-expression that represents that numeric type in the
- environment. For example:
- - {'n, 'n <= 10. atom('n)} => ['n], 'n <= 10, 'n
- - int => ['n], true, 'n (where x is fresh)
- - atom('n) => [], true, 'n
-**)
-let destruct_numeric env typ =
- let typ = Env.expand_synonyms env typ in
- match destruct_exist env typ, typ with
- | Some (kids, nc, Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp nexp, _)]), _)), _ when string_of_id id = "atom" ->
- Some (kids, nc, nexp)
- | None, Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp nexp, _)]), _) when string_of_id id = "atom" ->
- Some ([], nc_true, nexp)
- | None, Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp lo, _); Typ_arg_aux (Typ_arg_nexp hi, _)]), _) when string_of_id id = "range" ->
- let kid = fresh_existential () in
- Some ([kid], nc_and (nc_lteq lo (nvar kid)) (nc_lteq (nvar kid) hi), nvar kid)
- | None, Typ_aux (Typ_id id, _) when string_of_id id = "nat" ->
- let kid = fresh_existential () in
- Some ([kid], nc_lteq (nint 0) (nvar kid), nvar kid)
- | None, Typ_aux (Typ_id id, _) when string_of_id id = "int" ->
- let kid = fresh_existential () in
- Some ([kid], nc_true, nvar kid)
- | _, _ -> None
+ let fresh = fresh_existential K_int in
+ mk_typ (Typ_exist ([fresh], constr (kopt_kid fresh), typ (kopt_kid fresh)))
let bind_numeric l typ env =
- match destruct_numeric env typ with
+ match destruct_numeric (Env.expand_synonyms env typ) with
| Some (kids, nc, nexp) ->
- nexp, add_existential l kids nc env
+ nexp, add_existential l (List.map (mk_kopt K_int) kids) nc env
| None -> typ_error l ("Expected " ^ string_of_typ typ ^ " to be numeric")
(** Pull an (potentially)-existentially qualified type into the global
typing environment **)
let bind_existential l typ env =
- match destruct_numeric env typ with
- | Some (kids, nc, nexp) -> atom_typ nexp, add_existential l kids nc env
- | None -> match destruct_exist env typ with
- | Some (kids, nc, typ) -> typ, add_existential l kids nc env
- | None -> typ, env
+ match destruct_exist (Env.expand_synonyms env typ) with
+ | Some (kids, nc, typ) -> typ, add_existential l kids nc env
+ | None -> typ, env
let destruct_range env typ =
- let kids, constr, (Typ_aux (typ_aux, _)) =
- Util.option_default ([], nc_true, typ) (destruct_exist env typ)
+ let kopts, constr, (Typ_aux (typ_aux, _)) =
+ Util.option_default ([], nc_true, typ) (destruct_exist (Env.expand_synonyms env typ))
in
match typ_aux with
- | Typ_app (f, [Typ_arg_aux (Typ_arg_nexp n, _)])
- when string_of_id f = "atom" -> Some (kids, constr, n, n)
- | Typ_app (f, [Typ_arg_aux (Typ_arg_nexp n1, _); Typ_arg_aux (Typ_arg_nexp n2, _)])
- when string_of_id f = "range" -> Some (kids, constr, n1, n2)
+ | Typ_app (f, [A_aux (A_nexp n, _)])
+ when string_of_id f = "atom" -> Some (List.map kopt_kid kopts, constr, n, n)
+ | Typ_app (f, [A_aux (A_nexp n1, _); A_aux (A_nexp n2, _)])
+ when string_of_id f = "range" -> Some (List.map kopt_kid kopts, constr, n1, n2)
| _ -> None
let destruct_vector env typ =
let destruct_vector' = function
- | Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp n1, _);
- Typ_arg_aux (Typ_arg_order o, _);
- Typ_arg_aux (Typ_arg_typ vtyp, _)]
+ | Typ_aux (Typ_app (id, [A_aux (A_nexp n1, _);
+ A_aux (A_order o, _);
+ A_aux (A_typ vtyp, _)]
), _) when string_of_id id = "vector" -> Some (nexp_simp n1, o, vtyp)
| typ -> None
in
@@ -1340,15 +1179,15 @@ let rec is_typ_monomorphic (Typ_aux (typ, l)) =
| Typ_bidir (typ1, typ2) -> is_typ_monomorphic typ1 && is_typ_monomorphic typ2
| Typ_exist _ | Typ_var _ -> false
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and is_typ_arg_monomorphic (Typ_arg_aux (arg, _)) =
+and is_typ_arg_monomorphic (A_aux (arg, _)) =
match arg with
- | Typ_arg_nexp _ -> true
- | Typ_arg_typ typ -> is_typ_monomorphic typ
- | Typ_arg_order (Ord_aux (Ord_dec, _)) | Typ_arg_order (Ord_aux (Ord_inc, _)) -> true
- | Typ_arg_order (Ord_aux (Ord_var _, _)) -> false
+ | A_nexp _ -> true
+ | A_typ typ -> is_typ_monomorphic typ
+ | A_order (Ord_aux (Ord_dec, _)) | A_order (Ord_aux (Ord_inc, _)) -> true
+ | A_order (Ord_aux (Ord_var _, _)) -> false
(**************************************************************************)
-(* 3. Subtyping and constraint solving *)
+(* 2. Subtyping and constraint solving *)
(**************************************************************************)
let rec simp_typ (Typ_aux (typ_aux, l)) = Typ_aux (simp_typ_aux typ_aux, l)
@@ -1378,86 +1217,31 @@ this is equivalent to
which is then a problem we can feed to the constraint solver expecting unsat.
*)
-let rec nexp_constraint env var_of (Nexp_aux (nexp, l)) =
- match nexp with
- | Nexp_id v -> nexp_constraint env var_of (Env.get_num_def v env)
- | Nexp_var kid -> Constraint.variable (var_of kid)
- | Nexp_constant c -> Constraint.constant c
- | Nexp_times (nexp1, nexp2) -> Constraint.mult (nexp_constraint env var_of nexp1) (nexp_constraint env var_of nexp2)
- | Nexp_sum (nexp1, nexp2) -> Constraint.add (nexp_constraint env var_of nexp1) (nexp_constraint env var_of nexp2)
- | Nexp_minus (nexp1, nexp2) -> Constraint.sub (nexp_constraint env var_of nexp1) (nexp_constraint env var_of nexp2)
- | Nexp_exp nexp -> Constraint.pow2 (nexp_constraint env var_of nexp)
- | Nexp_neg nexp -> Constraint.sub (Constraint.constant (Big_int.of_int 0)) (nexp_constraint env var_of nexp)
- | Nexp_app (id, nexps) -> Constraint.app (Env.get_smt_op id env) (List.map (nexp_constraint env var_of) nexps)
-
-let rec nc_constraint env var_of (NC_aux (nc, l)) =
- match nc with
- | NC_equal (nexp1, nexp2) -> Constraint.eq (nexp_constraint env var_of nexp1) (nexp_constraint env var_of nexp2)
- | NC_not_equal (nexp1, nexp2) -> Constraint.neq (nexp_constraint env var_of nexp1) (nexp_constraint env var_of nexp2)
- | NC_bounded_ge (nexp1, nexp2) -> Constraint.gteq (nexp_constraint env var_of nexp1) (nexp_constraint env var_of nexp2)
- | NC_bounded_le (nexp1, nexp2) -> Constraint.lteq (nexp_constraint env var_of nexp1) (nexp_constraint env var_of nexp2)
- | NC_set (_, []) -> Constraint.literal false
- | NC_set (kid, (int :: ints)) ->
- List.fold_left Constraint.disj
- (Constraint.eq (nexp_constraint env var_of (nvar kid)) (Constraint.constant int))
- (List.map (fun i -> Constraint.eq (nexp_constraint env var_of (nvar kid)) (Constraint.constant i)) ints)
- | NC_or (nc1, nc2) -> Constraint.disj (nc_constraint env var_of nc1) (nc_constraint env var_of nc2)
- | NC_and (nc1, nc2) -> Constraint.conj (nc_constraint env var_of nc1) (nc_constraint env var_of nc2)
- | NC_app (id, nexps) -> raise (Reporting_basic.err_unreachable l __POS__ "constraint synonym reached smt generation")
- | NC_false -> Constraint.literal false
- | NC_true -> Constraint.literal true
-
-let rec nc_constraints env var_of ncs =
- match ncs with
- | [] -> Constraint.literal true
- | [nc] -> nc_constraint env var_of nc
- | (nc :: ncs) ->
- Constraint.conj (nc_constraint env var_of nc) (nc_constraints env var_of ncs)
-
-let prove_z3' env constr =
- let module Bindings = Map.Make(Kid) in
- let bindings = ref Bindings.empty in
- let fresh_var kid =
- let n = Bindings.cardinal !bindings in
- bindings := Bindings.add kid n !bindings;
- n
- in
- let var_of kid =
- try Bindings.find kid !bindings with
- | Not_found -> fresh_var kid
- in
- let constr = Constraint.conj (nc_constraints env var_of (Env.get_constraints env)) (constr var_of) in
- match Constraint.call_z3 constr with
+let prove_z3 env (NC_aux (_, l) as nc) =
+ let vars = Env.get_typ_vars env in
+ let vars = KBindings.filter (fun _ k -> match k with K_int | K_bool -> true | _ -> false) vars in
+ let ncs = Env.get_constraints env in
+ match Constraint.call_z3 l vars (List.fold_left nc_and (nc_not nc) ncs) with
| Constraint.Unsat -> typ_debug (lazy "unsat"); true
| Constraint.Sat -> typ_debug (lazy "sat"); false
| Constraint.Unknown -> typ_debug (lazy "unknown"); false
-let prove_z3 env nc =
- typ_print (lazy (Util.("Prove " |> red |> clear) ^ string_of_list ", " string_of_n_constraint (Env.get_constraints env) ^ " |- " ^ string_of_n_constraint nc));
- prove_z3' env (fun var_of -> Constraint.negate (nc_constraint env var_of nc))
-
-let solve env nexp =
- typ_print (lazy ("Solve " ^ string_of_list ", " string_of_n_constraint (Env.get_constraints env) ^ " |- " ^ string_of_nexp nexp ^ " = ?"));
+let solve env (Nexp_aux (_, l) as nexp) =
+ typ_print (lazy (Util.("Solve " |> red |> clear) ^ string_of_list ", " string_of_n_constraint (Env.get_constraints env)
+ ^ " |- " ^ string_of_nexp nexp ^ " = ?"));
match nexp with
| Nexp_aux (Nexp_constant n,_) -> Some n
| _ ->
- let bindings = ref KBindings.empty in
- let fresh_var kid =
- let n = KBindings.cardinal !bindings in
- bindings := KBindings.add kid n !bindings;
- n
- in
- let var_of kid =
- try KBindings.find kid !bindings with
- | Not_found -> fresh_var kid
- in
- let env = Env.add_typ_var Parse_ast.Unknown (mk_kid "solve#") BK_int env in
- let constr = Constraint.conj (nc_constraints env var_of (Env.get_constraints env))
- (nc_constraint env var_of (nc_eq (nvar (mk_kid "solve#")) nexp))
- in
- Constraint.solve_z3 constr (var_of (mk_kid "solve#"))
+ let env = Env.add_typ_var Parse_ast.Unknown (mk_kopt K_int (mk_kid "solve#")) env in
+ let vars = Env.get_typ_vars env in
+ let vars = KBindings.filter (fun _ k -> match k with K_int | K_bool -> true | _ -> false) vars in
+ let constr = List.fold_left nc_and (nc_eq (nvar (mk_kid "solve#")) nexp) (Env.get_constraints env) in
+ Constraint.solve_z3 l vars constr (mk_kid "solve#")
-let prove env (NC_aux (nc_aux, _) as nc) =
+let prove env nc =
+ typ_print (lazy (Util.("Prove " |> red |> clear) ^ string_of_list ", " string_of_n_constraint (Env.get_constraints env) ^ " |- " ^ string_of_n_constraint nc));
+ let (NC_aux (nc_aux, _) as nc) = Env.expand_constraint_synonyms env nc in
+ typ_debug ~level:2 (lazy (Util.("Prove " |> red |> clear) ^ string_of_list ", " string_of_n_constraint (Env.get_constraints env) ^ " |- " ^ string_of_n_constraint nc));
let compare_const f (Nexp_aux (n1, _)) (Nexp_aux (n2, _)) =
match n1, n2 with
| Nexp_constant c1, Nexp_constant c2 when f c1 c2 -> true
@@ -1471,7 +1255,7 @@ let prove env (NC_aux (nc_aux, _) as nc) =
| _ -> prove_z3 env nc
(**************************************************************************)
-(* 4. Unification *)
+(* 3. Unification *)
(**************************************************************************)
let rec nexp_frees ?exs:(exs=KidSet.empty) (Nexp_aux (nexp, l)) =
@@ -1503,11 +1287,11 @@ let rec typ_nexps (Typ_aux (typ_aux, l)) =
List.concat (List.map typ_nexps arg_typs) @ typ_nexps ret_typ
| Typ_bidir (typ1, typ2) ->
typ_nexps typ1 @ typ_nexps typ2
-and typ_arg_nexps (Typ_arg_aux (typ_arg_aux, l)) =
+and typ_arg_nexps (A_aux (typ_arg_aux, l)) =
match typ_arg_aux with
- | Typ_arg_nexp n -> [n]
- | Typ_arg_typ typ -> typ_nexps typ
- | Typ_arg_order ord -> []
+ | A_nexp n -> [n]
+ | A_typ typ -> typ_nexps typ
+ | A_order ord -> []
let rec typ_frees ?exs:(exs=KidSet.empty) (Typ_aux (typ_aux, l)) =
match typ_aux with
@@ -1517,14 +1301,15 @@ let rec typ_frees ?exs:(exs=KidSet.empty) (Typ_aux (typ_aux, l)) =
| Typ_var kid -> KidSet.singleton kid
| Typ_tup typs -> List.fold_left KidSet.union KidSet.empty (List.map (typ_frees ~exs:exs) typs)
| Typ_app (f, args) -> List.fold_left KidSet.union KidSet.empty (List.map (typ_arg_frees ~exs:exs) args)
- | Typ_exist (kids, nc, typ) -> typ_frees ~exs:(KidSet.of_list kids) typ
+ | Typ_exist (kopts, nc, typ) -> typ_frees ~exs:(KidSet.of_list (List.map kopt_kid kopts)) typ
| Typ_fn (arg_typs, ret_typ, _) -> List.fold_left KidSet.union (typ_frees ~exs:exs ret_typ) (List.map (typ_frees ~exs:exs) arg_typs)
| Typ_bidir (typ1, typ2) -> KidSet.union (typ_frees ~exs:exs typ1) (typ_frees ~exs:exs typ2)
-and typ_arg_frees ?exs:(exs=KidSet.empty) (Typ_arg_aux (typ_arg_aux, l)) =
+and typ_arg_frees ?exs:(exs=KidSet.empty) (A_aux (typ_arg_aux, l)) =
match typ_arg_aux with
- | Typ_arg_nexp n -> nexp_frees ~exs:exs n
- | Typ_arg_typ typ -> typ_frees ~exs:exs typ
- | Typ_arg_order ord -> order_frees ord
+ | A_nexp n -> nexp_frees ~exs:exs n
+ | A_typ typ -> typ_frees ~exs:exs typ
+ | A_order ord -> order_frees ord
+ | A_bool nc -> tyvars_of_constraint nc
let rec nexp_identical (Nexp_aux (nexp1, _)) (Nexp_aux (nexp2, _)) =
match nexp1, nexp2 with
@@ -1559,6 +1344,7 @@ let rec nc_identical (NC_aux (nc1, _)) (NC_aux (nc2, _)) =
| NC_false, NC_false -> true
| NC_set (kid1, ints1), NC_set (kid2, ints2) when List.length ints1 = List.length ints2 ->
Kid.compare kid1 kid2 = 0 && List.for_all2 (fun i1 i2 -> i1 = i2) ints1 ints2
+ | NC_var kid1, NC_var kid2 -> Kid.compare kid1 kid2 = 0
| _, _ -> false
let typ_identical env typ1 typ2 =
@@ -1584,97 +1370,139 @@ let typ_identical env typ1 typ2 =
try Id.compare f1 f2 = 0 && List.for_all2 typ_arg_identical args1 args2 with
| Invalid_argument _ -> false
end
- | Typ_exist (kids1, nc1, typ1), Typ_exist (kids2, nc2, typ2) when List.length kids1 = List.length kids2 ->
- List.for_all2 (fun k1 k2 -> Kid.compare k1 k2 = 0) kids1 kids2 && nc_identical nc1 nc2 && typ_identical' typ1 typ2
+ | Typ_exist (kopts1, nc1, typ1), Typ_exist (kopts2, nc2, typ2) when List.length kopts1 = List.length kopts2 ->
+ List.for_all2 (fun k1 k2 -> KOpt.compare k1 k2 = 0) kopts1 kopts2 && nc_identical nc1 nc2 && typ_identical' typ1 typ2
| _, _ -> false
- and typ_arg_identical (Typ_arg_aux (arg1, _)) (Typ_arg_aux (arg2, _)) =
+ and typ_arg_identical (A_aux (arg1, _)) (A_aux (arg2, _)) =
match arg1, arg2 with
- | Typ_arg_nexp n1, Typ_arg_nexp n2 -> nexp_identical n1 n2
- | Typ_arg_typ typ1, Typ_arg_typ typ2 -> typ_identical' typ1 typ2
- | Typ_arg_order ord1, Typ_arg_order ord2 -> ord_identical ord1 ord2
+ | A_nexp n1, A_nexp n2 -> nexp_identical n1 n2
+ | A_typ typ1, A_typ typ2 -> typ_identical' typ1 typ2
+ | A_order ord1, A_order ord2 -> ord_identical ord1 ord2
| _, _ -> false
in
typ_identical' (Env.expand_synonyms env typ1) (Env.expand_synonyms env typ2)
-type uvar =
- | U_nexp of nexp
- | U_order of order
- | U_typ of typ
+exception Unification_error of l * string;;
+
+let unify_error l str = raise (Unification_error (l, str))
-let uvar_subst_nexp sv subst = function
- | U_nexp nexp -> U_nexp (nexp_subst sv subst nexp)
- | U_typ typ -> U_typ (typ_subst_nexp sv subst typ)
- | U_order ord -> U_order ord
+let merge_unifiers l kid uvar1 uvar2 =
+ match uvar1, uvar2 with
+ | Some (A_aux (A_nexp n1, _)), Some (A_aux (A_nexp n2, _)) ->
+ if nexp_identical n1 n2 then
+ Some (arg_nexp n1)
+ else
+ unify_error l ("Multiple non-identical unifiers for " ^ string_of_kid kid
+ ^ ": " ^ string_of_nexp n1 ^ " and " ^ string_of_nexp n2)
+ | Some _, Some _ -> unify_error l "Multiple non-identical non-nexp unifiers"
+ | None, Some u2 -> Some u2
+ | Some u1, None -> Some u1
+ | None, None -> None
-let uvar_subst_typ sv subst = function
- | U_nexp nexp -> U_nexp nexp
- | U_typ typ -> U_typ (typ_subst_typ sv subst typ)
- | U_order ord -> U_order ord
+let merge_uvars l unifiers1 unifiers2 =
+ KBindings.merge (merge_unifiers l) unifiers1 unifiers2
-let uvar_subst_order sv subst = function
- | U_nexp nexp -> U_nexp nexp
- | U_typ typ -> U_typ (typ_subst_order sv subst typ)
- | U_order ord -> U_order (order_subst sv subst ord)
+let rec unify_typ l env goals (Typ_aux (aux1, _) as typ1) (Typ_aux (aux2, _) as typ2) =
+ match aux1, aux2 with
+ | Typ_internal_unknown, _ | _, Typ_internal_unknown
+ when Env.allow_unknowns env ->
+ KBindings.empty
-exception Unification_error of l * string;;
+ | Typ_var v, _ when KidSet.mem v goals -> KBindings.singleton v (arg_typ typ2)
-let unify_error l str = raise (Unification_error (l, str))
+ | Typ_app (range, [A_aux (A_nexp n1, _); A_aux (A_nexp n2, _)]),
+ Typ_app (atom, [A_aux (A_nexp m, _)])
+ when string_of_id range = "range" && string_of_id atom = "atom" ->
+ merge_uvars l (unify_nexp l env goals n1 m) (unify_nexp l env goals n2 m)
-let rec unify_nexps l env goals (Nexp_aux (nexp_aux1, _) as nexp1) (Nexp_aux (nexp_aux2, _) as nexp2) =
- typ_debug (lazy ("UNIFYING NEXPS " ^ string_of_nexp nexp1 ^ " AND " ^ string_of_nexp nexp2 ^ " FOR GOALS " ^ string_of_list ", " string_of_kid (KidSet.elements goals)));
+ | Typ_app (id1, args1), Typ_app (id2, args2) when List.length args1 = List.length args2 && Id.compare id1 id2 = 0 ->
+ List.fold_left (merge_uvars l) KBindings.empty (List.map2 (unify_typ_arg l env goals) args1 args2)
+
+ | Typ_app (id1, []), Typ_id id2 when Id.compare id1 id2 = 0 -> KBindings.empty
+ | Typ_id id1, Typ_app (id2, []) when Id.compare id1 id2 = 0 -> KBindings.empty
+ | Typ_id id1, Typ_id id2 when Id.compare id1 id2 = 0 -> KBindings.empty
+
+ | Typ_tup typs1, Typ_tup typs2 when List.length typs1 = List.length typs2 ->
+ List.fold_left (merge_uvars l) KBindings.empty (List.map2 (unify_typ l env goals) typs1 typs2)
+
+ | _, _ -> unify_error l ("Cound not unify " ^ string_of_typ typ1 ^ " and " ^ string_of_typ typ2)
+
+and unify_typ_arg l env goals (A_aux (aux1, _) as typ_arg1) (A_aux (aux2, _) as typ_arg2) =
+ match aux1, aux2 with
+ | A_typ typ1, A_typ typ2 -> unify_typ l env goals typ1 typ2
+ | A_nexp nexp1, A_nexp nexp2 -> unify_nexp l env goals nexp1 nexp2
+ | A_order ord1, A_order ord2 -> unify_order l goals ord1 ord2
+ | A_bool nc1, A_bool nc2 -> unify_constraint l goals nc1 nc2
+ | _, _ -> unify_error l ("Could not unify type arguments " ^ string_of_typ_arg typ_arg1 ^ " and " ^ string_of_typ_arg typ_arg2)
+
+and unify_constraint l goals (NC_aux (aux1, _) as nc1) (NC_aux (aux2, _) as nc2) =
+ typ_debug (lazy (Util.("Unify constraint " |> magenta |> clear) ^ string_of_n_constraint nc1 ^ " and " ^ string_of_n_constraint nc2));
+ match aux1, aux2 with
+ | NC_var v, _ when KidSet.mem v goals -> KBindings.singleton v (arg_bool nc2)
+ | _, _ -> unify_error l ("Could not unify constraints " ^ string_of_n_constraint nc1 ^ " and " ^ string_of_n_constraint nc2)
+
+and unify_order l goals (Ord_aux (aux1, _) as ord1) (Ord_aux (aux2, _) as ord2) =
+ typ_print (lazy (Util.("Unify order " |> magenta |> clear) ^ string_of_order ord1 ^ " and " ^ string_of_order ord2));
+ match aux1, aux2 with
+ | Ord_var v, _ when KidSet.mem v goals -> KBindings.singleton v (arg_order ord2)
+ | Ord_inc, Ord_inc -> KBindings.empty
+ | Ord_dec, Ord_dec -> KBindings.empty
+ | _, _ -> unify_error l ("Cound not unify " ^ string_of_order ord1 ^ " and " ^ string_of_order ord2)
+
+and unify_nexp l env goals (Nexp_aux (nexp_aux1, _) as nexp1) (Nexp_aux (nexp_aux2, _) as nexp2) =
+ typ_debug (lazy (Util.("Unify nexp " |> magenta |> clear) ^ string_of_nexp nexp1 ^ " and " ^ string_of_nexp nexp2
+ ^ " goals " ^ string_of_list ", " string_of_kid (KidSet.elements goals)));
if KidSet.is_empty (KidSet.inter (nexp_frees nexp1) goals)
then
begin
if prove env (NC_aux (NC_equal (nexp1, nexp2), Parse_ast.Unknown))
- then None
+ then KBindings.empty
else unify_error l ("Nexp " ^ string_of_nexp nexp1 ^ " and " ^ string_of_nexp nexp2 ^ " are not equal")
end
else
match nexp_aux1 with
| Nexp_id v -> unify_error l "Unimplemented Nexp_id in unify nexp"
- | Nexp_var kid when KidSet.mem kid goals -> Some (kid, nexp2)
+ | Nexp_var kid when KidSet.mem kid goals -> KBindings.singleton kid (arg_nexp nexp2)
| Nexp_constant c1 ->
begin
match nexp_aux2 with
- | Nexp_constant c2 -> if c1 = c2 then None else unify_error l "Constants are not the same"
+ | Nexp_constant c2 -> if c1 = c2 then KBindings.empty else unify_error l "Constants are not the same"
| _ -> unify_error l "Unification error"
end
| Nexp_sum (n1a, n1b) ->
if KidSet.is_empty (nexp_frees n1b)
- then unify_nexps l env goals n1a (nminus nexp2 n1b)
+ then unify_nexp l env goals n1a (nminus nexp2 n1b)
else
if KidSet.is_empty (nexp_frees n1a)
- then unify_nexps l env goals n1b (nminus nexp2 n1a)
+ then unify_nexp l env goals n1b (nminus nexp2 n1a)
else unify_error l ("Both sides of Int expression " ^ string_of_nexp nexp1
^ " contain free type variables so it cannot be unified with " ^ string_of_nexp nexp2)
| Nexp_minus (n1a, n1b) ->
if KidSet.is_empty (nexp_frees n1b)
- then unify_nexps l env goals n1a (nsum nexp2 n1b)
- else unify_error l ("Cannot unify minus Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
+ then unify_nexp l env goals n1a (nsum nexp2 n1b)
+ else unify_error l ("Cannot unify minus Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
| Nexp_times (n1a, n1b) ->
- (* If we have SMT operations div and mod, then we can use the
+ (* f we have SMT operations div and mod, then we can use the
property that
mod(m, C) = 0 && C != 0 --> (C * n = m <--> n = m / C)
- to help us unify multiplications. *)
- if Env.have_smt_op (mk_id "div") env && Env.have_smt_op (mk_id "mod") env then
- let valid n c = prove env (nc_eq (napp (mk_id "mod") [n; c]) (nint 0)) && prove env (nc_neq c (nint 0)) in
- if KidSet.is_empty (nexp_frees n1b) && valid nexp2 n1b then
- unify_nexps l env goals n1a (napp (mk_id "div") [nexp2; n1b])
- else if KidSet.is_empty (nexp_frees n1a) && valid nexp2 n1a then
- unify_nexps l env goals n1b (napp (mk_id "div") [nexp2; n1a])
- else unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
- else if KidSet.is_empty (nexp_frees n1a) then
+ to help us unify multiplications and divisions.
+ let valid n c = prove env (nc_eq (napp (mk_id "mod") [n; c]) (nint 0)) && prove env (nc_neq c (nint 0)) in
+ if KidSet.is_empty (nexp_frees n1b) && valid nexp2 n1b then
+ unify_nexp l env goals n1a (napp (mk_id "div") [nexp2; n1b])
+ else if KidSet.is_empty (nexp_frees n1a) && valid nexp2 n1a then
+ unify_nexp l env goals n1b (napp (mk_id "div") [nexp2; n1a]) *)
+ if KidSet.is_empty (nexp_frees n1a) then
begin
match nexp_aux2 with
| Nexp_times (n2a, n2b) when prove env (NC_aux (NC_equal (n1a, n2a), Parse_ast.Unknown)) ->
- unify_nexps l env goals n1b n2b
+ unify_nexp l env goals n1b n2b
| Nexp_constant c2 ->
begin
match n1a with
| Nexp_aux (Nexp_constant c1,_) when Big_int.equal (Big_int.modulus c2 c1) Big_int.zero ->
- unify_nexps l env goals n1b (mk_nexp (Nexp_constant (Big_int.div c2 c1)))
+ unify_nexp l env goals n1b (nconstant (Big_int.div c2 c1))
| _ -> unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
end
| _ -> unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
@@ -1683,213 +1511,103 @@ let rec unify_nexps l env goals (Nexp_aux (nexp_aux1, _) as nexp1) (Nexp_aux (ne
begin
match nexp_aux2 with
| Nexp_times (n2a, n2b) when prove env (NC_aux (NC_equal (n1b, n2b), Parse_ast.Unknown)) ->
- unify_nexps l env goals n1a n2a
+ unify_nexp l env goals n1a n2a
| _ -> unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
end
else unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
| _ -> unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
-let string_of_uvar = function
- | U_nexp n -> string_of_nexp n
- | U_order o -> string_of_order o
- | U_typ typ -> string_of_typ typ
-
-let unify_order l (Ord_aux (ord_aux1, _) as ord1) (Ord_aux (ord_aux2, _) as ord2) =
- typ_debug (lazy ("UNIFYING ORDERS " ^ string_of_order ord1 ^ " AND " ^ string_of_order ord2));
- match ord_aux1, ord_aux2 with
- | Ord_var kid, _ -> KBindings.singleton kid (U_order ord2)
- | Ord_inc, Ord_inc -> KBindings.empty
- | Ord_dec, Ord_dec -> KBindings.empty
- | _, _ -> unify_error l (string_of_order ord1 ^ " cannot be unified with " ^ string_of_order ord2)
+let unify l env goals typ1 typ2 =
+ typ_print (lazy (Util.("Unify " |> magenta |> clear) ^ string_of_typ typ1 ^ " and " ^ string_of_typ typ2
+ ^ " for " ^ Util.string_of_list ", " string_of_kid (KidSet.elements goals)));
+ let typ1, typ2 = Env.expand_synonyms env typ1, Env.expand_synonyms env typ2 in
+ if not (KidSet.is_empty (KidSet.inter goals (tyvars_of_typ typ2))) then
+ typ_error l ("Occurs check failed: " ^ string_of_typ typ2 ^ " contains "
+ ^ Util.string_of_list ", " string_of_kid (KidSet.elements goals))
+ else
+ unify_typ l env goals typ1 typ2
let subst_unifiers unifiers typ =
- let subst_unifier typ (kid, uvar) =
- match uvar with
- | U_nexp nexp -> typ_subst_nexp kid (unaux_nexp nexp) typ
- | U_order ord -> typ_subst_order kid (unaux_order ord) typ
- | U_typ subst -> typ_subst_typ kid (unaux_typ subst) typ
- in
- List.fold_left subst_unifier typ (KBindings.bindings unifiers)
-
-let subst_args_unifiers unifiers typ_args =
- let subst_unifier typ_args (kid, uvar) =
- match uvar with
- | U_nexp nexp -> List.map (typ_subst_arg_nexp kid (unaux_nexp nexp)) typ_args
- | U_order ord -> List.map (typ_subst_arg_order kid (unaux_order ord)) typ_args
- | U_typ subst -> List.map (typ_subst_arg_typ kid (unaux_typ subst)) typ_args
- in
- List.fold_left subst_unifier typ_args (KBindings.bindings unifiers)
-
-let subst_uvar_unifiers unifiers uvar =
- let subst_unifier uvar' (kid, uvar) =
- match uvar with
- | U_nexp nexp -> uvar_subst_nexp kid (unaux_nexp nexp) uvar'
- | U_order ord -> uvar_subst_order kid (unaux_order ord) uvar'
- | U_typ subst -> uvar_subst_typ kid (unaux_typ subst) uvar'
- in
- List.fold_left subst_unifier uvar (KBindings.bindings unifiers)
+ List.fold_left (fun typ (v, arg) -> typ_subst v arg typ) typ (KBindings.bindings unifiers)
-let merge_unifiers l kid uvar1 uvar2 =
- match uvar1, uvar2 with
- | Some (U_nexp n1), Some (U_nexp n2) ->
- if nexp_identical n1 n2 then Some (U_nexp n1)
- else unify_error l ("Multiple non-identical unifiers for " ^ string_of_kid kid
- ^ ": " ^ string_of_nexp n1 ^ " and " ^ string_of_nexp n2)
- | Some _, Some _ -> unify_error l "Multiple non-identical non-nexp unifiers"
- | None, Some u2 -> Some u2
- | Some u1, None -> Some u1
- | None, None -> None
+let subst_unifiers_typ_arg unifiers typ_arg =
+ List.fold_left (fun typ_arg (v, arg) -> typ_arg_subst v arg typ_arg) typ_arg (KBindings.bindings unifiers)
-let rec unify l env typ1 typ2 =
- typ_print (lazy ("Unify " ^ string_of_typ typ1 ^ " with " ^ string_of_typ typ2));
- let goals = KidSet.inter (KidSet.diff (typ_frees typ1) (typ_frees typ2)) (typ_frees typ1) in
-
- let rec unify_typ l (Typ_aux (typ1_aux, _) as typ1) (Typ_aux (typ2_aux, _) as typ2) =
- typ_debug (lazy ("UNIFYING TYPES " ^ string_of_typ typ1 ^ " AND " ^ string_of_typ typ2));
- match typ1_aux, typ2_aux with
- | Typ_internal_unknown, _
- | _, Typ_internal_unknown when Env.allow_unknowns env -> KBindings.empty
- | Typ_id v1, Typ_id v2 ->
- if Id.compare v1 v2 = 0 then KBindings.empty
- else unify_error l (string_of_typ typ1 ^ " cannot be unified with " ^ string_of_typ typ2)
- | Typ_id v1, Typ_app (f2, []) ->
- if Id.compare v1 f2 = 0 then KBindings.empty
- else unify_error l (string_of_typ typ1 ^ " cannot be unified with " ^ string_of_typ typ2)
- | Typ_app (f1, []), Typ_id v2 ->
- if Id.compare f1 v2 = 0 then KBindings.empty
- else unify_error l (string_of_typ typ1 ^ " cannot be unified with " ^ string_of_typ typ2)
- | Typ_var kid, _ when KidSet.mem kid goals -> KBindings.singleton kid (U_typ typ2)
- | Typ_var kid1, Typ_var kid2 when Kid.compare kid1 kid2 = 0 -> KBindings.empty
- | Typ_tup typs1, Typ_tup typs2 ->
- begin
- try List.fold_left (KBindings.merge (merge_unifiers l)) KBindings.empty (List.map2 (unify_typ l) typs1 typs2) with
- | Invalid_argument _ -> unify_error l (string_of_typ typ1 ^ " cannot be unified with " ^ string_of_typ typ2
- ^ " tuple type is of different length")
- end
- | Typ_app (f1, [arg1]), Typ_app (f2, [arg2a; arg2b])
- when Id.compare (mk_id "atom") f1 = 0 && Id.compare (mk_id "range") f2 = 0 ->
- unify_typ_arg_list 0 KBindings.empty [] [] [arg1; arg1] [arg2a; arg2b]
- | Typ_app (f1, [arg1a; arg1b]), Typ_app (f2, [arg2])
- when Id.compare (mk_id "range") f1 = 0 && Id.compare (mk_id "atom") f2 = 0 ->
- unify_typ_arg_list 0 KBindings.empty [] [] [arg1a; arg1b] [arg2; arg2]
- | Typ_app (f1, args1), Typ_app (f2, args2) when Id.compare f1 f2 = 0 ->
- unify_typ_arg_list 0 KBindings.empty [] [] args1 args2
- | _, _ -> unify_error l (string_of_typ typ1 ^ " cannot be unified with " ^ string_of_typ typ2)
-
- and unify_typ_arg_list unified acc uargs1 uargs2 args1 args2 =
- match args1, args2 with
- | [], [] when unified = 0 && List.length uargs1 > 0 ->
- unify_error l "Could not unify arg lists" (*FIXME improve error *)
- | [], [] when unified > 0 && List.length uargs1 > 0 -> unify_typ_arg_list 0 acc [] [] uargs1 uargs2
- | [], [] when List.length uargs1 = 0 -> acc
- | (a1 :: a1s), (a2 :: a2s) ->
- begin
- let unifiers, success =
- try unify_typ_args l a1 a2, true with
- | Unification_error _ -> KBindings.empty, false
- in
- let a1s = subst_args_unifiers unifiers a1s in
- let a2s = subst_args_unifiers unifiers a2s in
- let uargs1 = subst_args_unifiers unifiers uargs1 in
- let uargs2 = subst_args_unifiers unifiers uargs2 in
- if success
- then unify_typ_arg_list (unified + 1) (KBindings.merge (merge_unifiers l) unifiers acc) uargs1 uargs2 a1s a2s
- else unify_typ_arg_list unified acc (a1 :: uargs1) (a2 :: uargs2) a1s a2s
- end
- | _, _ -> unify_error l "Cannot unify type lists of different length"
-
- and unify_typ_args l (Typ_arg_aux (typ_arg_aux1, _) as typ_arg1) (Typ_arg_aux (typ_arg_aux2, _) as typ_arg2) =
- match typ_arg_aux1, typ_arg_aux2 with
- | Typ_arg_nexp n1, Typ_arg_nexp n2 ->
- begin
- match unify_nexps l env goals (nexp_simp n1) (nexp_simp n2) with
- | Some (kid, unifier) -> KBindings.singleton kid (U_nexp (nexp_simp unifier))
- | None -> KBindings.empty
- end
- | Typ_arg_typ typ1, Typ_arg_typ typ2 -> unify_typ l typ1 typ2
- | Typ_arg_order ord1, Typ_arg_order ord2 -> unify_order l ord1 ord2
- | _, _ -> unify_error l (string_of_typ_arg typ_arg1 ^ " cannot be unified with type argument " ^ string_of_typ_arg typ_arg2)
- in
-
- match destruct_exist env typ2 with
- | Some (kids, nc, typ2) ->
- let typ1, typ2 = Env.expand_synonyms env typ1, Env.expand_synonyms env typ2 in
- let (unifiers, _, _) = unify l env typ1 typ2 in
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
- unifiers, kids, Some nc
- | None ->
- let typ1, typ2 = Env.expand_synonyms env typ1, Env.expand_synonyms env typ2 in
- unify_typ l typ1 typ2, [], None
+let instantiate_quant (v, arg) (QI_aux (aux, l) as qi) =
+ match aux with
+ | QI_id kopt when Kid.compare (kopt_kid kopt) v = 0 ->
+ typ_debug (lazy ("Instantiated " ^ string_of_quant_item qi));
+ None
+ | QI_id _ -> Some qi
+ | QI_const nc -> Some (QI_aux (QI_const (constraint_subst v arg nc), l))
-let merge_uvars l unifiers1 unifiers2 =
- try KBindings.merge (merge_unifiers l) unifiers1 unifiers2
- with
- | Unification_error (_, m) -> typ_error l ("Could not merge unification variables: " ^ m)
+let instantiate_quants quants unifier =
+ List.map (instantiate_quant unifier) quants |> Util.option_these
(**************************************************************************)
-(* 4.5. Subtyping with existentials *)
+(* 3.5. Subtyping with existentials *)
(**************************************************************************)
let destruct_atom_nexp env typ =
match Env.expand_synonyms env typ with
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_nexp n, _)]), _)
+ | Typ_aux (Typ_app (f, [A_aux (A_nexp n, _)]), _)
when string_of_id f = "atom" -> Some n
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_nexp n, _); Typ_arg_aux (Typ_arg_nexp m, _)]), _)
+ | Typ_aux (Typ_app (f, [A_aux (A_nexp n, _); A_aux (A_nexp m, _)]), _)
when string_of_id f = "range" && nexp_identical n m -> Some n
| _ -> None
let destruct_atom_kid env typ =
match Env.expand_synonyms env typ with
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid, _)), _)]), _)
+ | Typ_aux (Typ_app (f, [A_aux (A_nexp (Nexp_aux (Nexp_var kid, _)), _)]), _)
when string_of_id f = "atom" -> Some kid
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid1, _)), _);
- Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var kid2, _)), _)]), _)
+ | Typ_aux (Typ_app (f, [A_aux (A_nexp (Nexp_aux (Nexp_var kid1, _)), _);
+ A_aux (A_nexp (Nexp_aux (Nexp_var kid2, _)), _)]), _)
when string_of_id f = "range" && Kid.compare kid1 kid2 = 0 -> Some kid1
| _ -> None
-let nc_subst_uvar kid uvar nc =
- match uvar with
- | U_nexp nexp -> nc_subst_nexp kid (unaux_nexp nexp) nc
- | _ -> nc
-
-let uv_nexp_constraint env (kid, uvar) =
- match uvar with
- | U_nexp nexp -> Env.add_constraint (nc_eq (nvar kid) nexp) env
- | _ -> env
-
(* The kid_order function takes a set of Int-kinded kids, and returns
a list of those kids in the order they appear in a type, as well as
a set containing all the kids that did not occur in the type. We
only care about Int-kinded kids because those are the only type
that can appear in an existential. *)
-let rec kid_order_nexp kids (Nexp_aux (aux, l) as nexp) =
+let rec kid_order_nexp kind_map (Nexp_aux (aux, l) as nexp) =
match aux with
- | Nexp_var kid when KidSet.mem kid kids -> ([kid], KidSet.remove kid kids)
- | Nexp_var _ | Nexp_id _ | Nexp_constant _ -> ([], kids)
- | Nexp_exp nexp | Nexp_neg nexp -> kid_order_nexp kids nexp
+ | Nexp_var kid when KBindings.mem kid kind_map ->
+ ([mk_kopt (unaux_kind (KBindings.find kid kind_map)) kid], KBindings.remove kid kind_map)
+ | Nexp_var _ | Nexp_id _ | Nexp_constant _ -> ([], kind_map)
+ | Nexp_exp nexp | Nexp_neg nexp -> kid_order_nexp kind_map nexp
| Nexp_times (nexp1, nexp2) | Nexp_sum (nexp1, nexp2) | Nexp_minus (nexp1, nexp2) ->
- let (ord, kids) = kid_order_nexp kids nexp1 in
+ let (ord, kids) = kid_order_nexp kind_map nexp1 in
let (ord', kids) = kid_order_nexp kids nexp2 in
(ord @ ord', kids)
| Nexp_app (id, nexps) ->
- List.fold_left (fun (ord, kids) nexp -> let (ord', kids) = kid_order_nexp kids nexp in (ord @ ord', kids)) ([], kids) nexps
+ List.fold_left (fun (ord, kids) nexp -> let (ord', kids) = kid_order_nexp kids nexp in (ord @ ord', kids)) ([], kind_map) nexps
+
-let rec kid_order kids (Typ_aux (aux, l) as typ) =
+let rec kid_order kind_map (Typ_aux (aux, l) as typ) =
match aux with
- | Typ_var kid when KidSet.mem kid kids -> ([kid], KidSet.remove kid kids)
- | Typ_id _ | Typ_var _ -> ([], kids)
+ | Typ_var kid when KBindings.mem kid kind_map ->
+ ([mk_kopt (unaux_kind (KBindings.find kid kind_map)) kid], KBindings.remove kid kind_map)
+ | Typ_id _ | Typ_var _ -> ([], kind_map)
| Typ_tup typs ->
- List.fold_left (fun (ord, kids) typ -> let (ord', kids) = kid_order kids typ in (ord @ ord', kids)) ([], kids) typs
+ List.fold_left (fun (ord, kids) typ -> let (ord', kids) = kid_order kids typ in (ord @ ord', kids)) ([], kind_map) typs
| Typ_app (_, args) ->
- List.fold_left (fun (ord, kids) arg -> let (ord', kids) = kid_order_arg kids arg in (ord @ ord', kids)) ([], kids) args
+ List.fold_left (fun (ord, kids) arg -> let (ord', kids) = kid_order_arg kids arg in (ord @ ord', kids)) ([], kind_map) args
| Typ_fn _ | Typ_bidir _ | Typ_exist _ -> typ_error l ("Existential or function type cannot appear within existential type: " ^ string_of_typ typ)
| Typ_internal_unknown -> unreachable l __POS__ "escaped Typ_internal_unknown"
-and kid_order_arg kids (Typ_arg_aux (aux, l) as arg) =
+and kid_order_arg kind_map (A_aux (aux, l) as arg) =
match aux with
- | Typ_arg_typ typ -> kid_order kids typ
- | Typ_arg_nexp nexp -> kid_order_nexp kids nexp
- | Typ_arg_order _ -> ([], kids)
+ | A_typ typ -> kid_order kind_map typ
+ | A_nexp nexp -> kid_order_nexp kind_map nexp
+ | A_bool nc -> kid_order_constraint kind_map nc
+ | A_order _ -> ([], kind_map)
+and kid_order_constraint kind_map (NC_aux (aux, l) as nc) =
+ match aux with
+ | NC_var kid when KBindings.mem kid kind_map ->
+ ([mk_kopt (unaux_kind (KBindings.find kid kind_map)) kid], KBindings.remove kid kind_map)
+ | NC_var _ -> ([], kind_map)
+ | _ -> unreachable l __POS__ "bad constraint type"
let rec alpha_equivalent env typ1 typ2 =
let counter = ref 0 in
@@ -1903,21 +1621,23 @@ let rec alpha_equivalent env typ1 typ2 =
| Typ_fn (arg_typs, ret_typ, eff) -> Typ_fn (List.map relabel arg_typs, relabel ret_typ, eff)
| Typ_bidir (typ1, typ2) -> Typ_bidir (relabel typ1, relabel typ2)
| Typ_tup typs -> Typ_tup (List.map relabel typs)
- | Typ_exist (kids, nc, typ) ->
- let (kids, _) = kid_order (KidSet.of_list kids) typ in
- let kids = List.map (fun kid -> (kid, new_kid ())) kids in
- let nc = List.fold_left (fun nc (kid, nk) -> nc_subst_nexp kid (Nexp_var nk) nc) nc kids in
- let typ = List.fold_left (fun nc (kid, nk) -> typ_subst_nexp kid (Nexp_var nk) nc) typ kids in
- let kids = List.map snd kids in
- Typ_exist (kids, nc, typ)
+ | Typ_exist (kopts, nc, typ) ->
+ let kind_map = List.fold_left (fun m kopt -> KBindings.add (kopt_kid kopt) (kopt_kind kopt) m) KBindings.empty kopts in
+ let (kopts, _) = kid_order kind_map typ in
+ let kopts = List.map (fun kopt -> (kopt_kid kopt, mk_kopt (unaux_kind (kopt_kind kopt)) (new_kid ()))) kopts in
+ let nc = List.fold_left (fun nc (kid, nk) -> constraint_subst kid (arg_kopt nk) nc) nc kopts in
+ let typ = List.fold_left (fun nc (kid, nk) -> typ_subst kid (arg_kopt nk) nc) typ kopts in
+ let kopts = List.map snd kopts in
+ Typ_exist (kopts, nc, typ)
| Typ_app (id, args) ->
Typ_app (id, List.map relabel_arg args)
in
Typ_aux (relabelled_aux, l)
- and relabel_arg (Typ_arg_aux (aux, l) as arg) =
+ and relabel_arg (A_aux (aux, l) as arg) =
+ (* FIXME relabel constraint *)
match aux with
- | Typ_arg_nexp _ | Typ_arg_order _ -> arg
- | Typ_arg_typ typ -> Typ_arg_aux (Typ_arg_typ (relabel typ), l)
+ | A_nexp _ | A_order _ | A_bool _ -> arg
+ | A_typ typ -> A_aux (A_typ (relabel typ), l)
in
let typ1 = relabel (Env.expand_synonyms env typ1) in
@@ -1929,62 +1649,121 @@ let rec alpha_equivalent env typ1 typ2 =
else (typ_debug (lazy "Not alpha-equivalent"); false)
let unwrap_exist env typ =
- match destruct_exist env typ with
+ match destruct_exist (Env.expand_synonyms env typ) with
| Some (kids, nc, typ) -> (kids, nc, typ)
| None -> ([], nc_true, typ)
-let rec subtyp l env (Typ_aux (typ_aux1, _) as typ1) (Typ_aux (typ_aux2, _) as typ2) =
+let unifier_constraint env (v, arg) =
+ match arg with
+ | A_aux (A_nexp nexp, _) -> Env.add_constraint (nc_eq (nvar v) nexp) env
+ | _ -> env
+
+let canonicalize env typ =
+ let typ = Env.expand_synonyms env typ in
+ let rec canon (Typ_aux (aux, l)) =
+ match aux with
+ | Typ_var v -> Typ_aux (Typ_var v, l)
+ | Typ_internal_unknown -> Typ_aux (Typ_internal_unknown, l)
+ | Typ_id id when string_of_id id = "int" ->
+ exist_typ (fun _ -> nc_true) (fun v -> atom_typ (nvar v))
+ | Typ_id id -> Typ_aux (Typ_id id, l)
+ | Typ_app (id, [A_aux (A_nexp lo, _); A_aux (A_nexp hi, _)]) when string_of_id id = "range" ->
+ exist_typ (fun v -> nc_and (nc_lteq lo (nvar v)) (nc_lteq (nvar v) hi)) (fun v -> atom_typ (nvar v))
+ | Typ_app (id, args) ->
+ Typ_aux (Typ_app (id, List.map canon_arg args), l)
+ | Typ_tup typs ->
+ let typs = List.map canon typs in
+ let fold_exist (kids, nc, typs) typ =
+ match destruct_exist typ with
+ | Some (kids', nc', typ') -> (kids @ kids', nc_and nc nc', typs @ [typ'])
+ | None -> (kids, nc, typs @ [typ])
+ in
+ let kids, nc, typs = List.fold_left fold_exist ([], nc_true, []) typs in
+ if kids = [] then
+ Typ_aux (Typ_tup typs, l)
+ else
+ Typ_aux (Typ_exist (kids, nc, Typ_aux (Typ_tup typs, l)), l)
+ | Typ_exist (kids, nc, typ) ->
+ begin match destruct_exist (canon typ) with
+ | Some (kids', nc', typ') ->
+ Typ_aux (Typ_exist (kids @ kids', nc_and nc nc', typ'), l)
+ | None -> Typ_aux (Typ_exist (kids, nc, typ), l)
+ end
+ | Typ_fn _ | Typ_bidir _ -> raise (Reporting.err_unreachable l __POS__ "Function type passed to Type_check.canonicalize")
+ and canon_arg (A_aux (aux, l)) =
+ A_aux ((match aux with
+ | A_typ typ -> A_typ (canon typ)
+ | arg -> arg),
+ l)
+ in
+ canon typ
+
+let rec subtyp l env typ1 typ2 =
+ let (Typ_aux (typ_aux1, _) as typ1) = Env.expand_synonyms env typ1 in
+ let (Typ_aux (typ_aux2, _) as typ2) = Env.expand_synonyms env typ2 in
typ_print (lazy (("Subtype " |> Util.green |> Util.clear) ^ string_of_typ typ1 ^ " and " ^ string_of_typ typ2));
- match typ_aux1, typ_aux2 with
- | Typ_tup typs1, Typ_tup typs2 when List.length typs1 = List.length typs2 ->
- List.iter2 (subtyp l env) typs1 typs2
- | _, _ ->
- match destruct_numeric env typ1, destruct_numeric env typ2 with
+ match destruct_numeric typ1, destruct_numeric typ2 with
(* Ensure alpha equivalent types are always subtypes of one another
- this ensures that we can always re-check inferred types. *)
| _, _ when alpha_equivalent env typ1 typ2 -> ()
(* Special cases for two numeric (atom) types *)
| Some (kids1, nc1, nexp1), Some ([], _, nexp2) ->
- let env = add_existential l kids1 nc1 env in
+ let env = add_existential l (List.map (mk_kopt K_int) kids1) nc1 env in
if prove env (nc_eq nexp1 nexp2) then () else typ_raise l (Err_subtype (typ1, typ2, Env.get_constraints env, Env.get_typ_var_locs env))
| Some (kids1, nc1, nexp1), Some (kids2, nc2, nexp2) ->
- let env = add_existential l kids1 nc1 env in
- let env = add_typ_vars l (KidSet.elements (KidSet.inter (nexp_frees nexp2) (KidSet.of_list kids2))) env in
+ let env = add_existential l (List.map (mk_kopt K_int) kids1) nc1 env in
+ let env = add_typ_vars l (List.map (mk_kopt K_int) (KidSet.elements (KidSet.inter (nexp_frees nexp2) (KidSet.of_list kids2)))) env in
let kids2 = KidSet.elements (KidSet.diff (KidSet.of_list kids2) (nexp_frees nexp2)) in
+ if not (kids2 = []) then typ_error l ("Universally quantified constraint generated: " ^ Util.string_of_list ", " string_of_kid kids2) else ();
let env = Env.add_constraint (nc_eq nexp1 nexp2) env in
- let constr var_of =
- Constraint.forall (List.map var_of kids2)
- (nc_constraint env var_of (nc_negate nc2))
- in
- if prove_z3' env constr then ()
+ if prove env nc2 then ()
else typ_raise l (Err_subtype (typ1, typ2, Env.get_constraints env, Env.get_typ_var_locs env))
| _, _ ->
- match destruct_exist env typ1, unwrap_exist env (Env.canonicalize env typ2) with
- | Some (kids, nc, typ1), _ ->
- let env = add_existential l kids nc env in subtyp l env typ1 typ2
- | None, (kids, nc, typ2) ->
+ match destruct_exist_plain typ1, destruct_exist (canonicalize env typ2) with
+ | Some (kopts, nc, typ1), _ ->
+ let env = add_existential l kopts nc env in subtyp l env typ1 typ2
+ | None, Some (kopts, nc, typ2) ->
typ_debug (lazy "Subtype check with unification");
- let env = add_typ_vars l kids env in
- let kids' = KidSet.elements (KidSet.diff (KidSet.of_list kids) (typ_frees typ2)) in
- let unifiers, existential_kids, existential_nc =
- try unify l env typ2 typ1 with
+ let typ1 = canonicalize env typ1 in
+ let env = add_typ_vars l kopts env in
+ let kids' = KidSet.elements (KidSet.diff (KidSet.of_list (List.map kopt_kid kopts)) (typ_frees typ2)) in
+ if not (kids' = []) then typ_error l "Universally quantified constraint generated" else ();
+ let unifiers =
+ try unify l env (KidSet.diff (tyvars_of_typ typ2) (tyvars_of_typ typ1)) typ2 typ1 with
| Unification_error (_, m) -> typ_error l m
in
- let nc = List.fold_left (fun nc (kid, uvar) -> nc_subst_uvar kid uvar nc) nc (KBindings.bindings unifiers) in
- let env = List.fold_left uv_nexp_constraint env (KBindings.bindings unifiers) in
- let env = match existential_kids, existential_nc with
- | [], None -> env
- | _, Some enc ->
- let env = List.fold_left (fun env kid -> Env.add_typ_var l kid BK_int env) env existential_kids in
- Env.add_constraint enc env
- | _, None -> assert false (* Cannot have existential_kids without existential_nc *)
- in
- let constr var_of =
- Constraint.forall (List.map var_of kids')
- (nc_constraint env var_of (nc_negate nc))
- in
- if prove_z3' env constr then ()
+ let nc = List.fold_left (fun nc (kid, uvar) -> constraint_subst kid uvar nc) nc (KBindings.bindings unifiers) in
+ let env = List.fold_left unifier_constraint env (KBindings.bindings unifiers) in
+ if prove env nc then ()
else typ_raise l (Err_subtype (typ1, typ2, Env.get_constraints env, Env.get_typ_var_locs env))
+ | None, None ->
+ match typ_aux1, typ_aux2 with
+ | _, Typ_internal_unknown when Env.allow_unknowns env -> ()
+
+ | Typ_app (id1, _), Typ_id id2 when string_of_id id1 = "atom_bool" && string_of_id id2 = "bool" ->
+ typ_debug (lazy "Boolean subtype");
+ ()
+
+ | Typ_tup typs1, Typ_tup typs2 when List.length typs1 = List.length typs2 ->
+ List.iter2 (subtyp l env) typs1 typs2
+
+ | Typ_app (id1, args1), Typ_app (id2, args2) when Id.compare id1 id2 = 0 && List.length args1 = List.length args2 ->
+ List.iter2 (subtyp_arg l env) args1 args2
+
+ | Typ_id id1, Typ_id id2 when Id.compare id1 id2 = 0 -> ()
+ | Typ_id id1, Typ_app (id2, []) when Id.compare id1 id2 = 0 -> ()
+ | Typ_app (id1, []), Typ_id id2 when Id.compare id1 id2 = 0 -> ()
+
+ | _, _ -> typ_raise l (Err_subtype (typ1, typ2, Env.get_constraints env, Env.get_typ_var_locs env))
+
+and subtyp_arg l env (A_aux (aux1, _) as arg1) (A_aux (aux2, _) as arg2) =
+ typ_print (lazy (("Subtype arg " |> Util.green |> Util.clear) ^ string_of_typ_arg arg1 ^ " and " ^ string_of_typ_arg arg2));
+ match aux1, aux2 with
+ | A_nexp n1, A_nexp n2 when prove env (nc_eq n1 n2) -> ()
+ | A_typ typ1, A_typ typ2 -> subtyp l env typ1 typ2
+ | A_order ord1, A_order ord2 when ord_identical ord1 ord2 -> ()
+ | A_bool nc1, A_bool nc2 when nc_identical nc1 nc2 -> ()
+ | _, _ -> typ_error l "Mismatched argument types in subtype check"
let typ_equality l env typ1 typ2 =
subtyp l env typ1 typ2; subtyp l env typ2 typ1
@@ -1994,7 +1773,7 @@ let subtype_check env typ1 typ2 =
| Type_error _ -> false
(**************************************************************************)
-(* 5. Type checking expressions *)
+(* 4. Type checking expressions *)
(**************************************************************************)
(* The type checker produces a fully annoted AST - tannot is the type
@@ -2052,52 +1831,24 @@ let infer_lit env (L_aux (lit_aux, l) as lit) =
| L_undef -> typ_error l "Cannot infer the type of undefined"
let is_nat_kid kid = function
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_int, _)], _), kid'), _) -> Kid.compare kid kid' = 0
- | KOpt_aux (KOpt_none kid', _) -> Kid.compare kid kid' = 0
+ | KOpt_aux (KOpt_kind (K_aux (K_int, _), kid'), _) -> Kid.compare kid kid' = 0
| _ -> false
let is_order_kid kid = function
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_order, _)], _), kid'), _) -> Kid.compare kid kid' = 0
+ | KOpt_aux (KOpt_kind (K_aux (K_order, _), kid'), _) -> Kid.compare kid kid' = 0
| _ -> false
let is_typ_kid kid = function
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_type, _)], _), kid'), _) -> Kid.compare kid kid' = 0
+ | KOpt_aux (KOpt_kind (K_aux (K_type, _), kid'), _) -> Kid.compare kid kid' = 0
| _ -> false
-let rec instantiate_quants quants kid uvar = match quants with
- | [] -> []
- | ((QI_aux (QI_id kinded_id, _) as quant) :: quants) ->
- typ_debug (lazy ("instantiating quant " ^ string_of_quant_item quant));
- begin
- match uvar with
- | U_nexp nexp ->
- if is_nat_kid kid kinded_id
- then instantiate_quants quants kid uvar
- else quant :: instantiate_quants quants kid uvar
- | U_order ord ->
- if is_order_kid kid kinded_id
- then instantiate_quants quants kid uvar
- else quant :: instantiate_quants quants kid uvar
- | U_typ typ ->
- if is_typ_kid kid kinded_id
- then instantiate_quants quants kid uvar
- else quant :: instantiate_quants quants kid uvar
- end
- | ((QI_aux (QI_const nc, l)) :: quants) ->
- begin
- match uvar with
- | U_nexp nexp ->
- QI_aux (QI_const (nc_subst_nexp kid (unaux_nexp nexp) nc), l) :: instantiate_quants quants kid uvar
- | _ -> (QI_aux (QI_const nc, l)) :: instantiate_quants quants kid uvar
- end
-
let instantiate_simple_equations =
let rec find_eqs kid (NC_aux (nc,_)) =
match nc with
| NC_equal (Nexp_aux (Nexp_var kid',_), nexp)
when Kid.compare kid kid' == 0 &&
not (KidSet.mem kid (nexp_frees nexp)) ->
- [U_nexp nexp]
+ [arg_nexp nexp]
| NC_and (nexp1, nexp2) ->
find_eqs kid nexp1 @ find_eqs kid nexp2
| _ -> []
@@ -2123,9 +1874,9 @@ in inst_from_eq
let destruct_vec_typ l env typ =
let destruct_vec_typ' l = function
- | Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp n1, _);
- Typ_arg_aux (Typ_arg_order o, _);
- Typ_arg_aux (Typ_arg_typ vtyp, _)]
+ | Typ_aux (Typ_app (id, [A_aux (A_nexp n1, _);
+ A_aux (A_order o, _);
+ A_aux (A_typ vtyp, _)]
), _) when string_of_id id = "vector" -> (n1, o, vtyp)
| typ -> typ_error l ("Expected vector type, got " ^ string_of_typ typ)
in
@@ -2134,25 +1885,25 @@ let destruct_vec_typ l env typ =
let env_of_annot (l, tannot) = match tannot with
| Some ((env, _, _),_) -> env
- | None -> raise (Reporting_basic.err_unreachable l __POS__ "no type annotation")
+ | None -> raise (Reporting.err_unreachable l __POS__ "no type annotation")
let env_of (E_aux (_, (l, tannot))) = env_of_annot (l, tannot)
let typ_of_annot (l, tannot) = match tannot with
| Some ((_, typ, _), _) -> typ
- | None -> raise (Reporting_basic.err_unreachable l __POS__ "no type annotation")
+ | None -> raise (Reporting.err_unreachable l __POS__ "no type annotation")
let env_of_annot (l, tannot) = match tannot with
| Some ((env, _, _), _) -> env
- | None -> raise (Reporting_basic.err_unreachable l __POS__ "no type annotation")
+ | None -> raise (Reporting.err_unreachable l __POS__ "no type annotation")
let typ_of (E_aux (_, (l, tannot))) = typ_of_annot (l, tannot)
let env_of (E_aux (_, (l, tannot))) = env_of_annot (l, tannot)
-let pat_typ_of (P_aux (_, (l, tannot))) = typ_of_annot (l, tannot)
+let typ_of_pat (P_aux (_, (l, tannot))) = typ_of_annot (l, tannot)
-let pat_env_of (P_aux (_, (l, tannot))) = env_of_annot (l, tannot)
+let env_of_pat (P_aux (_, (l, tannot))) = env_of_annot (l, tannot)
let typ_of_pexp (Pat_aux (_, (l, tannot))) = typ_of_annot (l, tannot)
@@ -2172,10 +1923,42 @@ let lexp_env_of (LEXP_aux (_, (l, tannot))) = env_of_annot (l, tannot)
let expected_typ_of (l, tannot) = match tannot with
| Some ((_, _, _), exp_typ) -> exp_typ
- | None -> raise (Reporting_basic.err_unreachable l __POS__ "no type annotation")
+ | None -> raise (Reporting.err_unreachable l __POS__ "no type annotation")
(* Flow typing *)
+type simple_numeric =
+ | Equal of nexp
+ | Constraint of (kid -> n_constraint)
+ | Anything
+
+let to_simple_numeric l kids nc (Nexp_aux (aux, _) as n) =
+ match aux, kids with
+ | Nexp_var v, [v'] when Kid.compare v v' = 0 ->
+ Constraint (fun subst -> constraint_subst v (arg_nexp (nvar subst)) nc)
+ | _, [] ->
+ Equal n
+ | _ ->
+ typ_error l "Numeric type is non-simple"
+
+let union_simple_numeric ex1 ex2 =
+ match ex1, ex2 with
+ | Equal nexp1, Equal nexp2 ->
+ Constraint (fun kid -> nc_or (nc_eq (nvar kid) nexp1) (nc_eq (nvar kid) nexp2))
+
+ | Equal nexp, Constraint c ->
+ Constraint (fun kid -> nc_or (nc_eq (nvar kid) nexp) (c kid))
+
+ | Constraint c, Equal nexp ->
+ Constraint (fun kid -> nc_or (c kid) (nc_eq (nvar kid) nexp))
+
+ | _, _ -> Anything
+
+let typ_of_simple_numeric = function
+ | Anything -> int_typ
+ | Equal nexp -> atom_typ nexp
+ | Constraint c -> exist_typ c (fun kid -> atom_typ (nvar kid))
+
let rec big_int_of_nexp (Nexp_aux (nexp, _)) = match nexp with
| Nexp_constant c -> Some c
| Nexp_times (n1, n2) ->
@@ -2190,10 +1973,10 @@ let rec big_int_of_nexp (Nexp_aux (nexp, _)) = match nexp with
let destruct_atom (Typ_aux (typ_aux, _)) =
match typ_aux with
- | Typ_app (f, [Typ_arg_aux (Typ_arg_nexp nexp, _)])
+ | Typ_app (f, [A_aux (A_nexp nexp, _)])
when string_of_id f = "atom" ->
Util.option_map (fun c -> (c, nexp)) (big_int_of_nexp nexp)
- | Typ_app (f, [Typ_arg_aux (Typ_arg_nexp nexp1, _); Typ_arg_aux (Typ_arg_nexp nexp2, _)])
+ | Typ_app (f, [A_aux (A_nexp nexp1, _); A_aux (A_nexp nexp2, _)])
when string_of_id f = "range" ->
begin
match big_int_of_nexp nexp1, big_int_of_nexp nexp2 with
@@ -2214,6 +1997,11 @@ let rec combine_constraint b f x y = match b, x, y with
| _, _, _ -> None
let rec assert_constraint env b (E_aux (exp_aux, _) as exp) =
+ typ_debug ~level:2 (lazy ("Asserting constraint for " ^ string_of_exp exp ^ " : " ^ string_of_typ (typ_of exp)));
+ match typ_of exp with
+ | Typ_aux (Typ_app (Id_aux (Id "atom_bool", _), [A_aux (A_bool nc, _)]), _) ->
+ Some nc
+ | _ ->
match exp_aux with
| E_constraint nc ->
Some nc
@@ -2225,17 +2013,17 @@ let rec assert_constraint env b (E_aux (exp_aux, _) as exp) =
combine_constraint (not b) nc_or (assert_constraint env b x) (assert_constraint env b y)
| E_app (op, [x; y]) when string_of_id op = "and_bool" ->
combine_constraint b nc_and (assert_constraint env b x) (assert_constraint env b y)
- | E_app (op, [x; y]) when string_of_id op = "gteq_atom" ->
+ | E_app (op, [x; y]) when string_of_id op = "gteq_int" ->
option_binop nc_gteq (assert_nexp env x) (assert_nexp env y)
- | E_app (op, [x; y]) when string_of_id op = "lteq_atom" ->
+ | E_app (op, [x; y]) when string_of_id op = "lteq_int" ->
option_binop nc_lteq (assert_nexp env x) (assert_nexp env y)
- | E_app (op, [x; y]) when string_of_id op = "gt_atom" ->
+ | E_app (op, [x; y]) when string_of_id op = "gt_int" ->
option_binop nc_gt (assert_nexp env x) (assert_nexp env y)
- | E_app (op, [x; y]) when string_of_id op = "lt_atom" ->
+ | E_app (op, [x; y]) when string_of_id op = "lt_int" ->
option_binop nc_lt (assert_nexp env x) (assert_nexp env y)
- | E_app (op, [x; y]) when string_of_id op = "eq_atom" ->
+ | E_app (op, [x; y]) when string_of_id op = "eq_int" ->
option_binop nc_eq (assert_nexp env x) (assert_nexp env y)
- | E_app (op, [x; y]) when string_of_id op = "neq_atom" ->
+ | E_app (op, [x; y]) when string_of_id op = "neq_int" ->
option_binop nc_neq (assert_nexp env x) (assert_nexp env y)
| _ ->
None
@@ -2315,6 +2103,14 @@ let irule r env exp =
with
| Type_error (l, err) -> decr depth; typ_raise l err
+
+(* This function adds useful assertion messages to asserts missing them *)
+let assert_msg test = function
+ | E_aux (E_lit (L_aux (L_string "", _)), (l, _)) ->
+ let open Reporting in
+ locate (fun _ -> l) (mk_lit_exp (L_string (loc_to_string ~code:false l ^ ": " ^ string_of_exp test)))
+ | msg -> msg
+
let strip_exp : 'a exp -> unit exp = function exp -> map_exp_annot (fun (l, _) -> (l, ())) exp
let strip_pat : 'a pat -> unit pat = function pat -> map_pat_annot (fun (l, _) -> (l, ())) pat
let strip_pexp : 'a pexp -> unit pexp = function pexp -> map_pexp_annot (fun (l, _) -> (l, ())) pexp
@@ -2343,15 +2139,16 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
let rec check_block l env exps typ =
let annot_exp_effect exp typ eff exp_typ = E_aux (exp, (l, Some ((env, typ, eff), exp_typ))) in
let annot_exp exp typ exp_typ = annot_exp_effect exp typ no_effect exp_typ in
- match exps with
+ match Nl_flow.analyze exps with
| [] -> typ_equality l env typ unit_typ; []
| [exp] -> [crule check_exp env exp typ]
| (E_aux (E_assign (lexp, bind), _) :: exps) ->
let texp, env = bind_assignment env lexp bind in
texp :: check_block l env exps typ
- | ((E_aux (E_assert (constr_exp, assert_msg), _) as exp) :: exps) ->
+ | ((E_aux (E_assert (constr_exp, msg), _) as exp) :: exps) ->
+ let msg = assert_msg constr_exp msg in
let constr_exp = crule check_exp env constr_exp bool_typ in
- let checked_msg = crule check_exp env assert_msg string_typ in
+ let checked_msg = crule check_exp env msg string_typ in
let env = match assert_constraint env true constr_exp with
| Some nc ->
typ_print (lazy (adding ^ "constraint " ^ string_of_n_constraint nc ^ " for assert"));
@@ -2360,6 +2157,11 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
in
let texp = annot_exp_effect (E_assert (constr_exp, checked_msg)) unit_typ (mk_effect [BE_escape]) (Some unit_typ) in
texp :: check_block l env exps typ
+ | ((E_aux (E_if (cond, (E_aux (E_throw _, _) | E_aux (E_block [E_aux (E_throw _, _)], _)), _), _) as exp) :: exps) ->
+ let texp = crule check_exp env exp (mk_typ (Typ_id (mk_id "unit"))) in
+ let cond' = crule check_exp env cond (mk_typ (Typ_id (mk_id "bool"))) in
+ let env = add_opt_constraint (option_map nc_not (assert_constraint env false cond')) env in
+ texp :: check_block l env exps typ
| (exp :: exps) ->
let texp = crule check_exp env exp (mk_typ (Typ_id (mk_id "unit"))) in
texp :: check_block l env exps typ
@@ -2391,7 +2193,7 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
annot_exp (E_list checked_xs) typ
| None -> typ_error l ("List " ^ string_of_exp exp ^ " must have list type, got " ^ string_of_typ typ)
end
- | E_record_update (exp, FES_aux (FES_Fexps (fexps, flag), (l, ()))), _ ->
+ | E_record_update (exp, fexps), _ ->
(* TODO: this could also infer exp - also fix code duplication with E_record below *)
let checked_exp = crule check_exp env exp typ in
let rectyp_id = match Env.expand_synonyms env typ with
@@ -2401,13 +2203,13 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
in
let check_fexp (FE_aux (FE_Fexp (field, exp), (l, ()))) =
let (typq, rectyp_q, field_typ, _) = Env.get_accessor rectyp_id field env in
- let unifiers, _, _ (* FIXME *) = try unify l env rectyp_q typ with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
+ let unifiers = try unify l env (tyvars_of_typ rectyp_q) rectyp_q typ with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
let field_typ' = subst_unifiers unifiers field_typ in
let checked_exp = crule check_exp env exp field_typ' in
FE_aux (FE_Fexp (field, checked_exp), (l, None))
in
- annot_exp (E_record_update (checked_exp, FES_aux (FES_Fexps (List.map check_fexp fexps, flag), (l, None)))) typ
- | E_record (FES_aux (FES_Fexps (fexps, flag), (l, ()))), _ ->
+ annot_exp (E_record_update (checked_exp, List.map check_fexp fexps)) typ
+ | E_record fexps, _ ->
(* TODO: check record fields are total *)
let rectyp_id = match Env.expand_synonyms env typ with
| Typ_aux (Typ_id rectyp_id, _) | Typ_aux (Typ_app (rectyp_id, _), _) when Env.is_record rectyp_id env ->
@@ -2416,12 +2218,12 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
in
let check_fexp (FE_aux (FE_Fexp (field, exp), (l, ()))) =
let (typq, rectyp_q, field_typ, _) = Env.get_accessor rectyp_id field env in
- let unifiers, _, _ (* FIXME *) = try unify l env rectyp_q typ with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
+ let unifiers = try unify l env (tyvars_of_typ rectyp_q) rectyp_q typ with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
let field_typ' = subst_unifiers unifiers field_typ in
let checked_exp = crule check_exp env exp field_typ' in
FE_aux (FE_Fexp (field, checked_exp), (l, None))
in
- annot_exp (E_record (FES_aux (FES_Fexps (List.map check_fexp fexps, flag), (l, None)))) typ
+ annot_exp (E_record (List.map check_fexp fexps)) typ
| E_let (LB_aux (letbind, (let_loc, _)), exp), _ ->
begin
match letbind with
@@ -2442,14 +2244,11 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
if prove env nc
then annot_exp (E_lit (L_aux (L_unit, Parse_ast.Unknown))) unit_typ
else typ_error l ("Cannot prove " ^ string_of_n_constraint nc)
- | E_app (f, [E_aux (E_sizeof nexp, _)]), _ when Id.compare f (mk_id "__solve") = 0 ->
- Env.wf_nexp env nexp;
- begin match solve env nexp with
- | None -> typ_error l ("Coud not solve " ^ string_of_nexp nexp)
- | Some n ->
- print_endline ("Solved " ^ string_of_nexp nexp ^ " = " ^ Big_int.to_string n);
- annot_exp (E_lit (L_aux (L_unit, Parse_ast.Unknown))) unit_typ
- end
+ | E_app (f, [E_aux (E_constraint nc, _)]), _ when Id.compare f (mk_id "_not_prove") = 0 ->
+ Env.wf_constraint env nc;
+ if prove env nc
+ then typ_error l ("Can prove " ^ string_of_n_constraint nc)
+ else annot_exp (E_lit (L_aux (L_unit, Parse_ast.Unknown))) unit_typ
(* All constructors and mappings are treated as having one argument
so Ctor(x, y) is checked as Ctor((x, y)) *)
| E_app (f, x :: y :: zs), _ when Env.is_union_constructor f env || Env.is_mapping f env ->
@@ -2494,10 +2293,19 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
let inferred_exp = infer_funapp l env f xs (Some typ) in
type_coercion env inferred_exp typ
| E_if (cond, then_branch, else_branch), _ ->
- let cond' = crule check_exp env cond (mk_typ (Typ_id (mk_id "bool"))) in
- let then_branch' = crule check_exp (add_opt_constraint (assert_constraint env true cond') env) then_branch typ in
- let else_branch' = crule check_exp (add_opt_constraint (option_map nc_negate (assert_constraint env false cond')) env) else_branch typ in
- annot_exp (E_if (cond', then_branch', else_branch')) typ
+ let cond' = try irule infer_exp env cond with Type_error _ -> crule check_exp env cond bool_typ in
+ begin match destruct_exist (typ_of cond') with
+ | Some (kopts, nc, Typ_aux (Typ_app (ab, [A_aux (A_bool flow, _)]), _)) when string_of_id ab = "atom_bool" ->
+ let env = add_existential l kopts nc env in
+ let then_branch' = crule check_exp (Env.add_constraint flow env) then_branch typ in
+ let else_branch' = crule check_exp (Env.add_constraint (nc_not flow) env) else_branch typ in
+ annot_exp (E_if (cond', then_branch', else_branch')) typ
+ | _ ->
+ let cond' = type_coercion env cond' bool_typ in
+ let then_branch' = crule check_exp (add_opt_constraint (assert_constraint env true cond') env) then_branch typ in
+ let else_branch' = crule check_exp (add_opt_constraint (option_map nc_not (assert_constraint env false cond')) env) else_branch typ in
+ annot_exp (E_if (cond', then_branch', else_branch')) typ
+ end
| E_exit exp, _ ->
let checked_exp = crule check_exp env exp (mk_typ (Typ_id (mk_id "unit"))) in
annot_exp_effect (E_exit checked_exp) typ (mk_effect [BE_escape])
@@ -2632,13 +2440,13 @@ and type_coercion env (E_aux (_, (l, _)) as annotated_exp) typ =
in
begin
try
- typ_debug (lazy ("PERFORMING TYPE COERCION: from " ^ string_of_typ (typ_of annotated_exp) ^ " to " ^ string_of_typ typ));
+ typ_debug (lazy ("Performing type coercion: from " ^ string_of_typ (typ_of annotated_exp) ^ " to " ^ string_of_typ typ));
subtyp l env (typ_of annotated_exp) typ; switch_exp_typ annotated_exp
with
| Type_error (_, trigger) when Env.allow_casts env ->
let casts = filter_casts env (typ_of annotated_exp) typ (Env.get_casts env) in
try_casts trigger [] casts
- | Type_error (l, err) -> typ_error l "Subtype error"
+ | Type_error (l, err) -> typ_raise l err
end
(* type_coercion_unify env exp typ attempts to coerce exp to a type
@@ -2646,7 +2454,7 @@ and type_coercion env (E_aux (_, (l, _)) as annotated_exp) typ =
required that exp_typ unifies with typ. Returns the annotated
coercion as with type_coercion and also a set of unifiers, or
throws a unification error *)
-and type_coercion_unify env (E_aux (_, (l, _)) as annotated_exp) typ =
+and type_coercion_unify env goals (E_aux (_, (l, _)) as annotated_exp) typ =
let strip exp_aux = strip_exp (E_aux (exp_aux, (Parse_ast.Unknown, None))) in
let annot_exp exp typ' = E_aux (exp, (l, Some ((env, typ', no_effect), Some typ))) in
let switch_typ exp typ = match exp with
@@ -2659,8 +2467,8 @@ and type_coercion_unify env (E_aux (_, (l, _)) as annotated_exp) typ =
typ_print (lazy ("Casting with " ^ string_of_id cast ^ " expression " ^ string_of_exp annotated_exp ^ " for unification"));
try
let inferred_cast = irule infer_exp (Env.no_casts env) (strip (E_app (cast, [annotated_exp]))) in
- let ityp = typ_of inferred_cast in
- annot_exp (E_cast (ityp, inferred_cast)) ityp, unify l env typ ityp
+ let ityp, env = bind_existential l (typ_of inferred_cast) env in
+ inferred_cast, unify l env goals typ ityp, env
with
| Type_error (_, err) -> try_casts casts
| Unification_error (_, err) -> try_casts casts
@@ -2668,8 +2476,9 @@ and type_coercion_unify env (E_aux (_, (l, _)) as annotated_exp) typ =
in
begin
try
- typ_debug (lazy "PERFORMING COERCING UNIFICATION");
- annotated_exp, unify l env typ (typ_of annotated_exp)
+ typ_debug (lazy ("Coercing unification: from " ^ string_of_typ (typ_of annotated_exp) ^ " to " ^ string_of_typ typ));
+ let atyp, env = bind_existential l (typ_of annotated_exp) env in
+ annotated_exp, unify l env goals typ atyp, env
with
| Unification_error (_, m) when Env.allow_casts env ->
let casts = filter_casts env (typ_of annotated_exp) typ (Env.get_casts env) in
@@ -2683,7 +2492,7 @@ and bind_pat_no_guard env (P_aux (_,(l,_)) as pat) typ =
and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ) =
let (Typ_aux (typ_aux, _) as typ), env = bind_existential l typ env in
- typ_print (lazy ("Binding " ^ string_of_pat pat ^ " to " ^ string_of_typ typ));
+ typ_print (lazy (Util.("Binding " |> yellow |> clear) ^ string_of_pat pat ^ " to " ^ string_of_typ typ));
let annot_pat pat typ' = P_aux (pat, (l, Some ((env, typ', no_effect), Some typ))) in
let switch_typ pat typ = match pat with
| P_aux (pat_aux, (l, Some ((env, _, eff), exp_typ))) -> P_aux (pat_aux, (l, Some ((env, typ, eff), exp_typ)))
@@ -2700,7 +2509,7 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
if Env.is_union_constructor v env then
Util.warn (Printf.sprintf "Identifier %s found in pattern is also a union constructor at %s\n"
(string_of_id v)
- (Reporting_basic.loc_to_string l))
+ (Reporting.loc_to_string l))
else ();
match Env.lookup_id v env with
| Local _ | Unbound -> annot_pat (P_id v) typ, Env.add_local v (Immutable, typ) env, []
@@ -2723,7 +2532,7 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
| P_cons (hd_pat, tl_pat) ->
begin
match Env.expand_synonyms env typ with
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
+ | Typ_aux (Typ_app (f, [A_aux (A_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
let hd_pat, env, hd_guards = bind_pat env hd_pat ltyp in
let tl_pat, env, tl_guards = bind_pat env tl_pat typ in
annot_pat (P_cons (hd_pat, tl_pat)) typ, env, hd_guards @ tl_guards
@@ -2747,7 +2556,7 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
| P_list pats ->
begin
match Env.expand_synonyms env typ with
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
+ | Typ_aux (Typ_app (f, [A_aux (A_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
let rec process_pats env = function
| [] -> [], env, []
| (pat :: pats) ->
@@ -2781,7 +2590,7 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
end
| P_app (f, pats) when Env.is_union_constructor f env ->
begin
- let (typq, ctor_typ) = Env.get_val_spec f env in
+ let (typq, ctor_typ) = Env.get_union_id f env in
let quants = quant_items typq in
let untuple (Typ_aux (typ_aux, _) as typ) = match typ_aux with
| Typ_tup typs -> typs
@@ -2791,13 +2600,13 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
| Typ_aux (Typ_fn ([arg_typ], ret_typ, _), _) ->
begin
try
+ let goals = quant_kopts typq |> List.map kopt_kid |> KidSet.of_list in
typ_debug (lazy ("Unifying " ^ string_of_bind (typq, ctor_typ) ^ " for pattern " ^ string_of_typ typ));
- let unifiers, _, _ (* FIXME! *) = unify l env ret_typ typ in
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
+ let unifiers = unify l env goals ret_typ typ in
let arg_typ' = subst_unifiers unifiers arg_typ in
- let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
- if (match quants' with [] -> false | _ -> true)
- then typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants' ^ " not resolved in pattern " ^ string_of_pat pat)
+ let quants' = List.fold_left instantiate_quants quants (KBindings.bindings unifiers) in
+ if not (List.for_all (solve_quant env) quants') then
+ typ_raise l (Err_unresolved_quants (f, quants', Env.get_locals env, Env.get_constraints env))
else ();
let ret_typ' = subst_unifiers unifiers ret_typ in
let tpats, env, guards =
@@ -2825,12 +2634,10 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
try
typ_debug (lazy ("Unifying " ^ string_of_bind (typq, mapping_typ) ^ " for pattern " ^ string_of_typ typ));
- let unifiers, _, _ (* FIXME! *) = unify l env typ2 typ in
-
- typ_debug (lazy ("unifiers: " ^ string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
-
+ (* FIXME: There's no obvious goals here *)
+ let unifiers = unify l env (tyvars_of_typ typ2) typ2 typ in
let arg_typ' = subst_unifiers unifiers typ1 in
- let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
+ let quants' = List.fold_left instantiate_quants quants (KBindings.bindings unifiers) in
if (match quants' with [] -> false | _ -> true)
then typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants' ^ " not resolved in pattern " ^ string_of_pat pat)
else ();
@@ -2846,10 +2653,9 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
try
typ_debug (lazy "Unifying mapping forwards failed, trying backwards.");
typ_debug (lazy ("Unifying " ^ string_of_bind (typq, mapping_typ) ^ " for pattern " ^ string_of_typ typ));
- let unifiers, _, _ (* FIXME! *) = unify l env typ1 typ in
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
+ let unifiers = unify l env (tyvars_of_typ typ1) typ1 typ in
let arg_typ' = subst_unifiers unifiers typ2 in
- let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
+ let quants' = List.fold_left instantiate_quants quants (KBindings.bindings unifiers) in
if (match quants' with [] -> false | _ -> true)
then typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants' ^ " not resolved in pattern " ^ string_of_pat pat)
else ();
@@ -2869,20 +2675,20 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
typ_error l (string_of_id f ^ " is not a union constructor or mapping in pattern " ^ string_of_pat pat)
| P_as (pat, id) ->
let (typed_pat, env, guards) = bind_pat env pat typ in
- annot_pat (P_as (typed_pat, id)) (pat_typ_of typed_pat), Env.add_local id (Immutable, pat_typ_of typed_pat) env, guards
+ annot_pat (P_as (typed_pat, id)) (typ_of_pat typed_pat), Env.add_local id (Immutable, typ_of_pat typed_pat) env, guards
(* This is a special case for flow typing when we match a constant numeric literal. *)
| P_lit (L_aux (L_num n, _) as lit) when is_atom typ ->
let nexp = match destruct_atom_nexp env typ with Some n -> n | None -> assert false in
annot_pat (P_lit lit) (atom_typ (nconstant n)), Env.add_constraint (nc_eq nexp (nconstant n)) env, []
| _ ->
let (inferred_pat, env, guards) = infer_pat env pat in
- match subtyp l env typ (pat_typ_of inferred_pat) with
- | () -> switch_typ inferred_pat (pat_typ_of inferred_pat), env, guards
+ match subtyp l env typ (typ_of_pat inferred_pat) with
+ | () -> switch_typ inferred_pat (typ_of_pat inferred_pat), env, guards
| exception (Type_error _ as typ_exn) ->
match pat_aux with
| P_lit lit ->
let var = fresh_var () in
- let guard = locate l (mk_exp (E_app_infix (mk_exp (E_id var), mk_id "==", mk_exp (E_lit lit)))) in
+ let guard = locate (fun _ -> l) (mk_exp (E_app_infix (mk_exp (E_id var), mk_id "==", mk_exp (E_lit lit)))) in
let (typed_pat, env, guards) = bind_pat env (mk_pat (P_id var)) typ in
typed_pat, env, guard::guards
| _ -> raise typ_exn
@@ -2934,8 +2740,8 @@ and infer_pat env (P_aux (pat_aux, (l, ())) as pat) =
in
let pats, env, guards = List.fold_left fold_pats ([], env, []) (pat :: pats) in
let len = nexp_simp (nint (List.length pats)) in
- let etyp = pat_typ_of (List.hd pats) in
- List.iter (fun pat -> typ_equality l env etyp (pat_typ_of pat)) pats;
+ let etyp = typ_of_pat (List.hd pats) in
+ List.iter (fun pat -> typ_equality l env etyp (typ_of_pat pat)) pats;
annot_pat (P_vector pats) (dvector_typ env len etyp), env, guards
| P_vector_concat (pat :: pats) ->
let fold_pats (pats, env, guards) pat =
@@ -2944,9 +2750,9 @@ and infer_pat env (P_aux (pat_aux, (l, ())) as pat) =
in
let inferred_pats, env, guards =
List.fold_left fold_pats ([], env, []) (pat :: pats) in
- let (len, _, vtyp) = destruct_vec_typ l env (pat_typ_of (List.hd inferred_pats)) in
+ let (len, _, vtyp) = destruct_vec_typ l env (typ_of_pat (List.hd inferred_pats)) in
let fold_len len pat =
- let (len', _, vtyp') = destruct_vec_typ l env (pat_typ_of pat) in
+ let (len', _, vtyp') = destruct_vec_typ l env (typ_of_pat pat) in
typ_equality l env vtyp vtyp';
nsum len len'
in
@@ -2955,7 +2761,7 @@ and infer_pat env (P_aux (pat_aux, (l, ())) as pat) =
| P_string_append pats ->
let fold_pats (pats, env, guards) pat =
let inferred_pat, env, guards' = infer_pat env pat in
- typ_equality l env (pat_typ_of inferred_pat) string_typ;
+ typ_equality l env (typ_of_pat inferred_pat) string_typ;
pats @ [inferred_pat], env, guards' @ guards
in
let typed_pats, env, guards =
@@ -2964,8 +2770,8 @@ and infer_pat env (P_aux (pat_aux, (l, ())) as pat) =
annot_pat (P_string_append typed_pats) string_typ, env, guards
| P_as (pat, id) ->
let (typed_pat, env, guards) = infer_pat env pat in
- annot_pat (P_as (typed_pat, id)) (pat_typ_of typed_pat),
- Env.add_local id (Immutable, pat_typ_of typed_pat) env,
+ annot_pat (P_as (typed_pat, id)) (typ_of_pat typed_pat),
+ Env.add_local id (Immutable, typ_of_pat typed_pat) env,
guards
| _ -> typ_error l ("Couldn't infer type of pattern " ^ string_of_pat pat)
@@ -2976,7 +2782,7 @@ and bind_typ_pat env (TP_aux (typ_pat_aux, l) as typ_pat) (Typ_aux (typ_aux, _)
begin
match typ_nexps typ with
| [nexp] ->
- Env.add_constraint (nc_eq (nvar kid) nexp) (Env.add_typ_var l kid BK_int env)
+ Env.add_constraint (nc_eq (nvar kid) nexp) (Env.add_typ_var l (mk_kopt K_int kid) env)
| [] ->
typ_error l ("No numeric expressions in " ^ string_of_typ typ ^ " to bind " ^ string_of_kid kid ^ " to")
| nexps ->
@@ -2985,13 +2791,13 @@ and bind_typ_pat env (TP_aux (typ_pat_aux, l) as typ_pat) (Typ_aux (typ_aux, _)
| TP_app (f1, tpats), Typ_app (f2, typs) when Id.compare f1 f2 = 0 ->
List.fold_left2 bind_typ_pat_arg env tpats typs
| _, _ -> typ_error l ("Couldn't bind type " ^ string_of_typ typ ^ " with " ^ string_of_typ_pat typ_pat)
-and bind_typ_pat_arg env (TP_aux (typ_pat_aux, l) as typ_pat) (Typ_arg_aux (typ_arg_aux, _) as typ_arg) =
+and bind_typ_pat_arg env (TP_aux (typ_pat_aux, l) as typ_pat) (A_aux (typ_arg_aux, _) as typ_arg) =
match typ_pat_aux, typ_arg_aux with
| TP_wild, _ -> env
- | TP_var kid, Typ_arg_nexp nexp ->
- Env.add_constraint (nc_eq (nvar kid) nexp) (Env.add_typ_var l kid BK_int env)
- | _, Typ_arg_typ typ -> bind_typ_pat env typ_pat typ
- | _, Typ_arg_order _ -> typ_error l "Cannot bind type pattern against order"
+ | TP_var kid, A_nexp nexp ->
+ Env.add_constraint (nc_eq (nvar kid) nexp) (Env.add_typ_var l (mk_kopt K_int kid) env)
+ | _, A_typ typ -> bind_typ_pat env typ_pat typ
+ | _, A_order _ -> typ_error l "Cannot bind type pattern against order"
| _, _ -> typ_error l ("Couldn't bind type argument " ^ string_of_typ_arg typ_arg ^ " with " ^ string_of_typ_pat typ_pat)
and bind_assignment env (LEXP_aux (lexp_aux, _) as lexp) (E_aux (_, (l, ())) as exp) =
@@ -3038,7 +2844,7 @@ and bind_assignment env (LEXP_aux (lexp_aux, _) as lexp) (E_aux (_, (l, ())) as
| Typ_aux (Typ_id rectyp_id, _) | Typ_aux (Typ_app (rectyp_id, _), _) when Env.is_record rectyp_id env ->
let eff = if is_register then mk_effect [BE_wreg] else no_effect in
let (typq, rectyp_q, field_typ, _) = Env.get_accessor rectyp_id field env in
- let unifiers, _, _ (* FIXME *) = try unify l env rectyp_q regtyp with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
+ let unifiers = try unify l env (tyvars_of_typ rectyp_q) rectyp_q regtyp with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
let field_typ' = subst_unifiers unifiers field_typ in
let checked_exp = crule check_exp env exp field_typ' in
annot_assign (annot_lexp (LEXP_field (annot_lexp_effect inferred_flexp regtyp eff, field)) field_typ') checked_exp, env
@@ -3059,9 +2865,21 @@ and bind_assignment env (LEXP_aux (lexp_aux, _) as lexp) (E_aux (_, (l, ())) as
| _ -> assert false
end
| _ ->
- let inferred_exp = irule infer_exp env exp in
- let tlexp, env' = bind_lexp env lexp (typ_of inferred_exp) in
- annot_assign tlexp inferred_exp, env'
+ (* Here we have two options, we can infer the type from the
+ expression, or we can infer the type from the
+ l-expression. Both are useful in different cases, so try
+ both. *)
+ try
+ let inferred_exp = irule infer_exp env exp in
+ let tlexp, env' = bind_lexp env lexp (typ_of inferred_exp) in
+ annot_assign tlexp inferred_exp, env'
+ with
+ | Type_error (l, err) ->
+ try
+ let inferred_lexp = infer_lexp env lexp in
+ let checked_exp = crule check_exp env exp (lexp_typ_of inferred_lexp) in
+ annot_assign inferred_lexp checked_exp, env
+ with Type_error (l, err') -> typ_raise l (Err_because (err', err))
and bind_lexp env (LEXP_aux (lexp_aux, (l, ())) as lexp) typ =
typ_print (lazy ("Binding mutable " ^ string_of_lexp lexp ^ " to " ^ string_of_typ typ));
@@ -3087,7 +2905,7 @@ and bind_lexp env (LEXP_aux (lexp_aux, (l, ())) as lexp) typ =
| LEXP_deref exp ->
let inferred_exp = infer_exp env exp in
begin match typ_of inferred_exp with
- | Typ_aux (Typ_app (r, [Typ_arg_aux (Typ_arg_typ vtyp, _)]), _) when string_of_id r = "register" ->
+ | Typ_aux (Typ_app (r, [A_aux (A_typ vtyp, _)]), _) when string_of_id r = "register" ->
subtyp l env typ vtyp; annot_lexp_effect (LEXP_deref inferred_exp) typ (mk_effect [BE_wreg]), env
| _ ->
typ_error l (string_of_typ typ ^ " must be a register type in " ^ string_of_exp exp ^ ")")
@@ -3140,7 +2958,7 @@ and infer_lexp env (LEXP_aux (lexp_aux, (l, ())) as lexp) =
let inferred_v_lexp = infer_lexp env v_lexp in
let (Typ_aux (v_typ_aux, _) as v_typ) = Env.expand_synonyms env (lexp_typ_of inferred_v_lexp) in
match v_typ_aux with
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp len, _); Typ_arg_aux (Typ_arg_order ord, _); Typ_arg_aux (Typ_arg_typ elem_typ, _)])
+ | Typ_app (id, [A_aux (A_nexp len, _); A_aux (A_order ord, _); A_aux (A_typ elem_typ, _)])
when Id.compare id (mk_id "vector") = 0 ->
let inferred_exp1 = infer_exp env exp1 in
let inferred_exp2 = infer_exp env exp2 in
@@ -3162,7 +2980,7 @@ and infer_lexp env (LEXP_aux (lexp_aux, (l, ())) as lexp) =
let inferred_v_lexp = infer_lexp env v_lexp in
let (Typ_aux (v_typ_aux, _) as v_typ) = Env.expand_synonyms env (lexp_typ_of inferred_v_lexp) in
match v_typ_aux with
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp len, _); Typ_arg_aux (Typ_arg_order ord, _); Typ_arg_aux (Typ_arg_typ elem_typ, _)])
+ | Typ_app (id, [A_aux (A_nexp len, _); A_aux (A_order ord, _); A_aux (A_typ elem_typ, _)])
when Id.compare id (mk_id "vector") = 0 ->
let inferred_exp = infer_exp env exp in
let nexp, env = bind_numeric l (typ_of inferred_exp) env in
@@ -3177,7 +2995,7 @@ and infer_lexp env (LEXP_aux (lexp_aux, (l, ())) as lexp) =
begin
let sum_lengths first_ord first_elem_typ acc (Typ_aux (v_typ_aux, _) as v_typ) =
match v_typ_aux with
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp len, _); Typ_arg_aux (Typ_arg_order ord, _); Typ_arg_aux (Typ_arg_typ elem_typ, _)])
+ | Typ_app (id, [A_aux (A_nexp len, _); A_aux (A_order ord, _); A_aux (A_typ elem_typ, _)])
when Id.compare id (mk_id "vector") = 0 && ord_identical ord first_ord ->
typ_equality l env elem_typ first_elem_typ;
nsum acc len
@@ -3188,7 +3006,7 @@ and infer_lexp env (LEXP_aux (lexp_aux, (l, ())) as lexp) =
let (Typ_aux (v_typ_aux, _) as v_typ) = Env.expand_synonyms env (lexp_typ_of inferred_v_lexp) in
let v_typs = List.map (fun lexp -> Env.expand_synonyms env (lexp_typ_of lexp)) inferred_v_lexps in
match v_typ_aux with
- | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp len, _); Typ_arg_aux (Typ_arg_order ord, _); Typ_arg_aux (Typ_arg_typ elem_typ, _)])
+ | Typ_app (id, [A_aux (A_nexp len, _); A_aux (A_order ord, _); A_aux (A_typ elem_typ, _)])
when Id.compare id (mk_id "vector") = 0 ->
let len = List.fold_left (sum_lengths ord elem_typ) len v_typs in
annot_lexp (LEXP_vector_concat (inferred_v_lexp :: inferred_v_lexps)) (vector_typ (nexp_simp len) ord elem_typ)
@@ -3203,7 +3021,10 @@ and infer_lexp env (LEXP_aux (lexp_aux, (l, ())) as lexp) =
in
let typq, _, ret_typ, _ = Env.get_accessor rec_id fid env in
annot_lexp_effect (LEXP_field (annot_lexp (LEXP_id v) (mk_id_typ rec_id), fid)) ret_typ weff
- | _ -> typ_error l ("Unhandled l-expression " ^ string_of_lexp lexp)
+ | LEXP_tup lexps ->
+ let inferred_lexps = List.map (infer_lexp env) lexps in
+ annot_lexp (LEXP_tup inferred_lexps) (tuple_typ (List.map lexp_typ_of inferred_lexps))
+ | _ -> typ_error l ("Could not infer the type of " ^ string_of_lexp lexp)
and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
let annot_exp_effect exp typ eff = E_aux (exp, (l, Some ((env, typ, eff),None))) in
@@ -3219,7 +3040,7 @@ and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
| Unbound -> typ_error l ("Identifier " ^ string_of_id v ^ " is unbound")
end
| E_lit lit -> annot_exp (E_lit lit) (infer_lit env lit)
- | E_sizeof nexp -> annot_exp (E_sizeof nexp) (mk_typ (Typ_app (mk_id "atom", [mk_typ_arg (Typ_arg_nexp nexp)])))
+ | E_sizeof nexp -> annot_exp (E_sizeof nexp) (mk_typ (Typ_app (mk_id "atom", [mk_typ_arg (A_nexp nexp)])))
| E_constraint nc ->
Env.wf_constraint env nc;
annot_exp (E_constraint nc) bool_typ
@@ -3250,7 +3071,7 @@ and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
annot_exp (E_tuple inferred_exps) (mk_typ (Typ_tup (List.map typ_of inferred_exps)))
| E_assign (lexp, bind) ->
fst (bind_assignment env lexp bind)
- | E_record_update (exp, FES_aux (FES_Fexps (fexps, flag), (l, ()))) ->
+ | E_record_update (exp, fexps) ->
let inferred_exp = irule infer_exp env exp in
let typ = typ_of inferred_exp in
let rectyp_id = match Env.expand_synonyms env typ with
@@ -3260,12 +3081,12 @@ and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
in
let check_fexp (FE_aux (FE_Fexp (field, exp), (l, ()))) =
let (typq, rectyp_q, field_typ, _) = Env.get_accessor rectyp_id field env in
- let unifiers, _, _ (* FIXME *) = try unify l env rectyp_q typ with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
+ let unifiers = try unify l env (tyvars_of_typ rectyp_q) rectyp_q typ with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
let field_typ' = subst_unifiers unifiers field_typ in
let inferred_exp = crule check_exp env exp field_typ' in
FE_aux (FE_Fexp (field, inferred_exp), (l, None))
in
- annot_exp (E_record_update (inferred_exp, FES_aux (FES_Fexps (List.map check_fexp fexps, flag), (l, None)))) typ
+ annot_exp (E_record_update (inferred_exp, List.map check_fexp fexps)) typ
| E_cast (typ, exp) ->
let checked_exp = crule check_exp env exp typ in
annot_exp (E_cast (typ, checked_exp)) typ
@@ -3315,10 +3136,10 @@ and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
let inferred_f = irule infer_exp env f in
let inferred_t = irule infer_exp env t in
let checked_step = crule check_exp env step int_typ in
- match destruct_numeric env (typ_of inferred_f), destruct_numeric env (typ_of inferred_t) with
+ match destruct_numeric (typ_of inferred_f), destruct_numeric (typ_of inferred_t) with
| Some (kids1, nc1, nexp1), Some (kids2, nc2, nexp2) ->
let loop_kid = mk_kid ("loop_" ^ string_of_id v) in
- let env = List.fold_left (fun env kid -> Env.add_typ_var l kid BK_int env) env (loop_kid :: kids1 @ kids2) in
+ let env = List.fold_left (fun env kid -> Env.add_typ_var l (mk_kopt K_int kid) env) env (loop_kid :: kids1 @ kids2) in
let env = Env.add_constraint (nc_and nc1 nc2) env in
let env = Env.add_constraint (nc_and (nc_lteq nexp1 (nvar loop_kid)) (nc_lteq (nvar loop_kid) nexp2)) env in
let loop_vtyp = atom_typ (nvar loop_kid) in
@@ -3331,8 +3152,22 @@ and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
| E_if (cond, then_branch, else_branch) ->
let cond' = crule check_exp env cond (mk_typ (Typ_id (mk_id "bool"))) in
let then_branch' = irule infer_exp (add_opt_constraint (assert_constraint env true cond') env) then_branch in
- let else_branch' = crule check_exp (add_opt_constraint (option_map nc_negate (assert_constraint env false cond')) env) else_branch (typ_of then_branch') in
- annot_exp (E_if (cond', then_branch', else_branch')) (typ_of then_branch')
+ (* We don't have generic type union in Sail, but we can union simple numeric types. *)
+ begin match destruct_numeric (Env.expand_synonyms env (typ_of then_branch')) with
+ | Some (kids, nc, then_nexp) ->
+ let then_sn = to_simple_numeric l kids nc then_nexp in
+ let else_branch' = irule infer_exp (add_opt_constraint (option_map nc_not (assert_constraint env false cond')) env) else_branch in
+ begin match destruct_numeric (Env.expand_synonyms env (typ_of else_branch')) with
+ | Some (kids, nc, else_nexp) ->
+ let else_sn = to_simple_numeric l kids nc else_nexp in
+ let typ = typ_of_simple_numeric (union_simple_numeric then_sn else_sn) in
+ annot_exp (E_if (cond', then_branch', else_branch')) typ
+ | None -> typ_error l ("Could not infer type of " ^ string_of_exp else_branch)
+ end
+ | None ->
+ let else_branch' = crule check_exp (add_opt_constraint (option_map nc_not (assert_constraint env false cond')) env) else_branch (typ_of then_branch') in
+ annot_exp (E_if (cond', then_branch', else_branch')) (typ_of then_branch')
+ end
| E_vector_access (v, n) -> infer_exp env (E_aux (E_app (mk_id "vector_access", [v; n]), (l, ())))
| E_vector_update (v, n, exp) -> infer_exp env (E_aux (E_app (mk_id "vector_update", [v; n; exp]), (l, ())))
| E_vector_update_subrange (v, n, m, exp) -> infer_exp env (E_aux (E_app (mk_id "vector_update_subrange", [v; n; m; exp]), (l, ())))
@@ -3346,6 +3181,7 @@ and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
let vec_typ = dvector_typ env (nint (List.length vec)) (typ_of inferred_item) in
annot_exp (E_vector (inferred_item :: checked_items)) vec_typ
| E_assert (test, msg) ->
+ let msg = assert_msg test msg in
let checked_test = crule check_exp env test bool_typ in
let checked_msg = crule check_exp env msg string_typ in
annot_exp_effect (E_assert (checked_test, checked_msg)) unit_typ (mk_effect [BE_escape])
@@ -3406,161 +3242,125 @@ and instantiation_of_without_type (E_aux (exp_aux, (l, _)) as exp) =
| E_app (f, xs) -> snd (infer_funapp' l (Env.no_casts env) f (Env.get_val_spec f env) (List.map strip_exp xs) None)
| _ -> invalid_arg ("instantiation_of expected application, got " ^ string_of_exp exp)
-and infer_funapp' l env f (typq, f_typ) xs ret_ctx_typ =
- let annot_exp exp typ eff = E_aux (exp, (l, Some ((env, typ, eff), ret_ctx_typ))) in
- let switch_annot env typ = function
- | (E_aux (exp, (l, Some (_, _, eff)))) -> E_aux (exp, (l, Some (env, typ, eff)))
- | _ -> failwith "Cannot switch annot for unannotated function"
- in
- let all_unifiers = ref KBindings.empty in
- let ex_goal = ref None in
- let prove_goal env = match !ex_goal with
- | Some goal when prove env goal -> ()
- | Some goal -> typ_error l ("Could not prove existential goal: " ^ string_of_n_constraint goal)
- | None -> ()
- in
+and infer_funapp' l env f (typq, f_typ) xs expected_ret_typ =
+ typ_print (lazy (Util.("Function " |> cyan |> clear) ^ string_of_id f));
+ let annot_exp exp typ eff = E_aux (exp, (l, Some ((env, typ, eff), expected_ret_typ))) in
+ let is_bound env kid = KBindings.mem kid (Env.get_typ_vars env) in
+
+ (* First we record all the type variables when we start checking the
+ application, so we can distinguish them from existentials
+ introduced by instantiating function arguments later. *)
let universals = Env.get_typ_vars env in
let universal_constraints = Env.get_constraints env in
- let is_bound kid env = KBindings.mem kid (Env.get_typ_vars env) in
- let rec number n = function
- | [] -> []
- | (x :: xs) -> (n, x) :: number (n + 1) xs
- in
- let solve_quant env = function
- | QI_aux (QI_id _, _) -> false
- | QI_aux (QI_const nc, _) -> prove env nc
- in
+
+ let all_unifiers = ref KBindings.empty in
let record_unifiers unifiers =
let previous_unifiers = !all_unifiers in
- let updated_unifiers = KBindings.map (subst_uvar_unifiers unifiers) previous_unifiers in
+ let updated_unifiers = KBindings.map (subst_unifiers_typ_arg unifiers) previous_unifiers in
all_unifiers := merge_uvars l updated_unifiers unifiers;
in
- let rec instantiate env quants typs ret_typ args =
- match typs, args with
- | (utyps, []), (uargs, []) ->
- begin
- typ_debug (lazy ("Got unresolved args: " ^ string_of_list ", " (fun (_, exp) -> string_of_exp exp) uargs));
- if List.for_all (solve_quant env) quants
- then
- let iuargs = List.map2 (fun utyp (n, uarg) -> (n, crule check_exp env uarg utyp)) utyps uargs in
- (iuargs, ret_typ, env)
- else typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants
- ^ " not resolved during application of " ^ string_of_id f ^ " unresolved args: " ^ string_of_list ", " (fun (_, exp) -> string_of_exp exp) uargs)
- end
- | (utyps, (typ :: typs)), (uargs, ((n, arg) :: args))
- when List.for_all (fun kid -> is_bound kid env) (KidSet.elements (typ_frees typ)) ->
- begin
- let carg = crule check_exp env arg typ in
- let (iargs, ret_typ', env) = instantiate env quants (utyps, typs) ret_typ (uargs, args) in
- ((n, carg) :: iargs, ret_typ', env)
- end
- | (utyps, (typ :: typs)), (uargs, ((n, arg) :: args)) ->
- begin
- typ_debug (lazy ("INSTANTIATE: " ^ string_of_exp arg ^ " with " ^ string_of_typ typ));
- let iarg = irule infer_exp env arg in
- typ_debug (lazy ("INFER: " ^ string_of_exp arg ^ " type " ^ string_of_typ (typ_of iarg)));
- try
- (* If we get an existential when instantiating, we prepend
- the identifier of the exisitential with the tag argN# to
- denote that it was bound by the Nth argument to the
- function. *)
- let ex_tag = "arg" ^ string_of_int n ^ "#" in
- let iarg, (unifiers, ex_kids, ex_nc) = type_coercion_unify env iarg typ in
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
- typ_debug (lazy ("EX KIDS: " ^ string_of_list ", " string_of_kid ex_kids));
- let env = match ex_kids, ex_nc with
- | [], None -> env
- | _, Some enc ->
- let enc = List.fold_left (fun nc kid -> nc_subst_nexp kid (Nexp_var (prepend_kid ex_tag kid)) nc) enc ex_kids in
- let env = List.fold_left (fun env kid -> Env.add_typ_var l (prepend_kid ex_tag kid) BK_int env) env ex_kids in
- Env.add_constraint enc env
- | _, None -> assert false (* Cannot have ex_kids without ex_nc *)
- in
- let tag_unifier uvar = List.fold_left (fun uvar kid -> uvar_subst_nexp kid (Nexp_var (prepend_kid ex_tag kid)) uvar) uvar ex_kids in
- let unifiers = KBindings.map tag_unifier unifiers in
- record_unifiers unifiers;
- let utyps' = List.map (subst_unifiers unifiers) utyps in
- let typs' = List.map (subst_unifiers unifiers) typs in
- let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
- let ret_typ' = subst_unifiers unifiers ret_typ in
- let (iargs, ret_typ'', env) = instantiate env quants' (utyps', typs') ret_typ' (uargs, args) in
- ((n, iarg) :: iargs, ret_typ'', env)
- with
- | Unification_error (l, str) ->
- typ_print (lazy ("Unification error: " ^ str));
- instantiate env quants (typ :: utyps, typs) ret_typ ((n, arg) :: uargs, args)
- end
- | (_, []), _ -> typ_error l ("Function " ^ string_of_id f ^ " applied to too many arguments")
- | _, (_, []) -> typ_error l ("Function " ^ string_of_id f ^ " not applied to enough arguments")
- in
- let instantiate_ret env quants typs ret_typ =
- match ret_ctx_typ with
- | None -> (quants, typs, ret_typ, env)
- | Some rct when is_exist (Env.expand_synonyms env rct) -> (quants, typs, ret_typ, env)
- | Some rct ->
- begin
- typ_debug (lazy ("RCT is " ^ string_of_typ rct));
- typ_debug (lazy ("INSTANTIATE RETURN:" ^ string_of_typ ret_typ));
- let unifiers, ex_kids, ex_nc =
- try unify l env ret_typ rct with
- | Unification_error _ -> typ_debug (lazy "UERROR"); KBindings.empty, [], None
- in
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
- if ex_kids = [] then () else (typ_debug (lazy ("EX GOAL: " ^ string_of_option string_of_n_constraint ex_nc)); ex_goal := ex_nc);
- record_unifiers unifiers;
- let env = List.fold_left (fun env kid -> Env.add_typ_var l kid BK_int env) env ex_kids in
- let typs' = List.map (subst_unifiers unifiers) typs in
- let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
- let ret_typ' =
- match ex_nc with
- | None -> subst_unifiers unifiers ret_typ
- | Some nc -> mk_typ (Typ_exist (ex_kids, nc, subst_unifiers unifiers ret_typ))
- in
- (quants', typs', ret_typ', env)
- end
- in
+
let quants, typ_args, typ_ret, eff =
match Env.expand_synonyms env f_typ with
- | Typ_aux (Typ_fn (typ_args, typ_ret, eff), _) -> quant_items typq, typ_args, typ_ret, eff
+ | Typ_aux (Typ_fn (typ_args, typ_ret, eff), _) -> ref (quant_items typq), typ_args, ref typ_ret, eff
| _ -> typ_error l (string_of_typ f_typ ^ " is not a function type")
in
- let unifiers = instantiate_simple_equations quants in
+
+ let unifiers = instantiate_simple_equations !quants in
typ_debug (lazy "Instantiating from equations");
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers))); all_unifiers := unifiers;
+ typ_debug (lazy (string_of_list ", " (fun (kid, arg) -> string_of_kid kid ^ " => " ^ string_of_typ_arg arg) (KBindings.bindings unifiers)));
+ all_unifiers := unifiers;
let typ_args = List.map (subst_unifiers unifiers) typ_args in
- let quants = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
- let typ_ret = subst_unifiers unifiers typ_ret in
- let quants, typ_args, typ_ret, env =
- instantiate_ret env quants typ_args typ_ret
+ List.iter (fun unifier -> quants := instantiate_quants !quants unifier) (KBindings.bindings unifiers);
+ List.iter (fun (v, arg) -> typ_ret := typ_subst v arg !typ_ret) (KBindings.bindings unifiers);
+
+ typ_debug (lazy ("Quantifiers " ^ Util.string_of_list ", " string_of_quant_item !quants));
+
+ if not (List.length typ_args = List.length xs) then
+ typ_error l (Printf.sprintf "Function %s applied to %d args, expected %d" (string_of_id f) (List.length xs) (List.length typ_args))
+ else ();
+
+ let instantiate_quant (v, arg) (QI_aux (aux, l) as qi) =
+ match aux with
+ | QI_id kopt when Kid.compare (kopt_kid kopt) v = 0 -> None
+ | QI_id _ -> Some qi
+ | QI_const nc -> Some (QI_aux (QI_const (constraint_subst v arg nc), l))
+ in
+
+ let typ_args = match expected_ret_typ with
+ | None -> typ_args
+ | Some expect when is_exist (Env.expand_synonyms env expect) || is_exist !typ_ret -> typ_args
+ | Some expect ->
+ let goals = quant_kopts (mk_typquant !quants) |> List.map kopt_kid |> KidSet.of_list in
+ try
+ let unifiers = unify l env goals !typ_ret expect in
+ record_unifiers unifiers;
+ let unifiers = KBindings.bindings unifiers in
+ typ_debug (lazy (Util.("Unifiers " |> magenta |> clear)
+ ^ Util.string_of_list ", " (fun (v, arg) -> string_of_kid v ^ " => " ^ string_of_typ_arg arg) unifiers));
+ List.iter (fun unifier -> quants := instantiate_quants !quants unifier) unifiers;
+ List.iter (fun (v, arg) -> typ_ret := typ_subst v arg !typ_ret) unifiers;
+ List.map (fun typ -> List.fold_left (fun typ (v, arg) -> typ_subst v arg typ) typ unifiers) typ_args
+ with Unification_error _ -> typ_args
+ in
+
+ (* We now iterate throught the function arguments, checking them and
+ instantiating quantifiers. *)
+ let instantiate env arg typ remaining_typs =
+ if KidSet.for_all (is_bound env) (tyvars_of_typ typ) then
+ crule check_exp env arg typ, remaining_typs, env
+ else
+ let goals = quant_kopts (mk_typquant !quants) |> List.map kopt_kid |> KidSet.of_list in
+ typ_debug (lazy ("Quantifiers " ^ Util.string_of_list ", " string_of_quant_item !quants));
+ let inferred_arg = irule infer_exp env arg in
+ let inferred_arg, unifiers, env =
+ try type_coercion_unify env goals inferred_arg typ with
+ | Unification_error (l, m) -> typ_error l m
+ in
+ record_unifiers unifiers;
+ let unifiers = KBindings.bindings unifiers in
+ typ_debug (lazy (Util.("Unifiers " |> magenta |> clear)
+ ^ Util.string_of_list ", " (fun (v, arg) -> string_of_kid v ^ " => " ^ string_of_typ_arg arg) unifiers));
+ List.iter (fun unifier -> quants := instantiate_quants !quants unifier) unifiers;
+ List.iter (fun (v, arg) -> typ_ret := typ_subst v arg !typ_ret) unifiers;
+ let remaining_typs =
+ List.map (fun typ -> List.fold_left (fun typ (v, arg) -> typ_subst v arg typ) typ unifiers) remaining_typs
+ in
+ inferred_arg, remaining_typs, env
+ in
+ let fold_instantiate (xs, args, env) x =
+ match args with
+ | arg :: remaining_args ->
+ let x, remaining_args, env = instantiate env x arg remaining_args in
+ (x :: xs, remaining_args, env)
+ | [] -> raise (Reporting.err_unreachable l __POS__ "Empty arguments during instantiation")
in
- let (xs_instantiated, typ_ret, env) = instantiate env quants ([], typ_args) typ_ret ([], number 0 xs) in
- let xs_reordered = List.map snd (List.sort (fun (n, _) (m, _) -> compare n m) xs_instantiated) in
+ let xs, _, env = List.fold_left fold_instantiate ([], typ_args, env) xs in
+ let xs = List.rev xs in
- prove_goal env;
+ if not (List.for_all (solve_quant env) !quants) then
+ typ_raise l (Err_unresolved_quants (f, !quants, Env.get_locals env, Env.get_constraints env))
+ else ();
- let ty_vars = List.map fst (KBindings.bindings (Env.get_typ_vars env)) in
- let existentials = List.filter (fun kid -> not (KBindings.mem kid universals)) ty_vars in
+ let ty_vars = KBindings.bindings (Env.get_typ_vars env) |> List.map (fun (v, k) -> mk_kopt k v) in
+ let existentials = List.filter (fun kopt -> not (KBindings.mem (kopt_kid kopt) universals)) ty_vars in
let num_new_ncs = List.length (Env.get_constraints env) - List.length universal_constraints in
- let ex_constraints = take num_new_ncs (Env.get_constraints env) in
+ let ex_constraints = take num_new_ncs (Env.get_constraints env) in
- typ_debug (lazy ("Existentials: " ^ string_of_list ", " string_of_kid existentials));
+ typ_debug (lazy ("Existentials: " ^ string_of_list ", " string_of_kinded_id existentials));
typ_debug (lazy ("Existential constraints: " ^ string_of_list ", " string_of_n_constraint ex_constraints));
+ let universals = KBindings.bindings universals |> List.map fst |> KidSet.of_list in
let typ_ret =
- if KidSet.is_empty (KidSet.of_list existentials) || KidSet.is_empty (typ_frees typ_ret)
- then (typ_debug (lazy "Returning Existential"); typ_ret)
- else mk_typ (Typ_exist (existentials, List.fold_left nc_and nc_true ex_constraints, typ_ret))
+ if KidSet.is_empty (KidSet.of_list (List.map kopt_kid existentials)) || KidSet.is_empty (KidSet.diff (typ_frees !typ_ret) universals)
+ then !typ_ret
+ else mk_typ (Typ_exist (existentials, List.fold_left nc_and nc_true ex_constraints, !typ_ret))
in
let typ_ret = simp_typ typ_ret in
- let exp = annot_exp (E_app (f, xs_reordered)) typ_ret eff in
- typ_debug (lazy ("RETURNING: " ^ string_of_typ (typ_of exp)));
- match ret_ctx_typ with
- | None ->
- exp, !all_unifiers
- | Some rct ->
- let exp = type_coercion env exp rct in
- typ_debug (lazy ("RETURNING AFTER COERCION " ^ string_of_typ (typ_of exp)));
- exp, !all_unifiers
+ let exp = annot_exp (E_app (f, xs)) typ_ret eff in
+ typ_debug (lazy ("Returning: " ^ string_of_exp exp));
+
+ exp, !all_unifiers
and bind_mpat allow_unknown other_env env (MP_aux (mpat_aux, (l, ())) as mpat) (Typ_aux (typ_aux, _) as typ) =
let (Typ_aux (typ_aux, _) as typ), env = bind_existential l typ env in
@@ -3581,7 +3381,7 @@ and bind_mpat allow_unknown other_env env (MP_aux (mpat_aux, (l, ())) as mpat) (
if Env.is_union_constructor v env then
Util.warn (Printf.sprintf "Identifier %s found in mapping-pattern is also a union constructor at %s\n"
(string_of_id v)
- (Reporting_basic.loc_to_string l))
+ (Reporting.loc_to_string l))
else ();
match Env.lookup_id v env with
| Local (Immutable, _) | Unbound -> annot_mpat (MP_id v) typ, Env.add_local v (Immutable, typ) env, []
@@ -3592,7 +3392,7 @@ and bind_mpat allow_unknown other_env env (MP_aux (mpat_aux, (l, ())) as mpat) (
| MP_cons (hd_mpat, tl_mpat) ->
begin
match Env.expand_synonyms env typ with
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
+ | Typ_aux (Typ_app (f, [A_aux (A_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
let hd_mpat, env, hd_guards = bind_mpat allow_unknown other_env env hd_mpat ltyp in
let tl_mpat, env, tl_guards = bind_mpat allow_unknown other_env env tl_mpat typ in
annot_mpat (MP_cons (hd_mpat, tl_mpat)) typ, env, hd_guards @ tl_guards
@@ -3616,7 +3416,7 @@ and bind_mpat allow_unknown other_env env (MP_aux (mpat_aux, (l, ())) as mpat) (
| MP_list mpats ->
begin
match Env.expand_synonyms env typ with
- | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
+ | Typ_aux (Typ_app (f, [A_aux (A_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
let rec process_mpats env = function
| [] -> [], env, []
| (pat :: mpats) ->
@@ -3659,10 +3459,9 @@ and bind_mpat allow_unknown other_env env (MP_aux (mpat_aux, (l, ())) as mpat) (
begin
try
typ_debug (lazy ("Unifying " ^ string_of_bind (typq, ctor_typ) ^ " for mapping-pattern " ^ string_of_typ typ));
- let unifiers, _, _ (* FIXME! *) = unify l env ret_typ typ in
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
+ let unifiers = unify l env (tyvars_of_typ ret_typ) ret_typ typ in
let arg_typ' = subst_unifiers unifiers arg_typ in
- let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
+ let quants' = List.fold_left instantiate_quants quants (KBindings.bindings unifiers) in
if (match quants' with [] -> false | _ -> true)
then typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants' ^ " not resolved in mapping-pattern " ^ string_of_mpat mpat)
else ();
@@ -3690,10 +3489,9 @@ and bind_mpat allow_unknown other_env env (MP_aux (mpat_aux, (l, ())) as mpat) (
begin
try
typ_debug (lazy ("Unifying " ^ string_of_bind (typq, mapping_typ) ^ " for mapping-pattern " ^ string_of_typ typ));
- let unifiers, _, _ (* FIXME! *) = unify l env typ2 typ in
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
+ let unifiers = unify l env (tyvars_of_typ typ2) typ2 typ in
let arg_typ' = subst_unifiers unifiers typ1 in
- let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
+ let quants' = List.fold_left instantiate_quants quants (KBindings.bindings unifiers) in
if (match quants' with [] -> false | _ -> true)
then typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants' ^ " not resolved in mapping-pattern " ^ string_of_mpat mpat)
else ();
@@ -3708,10 +3506,9 @@ and bind_mpat allow_unknown other_env env (MP_aux (mpat_aux, (l, ())) as mpat) (
try
typ_debug (lazy "Unifying mapping forwards failed, trying backwards.");
typ_debug (lazy ("Unifying " ^ string_of_bind (typq, mapping_typ) ^ " for mapping-pattern " ^ string_of_typ typ));
- let unifiers, _, _ (* FIXME! *) = unify l env typ1 typ in
- typ_debug (lazy (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers)));
+ let unifiers = unify l env (tyvars_of_typ typ1) typ1 typ in
let arg_typ' = subst_unifiers unifiers typ2 in
- let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
+ let quants' = List.fold_left instantiate_quants quants (KBindings.bindings unifiers) in
if (match quants' with [] -> false | _ -> true)
then typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants' ^ " not resolved in mapping-pattern " ^ string_of_mpat mpat)
else ();
@@ -3844,7 +3641,7 @@ and infer_mpat allow_unknown other_env env (MP_aux (mpat_aux, (l, ())) as mpat)
typ_error l ("Couldn't infer type of mapping-pattern " ^ string_of_mpat mpat)
(**************************************************************************)
-(* 6. Effect system *)
+(* 5. Effect system *)
(**************************************************************************)
let effect_of_annot = function
@@ -3942,14 +3739,14 @@ and propagate_exp_effect_aux = function
let p_cases = List.map propagate_pexp_effect cases in
let case_eff = List.fold_left union_effects no_effect (List.map snd p_cases) in
E_case (p_exp, List.map fst p_cases), union_effects (effect_of p_exp) case_eff
- | E_record_update (exp, FES_aux (FES_Fexps (fexps, flag), (l, _))) ->
+ | E_record_update (exp, fexps) ->
let p_exp = propagate_exp_effect exp in
let p_fexps = List.map propagate_fexp_effect fexps in
- E_record_update (p_exp, FES_aux (FES_Fexps (List.map fst p_fexps, flag), (l, None))),
+ E_record_update (p_exp, List.map fst p_fexps),
List.fold_left union_effects no_effect (effect_of p_exp :: List.map snd p_fexps)
- | E_record (FES_aux (FES_Fexps (fexps, flag), (l, _))) ->
+ | E_record fexps ->
let p_fexps = List.map propagate_fexp_effect fexps in
- E_record (FES_aux (FES_Fexps (List.map fst p_fexps, flag), (l, None))),
+ E_record (List.map fst p_fexps),
List.fold_left union_effects no_effect (List.map snd p_fexps)
| E_try (exp, cases) ->
let p_exp = propagate_exp_effect exp in
@@ -4288,7 +4085,7 @@ let check_mapcl : 'a. Env.t -> 'a mapcl -> typ -> tannot mapcl =
MCL_aux (MCL_backwards (typed_mpexp, typed_exp), (l, Some ((env, typ, prop_effs), Some typ)))
end
end
- | _ -> typ_error l ("Mapping clause must have mapping type: " ^ string_of_typ typ ^ " is not a mapping type")
+ | _ -> typ_error l ("Mapping clause must have mapping type: " ^ string_of_typ typ ^ " is not a mapping type")
let funcl_effect (FCL_aux (FCL_Funcl (id, typed_pexp), (l, annot))) =
match annot with
@@ -4357,7 +4154,7 @@ let check_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls)
| Some id -> id
| None -> typ_error l "funcl list is empty"
in
- typ_print (lazy ("\nChecking function " ^ string_of_id id));
+ typ_print (lazy ("\n" ^ Util.("Check function " |> cyan |> clear) ^ string_of_id id));
let have_val_spec, (quant, typ), env =
try true, Env.get_val_spec id env, env with
| Type_error (l, _) ->
@@ -4366,11 +4163,21 @@ let check_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls)
in
let vtyp_args, vtyp_ret, declared_eff, vl = match typ with
| Typ_aux (Typ_fn (vtyp_args, vtyp_ret, declared_eff), vl) -> vtyp_args, vtyp_ret, declared_eff, vl
- | _ -> typ_error l "Function val spec was not a function type"
+ | _ -> typ_error l "Function val spec is not a function type"
in
check_tannotopt env quant vtyp_ret tannotopt;
typ_debug (lazy ("Checking fundef " ^ string_of_id id ^ " has type " ^ string_of_bind (quant, typ)));
let funcl_env = add_typquant l quant env in
+ let recopt =
+ match recopt with
+ | Rec_aux (Rec_nonrec, l) -> Rec_aux (Rec_nonrec, l)
+ | Rec_aux (Rec_rec, l) -> Rec_aux (Rec_rec, l)
+ | Rec_aux (Rec_measure (measure_p, measure_e), l) ->
+ let typ = match vtyp_args with [x] -> x | _ -> Typ_aux (Typ_tup vtyp_args,Unknown) in
+ let tpat, env = bind_pat_no_guard funcl_env (strip_pat measure_p) typ in
+ let texp = check_exp env (strip_exp measure_e) int_typ in
+ Rec_aux (Rec_measure (tpat, texp), l)
+ in
let funcls = List.map (fun funcl -> check_funcl funcl_env funcl typ) funcls in
let eff = List.fold_left union_effects no_effect (List.map funcl_effect funcls) in
let vs_def, env, declared_eff =
@@ -4424,7 +4231,6 @@ let check_mapdef env (MD_aux (MD_mapping (id, tannot_opt, mapcls), (l, _)) as md
else
typ_error l ("Mapping not pure (or escape only): " ^ string_of_effect eff ^ " found")
-
(* Checking a val spec simply adds the type as a binding in the
context. We have to destructure the various kinds of val specs, but
the difference is irrelevant for the typechecker. *)
@@ -4433,13 +4239,14 @@ let check_val_spec env (VS_aux (vs, (l, _))) =
let vs, id, typq, typ, env = match vs with
| VS_val_spec (TypSchm_aux (TypSchm_ts (typq, typ), ts_l) as typschm, id, exts, is_cast) ->
typ_print (lazy (Util.("Check val spec " |> cyan |> clear) ^ string_of_id id ^ " : " ^ string_of_typschm typschm));
- let env = match (Ast_util.extern_assoc "smt" exts, Ast_util.extern_assoc "#" exts) with
- | Some op, None -> Env.add_smt_op id op env
- | _, _ -> env
- in
let env = Env.add_extern id exts env in
let env = if is_cast then Env.add_cast id env else env in
- let typq, typ = expand_bind_synonyms ts_l env (typq, typ) in
+ let typq, typ =
+ if !opt_expand_valspec then
+ expand_bind_synonyms ts_l env (typq, typ)
+ else
+ (typq, typ)
+ in
let vs = VS_val_spec (TypSchm_aux (TypSchm_ts (typq, typ), ts_l), id, exts, is_cast) in
(vs, id, typq, typ, env)
in
@@ -4457,15 +4264,16 @@ let check_default env (DT_aux (ds, l)) =
| DT_order (Ord_aux (Ord_var _, _)) -> typ_error l "Cannot have variable default order"
let kinded_id_arg kind_id =
- let typ_arg arg = Typ_arg_aux (arg, Parse_ast.Unknown) in
+ let typ_arg arg = A_aux (arg, Parse_ast.Unknown) in
match kind_id with
- | KOpt_aux (KOpt_none kid, _) -> typ_arg (Typ_arg_nexp (nvar kid))
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_int, _)], _), kid), _) -> typ_arg (Typ_arg_nexp (nvar kid))
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_order, _)], _), kid), _) ->
- typ_arg (Typ_arg_order (Ord_aux (Ord_var kid, Parse_ast.Unknown)))
- | KOpt_aux (KOpt_kind (K_aux (K_kind [BK_aux (BK_type, _)], _), kid), _) ->
- typ_arg (Typ_arg_typ (mk_typ (Typ_var kid)))
- | KOpt_aux (KOpt_kind (K_aux (K_kind kinds, _), kid), l) -> typ_error l "Badly formed kind"
+ | KOpt_aux (KOpt_kind (K_aux (K_int, _), kid), _) ->
+ typ_arg (A_nexp (nvar kid))
+ | KOpt_aux (KOpt_kind (K_aux (K_order, _), kid), _) ->
+ typ_arg (A_order (Ord_aux (Ord_var kid, Parse_ast.Unknown)))
+ | KOpt_aux (KOpt_kind (K_aux (K_type, _), kid), _) ->
+ typ_arg (A_typ (mk_typ (Typ_var kid)))
+ | KOpt_aux (KOpt_kind (K_aux (K_bool, _), kid), _) ->
+ typ_arg (A_bool (nc_var kid))
let fold_union_quant quants (QI_aux (qi, l)) =
match qi with
@@ -4476,7 +4284,7 @@ let check_type_union env variant typq (Tu_aux (tu, l)) =
let ret_typ = app_typ variant (List.fold_left fold_union_quant [] (quant_items typq)) in
match tu with
| Tu_ty_id (Typ_aux (Typ_fn (arg_typ, ret_typ, _), _) as typ, v) ->
- let typq = mk_typquant (List.map (mk_qi_id BK_type) (KidSet.elements (typ_frees typ))) in
+ let typq = mk_typquant (List.map (mk_qi_id K_type) (KidSet.elements (typ_frees typ))) in
env
|> Env.add_union_id v (typq, typ)
|> Env.add_val_spec v (typq, typ)
@@ -4487,46 +4295,53 @@ let check_type_union env variant typq (Tu_aux (tu, l)) =
|> Env.add_val_spec v (typq, typ')
(* FIXME: This code is duplicated with general kind-checking code in environment, can they be merged? *)
-let mk_synonym typq typ =
+let mk_synonym typq typ_arg =
let kopts, ncs = quant_split typq in
+ let kopts = List.map (fun kopt -> kopt, fresh_existential (unaux_kind (kopt_kind kopt))) kopts in
+ let ncs = List.map (fun nc -> List.fold_left (fun nc (kopt, fresh) -> constraint_subst (kopt_kid kopt) (arg_kopt fresh) nc) nc kopts) ncs in
+ let typ_arg = List.fold_left (fun typ_arg (kopt, fresh) -> typ_arg_subst (kopt_kid kopt) (arg_kopt fresh) typ_arg) typ_arg kopts in
+ let kopts = List.map snd kopts in
let rec subst_args kopts args =
match kopts, args with
- | kopt :: kopts, Typ_arg_aux (Typ_arg_nexp arg, _) :: args when is_nat_kopt kopt ->
- let typ, ncs = subst_args kopts args in
- typ_subst_nexp (kopt_kid kopt) (unaux_nexp arg) typ,
- List.map (nc_subst_nexp (kopt_kid kopt) (unaux_nexp arg)) ncs
- | kopt :: kopts, Typ_arg_aux (Typ_arg_typ arg, _) :: args when is_typ_kopt kopt ->
- let typ, ncs = subst_args kopts args in
- typ_subst_typ (kopt_kid kopt) (unaux_typ arg) typ, ncs
- | kopt :: kopts, Typ_arg_aux (Typ_arg_order arg, _) :: args when is_order_kopt kopt ->
- let typ, ncs = subst_args kopts args in
- typ_subst_order (kopt_kid kopt) (unaux_order arg) typ, ncs
- | [], [] -> typ, ncs
- | _, Typ_arg_aux (_, l) :: _ -> typ_error l "Synonym applied to bad arguments"
+ | kopt :: kopts, A_aux (A_nexp arg, _) :: args when is_nat_kopt kopt ->
+ let typ_arg, ncs = subst_args kopts args in
+ typ_arg_subst (kopt_kid kopt) (arg_nexp arg) typ_arg,
+ List.map (constraint_subst (kopt_kid kopt) (arg_nexp arg)) ncs
+ | kopt :: kopts, A_aux (A_typ arg, _) :: args when is_typ_kopt kopt ->
+ let typ_arg, ncs = subst_args kopts args in
+ typ_arg_subst (kopt_kid kopt) (arg_typ arg) typ_arg, ncs
+ | kopt :: kopts, A_aux (A_order arg, _) :: args when is_order_kopt kopt ->
+ let typ_arg, ncs = subst_args kopts args in
+ typ_arg_subst (kopt_kid kopt) (arg_order arg) typ_arg, ncs
+ | kopt :: kopts, A_aux (A_bool arg, _) :: args when is_bool_kopt kopt ->
+ let typ_arg, ncs = subst_args kopts args in
+ typ_arg_subst (kopt_kid kopt) (arg_bool arg) typ_arg, ncs
+ | [], [] -> typ_arg, ncs
+ | _, A_aux (_, l) :: _ -> typ_error l "Synonym applied to bad arguments"
| _, _ -> typ_error Parse_ast.Unknown "Synonym applied to bad arguments"
in
fun env args ->
- let typ, ncs = subst_args kopts args in
+ let typ_arg, ncs = subst_args kopts args in
if List.for_all (prove env) ncs
- then typ
+ then typ_arg
else typ_error Parse_ast.Unknown ("Could not prove constraints " ^ string_of_list ", " string_of_n_constraint ncs
- ^ " in type synonym " ^ string_of_typ typ
+ ^ " in type synonym " ^ string_of_typ_arg typ_arg
^ " with " ^ string_of_list ", " string_of_n_constraint (Env.get_constraints env))
let check_kinddef env (KD_aux (kdef, (l, _))) =
- let kd_err () = raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__ "Unimplemented kind def") in
+ let kd_err () = raise (Reporting.err_unreachable Parse_ast.Unknown __POS__ "Unimplemented kind def") in
match kdef with
- | KD_nabbrev ((K_aux(K_kind([BK_aux (BK_int, _)]),_) as kind), id, nmscm, nexp) ->
+ | KD_nabbrev (K_aux (K_int, _) as kind, id, nmscm, nexp) ->
[DEF_kind (KD_aux (KD_nabbrev (kind, id, nmscm, nexp), (l, None)))],
Env.add_num_def id nexp env
| _ -> kd_err ()
let rec check_typedef : 'a. Env.t -> 'a type_def -> (tannot def) list * Env.t =
fun env (TD_aux (tdef, (l, _))) ->
- let td_err () = raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__ "Unimplemented Typedef") in
+ let td_err () = raise (Reporting.err_unreachable Parse_ast.Unknown __POS__ "Unimplemented Typedef") in
match tdef with
- | TD_abbrev (id, nmscm, (TypSchm_aux (TypSchm_ts (typq, typ), _))) ->
- [DEF_type (TD_aux (tdef, (l, None)))], Env.add_typ_synonym id (mk_synonym typq typ) env
+ | TD_abbrev (id, typq, typ_arg) ->
+ [DEF_type (TD_aux (tdef, (l, None)))], Env.add_typ_synonym id (mk_synonym typq typ_arg) env
| TD_record (id, nmscm, typq, fields, _) ->
[DEF_type (TD_aux (tdef, (l, None)))], Env.add_record id typq fields env
| TD_variant (id, nmscm, typq, arms, _) ->
@@ -4543,9 +4358,9 @@ let rec check_typedef : 'a. Env.t -> 'a type_def -> (tannot def) list * Env.t =
begin
match typ with
(* The type of a bitfield must be a constant-width bitvector *)
- | Typ_aux (Typ_app (v, [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant size, _)), _);
- Typ_arg_aux (Typ_arg_order order, _);
- Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id b, _)), _)]), _)
+ | Typ_aux (Typ_app (v, [A_aux (A_nexp (Nexp_aux (Nexp_constant size, _)), _);
+ A_aux (A_order order, _);
+ A_aux (A_typ (Typ_aux (Typ_id b, _)), _)]), _)
when string_of_id v = "vector" && string_of_id b = "bit" ->
let size = Big_int.to_int size in
let (Defs defs), env = check env (Bitfield.macro id size order ranges) in
@@ -4554,19 +4369,37 @@ let rec check_typedef : 'a. Env.t -> 'a type_def -> (tannot def) list * Env.t =
typ_error l "Bad bitfield type"
end
+and check_scattered : 'a. Env.t -> 'a scattered_def -> (tannot def) list * Env.t =
+ fun env (SD_aux (sdef, (l, _))) ->
+ match sdef with
+ | SD_function _ | SD_end _ | SD_mapping _ -> [], env
+ | SD_variant (id, namescm, typq) ->
+ [DEF_scattered (SD_aux (SD_variant (id, namescm, typq), (l, None)))], Env.add_scattered_variant id typq env
+ | SD_unioncl (id, tu) ->
+ [DEF_scattered (SD_aux (SD_unioncl (id, tu), (l, None)))],
+ let env = Env.add_variant_clause id tu env in
+ let typq, _ = Env.get_variant id env in
+ check_type_union env id typq tu
+ | SD_funcl (FCL_aux (FCL_Funcl (id, _), (l, _)) as funcl) ->
+ let typq, typ = Env.get_val_spec id env in
+ let funcl_env = add_typquant l typq env in
+ let funcl = check_funcl funcl_env funcl typ in
+ [DEF_scattered (SD_aux (SD_funcl funcl, (l, None)))], env
+ | SD_mapcl (id, mapcl) ->
+ let typq, typ = Env.get_val_spec id env in
+ let mapcl_env = add_typquant l typq env in
+ let mapcl = check_mapcl mapcl_env mapcl typ in
+ [DEF_scattered (SD_aux (SD_mapcl (id, mapcl), (l, None)))], env
+
and check_def : 'a. Env.t -> 'a def -> (tannot def) list * Env.t =
fun env def ->
- let cd_err () = raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__ "Unimplemented Case") in
+ let cd_err () = raise (Reporting.err_unreachable Parse_ast.Unknown __POS__ "Unimplemented Case") in
match def with
| DEF_kind kdef -> check_kinddef env kdef
| DEF_type tdef -> check_typedef env tdef
| DEF_fixity (prec, n, op) -> [DEF_fixity (prec, n, op)], env
| DEF_fundef fdef -> check_fundef env fdef
| DEF_mapdef mdef -> check_mapdef env mdef
- | DEF_constraint (id, kids, nc) when !opt_constraint_synonyms ->
- [], Env.add_constraint_synonym id kids nc env
- | DEF_constraint (id, _, _) ->
- typ_error (id_loc id) "Use -Xconstraint_synonyms to enable constraint synonyms"
| DEF_internal_mutrec fdefs ->
let defs = List.concat (List.map (fun fdef -> fst (check_fundef env fdef)) fdefs) in
let split_fundef (defs, fdefs) def = match def with
@@ -4585,9 +4418,10 @@ and check_def : 'a. Env.t -> 'a def -> (tannot def) list * Env.t =
let checked_exp = crule check_exp env (strip_exp exp) typ in
let env = Env.add_register id no_effect (mk_effect [BE_config]) typ env in
[DEF_reg_dec (DEC_aux (DEC_config (id, typ, checked_exp), (l, Some ((env, typ, no_effect), Some typ))))], env
+ | DEF_pragma (pragma, arg, l) -> [DEF_pragma (pragma, arg, l)], env
| DEF_reg_dec (DEC_aux (DEC_alias (id, aspec), (l, annot))) -> cd_err ()
| DEF_reg_dec (DEC_aux (DEC_typ_alias (typ, id, aspec), (l, tannot))) -> cd_err ()
- | DEF_scattered _ -> raise (Reporting_basic.err_unreachable Parse_ast.Unknown __POS__ "Scattered given to type checker")
+ | DEF_scattered sdef -> check_scattered env sdef
and check : 'a. Env.t -> 'a defs -> tannot defs * Env.t =
fun env (Defs defs) ->
@@ -4610,13 +4444,13 @@ let initial_env =
|> Env.add_extern (mk_id "size_itself_int") [("_", "size_itself_int")]
|> Env.add_val_spec (mk_id "size_itself_int")
- (TypQ_aux (TypQ_tq [QI_aux (QI_id (KOpt_aux (KOpt_none (mk_kid "n"),Parse_ast.Unknown)),
+ (TypQ_aux (TypQ_tq [QI_aux (QI_id (mk_kopt K_int (mk_kid "n")),
Parse_ast.Unknown)],Parse_ast.Unknown),
- function_typ [app_typ (mk_id "itself") [mk_typ_arg (Typ_arg_nexp (nvar (mk_kid "n")))]]
+ function_typ [app_typ (mk_id "itself") [mk_typ_arg (A_nexp (nvar (mk_kid "n")))]]
(atom_typ (nvar (mk_kid "n"))) no_effect)
|> Env.add_extern (mk_id "make_the_value") [("_", "make_the_value")]
|> Env.add_val_spec (mk_id "make_the_value")
- (TypQ_aux (TypQ_tq [QI_aux (QI_id (KOpt_aux (KOpt_none (mk_kid "n"),Parse_ast.Unknown)),
+ (TypQ_aux (TypQ_tq [QI_aux (QI_id (mk_kopt K_int (mk_kid "n")),
Parse_ast.Unknown)],Parse_ast.Unknown),
function_typ [atom_typ (nvar (mk_kid "n"))]
- (app_typ (mk_id "itself") [mk_typ_arg (Typ_arg_nexp (nvar (mk_kid "n")))]) no_effect)
+ (app_typ (mk_id "itself") [mk_typ_arg (A_nexp (nvar (mk_kid "n")))]) no_effect)
diff --git a/src/type_check.mli b/src/type_check.mli
index 93f5302a..501a0d7d 100644
--- a/src/type_check.mli
+++ b/src/type_check.mli
@@ -67,23 +67,24 @@ val opt_no_effects : bool ref
assignments in l-expressions. *)
val opt_no_lexp_bounds_check : bool ref
-(** [opt_constraint_synonyms] allows constraint synonyms as toplevel
- definitions *)
-val opt_constraint_synonyms : bool ref
+(** opt_expand_valspec expands typedefs in valspecs during type check.
+ We prefer not to do it for latex output but it is otherwise a good idea. *)
+val opt_expand_valspec : bool ref
(** {2 Type errors} *)
type type_error =
| Err_no_casts of unit exp * typ * typ * type_error * type_error list
| Err_no_overloading of id * (id * type_error) list
- | Err_unresolved_quants of id * quant_item list
+ | Err_unresolved_quants of id * quant_item list * (mut * typ) Bindings.t * n_constraint list
| Err_subtype of typ * typ * n_constraint list * Ast.l KBindings.t
| Err_no_num_ident of id
| Err_other of string
+ | Err_because of type_error * type_error
exception Type_error of l * type_error;;
-val typ_debug : string Lazy.t -> unit
+val typ_debug : ?level:int -> string Lazy.t -> unit
val typ_print : string Lazy.t -> unit
(** {2 Environments} *)
@@ -95,7 +96,7 @@ module Env : sig
type t
(** Note: Most get_ functions assume the identifiers exist, and throw
- type errors if it doesn't. *)
+ type errors if they don't. *)
(** Get the quantifier and type for a function identifier, freshening
type variables. *)
@@ -127,13 +128,13 @@ module Env : sig
val add_constraint : n_constraint -> t -> t
- val get_typ_var : kid -> t -> base_kind_aux
+ val get_typ_var : kid -> t -> kind_aux
- val get_typ_vars : t -> base_kind_aux KBindings.t
+ val get_typ_vars : t -> kind_aux KBindings.t
val get_typ_var_locs : t -> Ast.l KBindings.t
- val add_typ_var : Ast.l -> kid -> base_kind_aux -> t -> t
+ val add_typ_var : Ast.l -> kinded_id -> t -> t
val is_record : id -> t -> bool
@@ -149,7 +150,7 @@ module Env : sig
won't throw any exceptions. *)
val get_ret_typ : t -> typ option
- val get_typ_synonym : id -> t -> (t -> typ_arg list -> typ)
+ val get_typ_synonym : id -> t -> (t -> typ_arg list -> typ_arg)
val get_overloads : id -> t -> id list
@@ -207,9 +208,14 @@ end
an environment *)
val add_typquant : Ast.l -> typquant -> Env.t -> Env.t
-val destruct_exist : Env.t -> typ -> (kid list * n_constraint * typ) option
+(** Safely destructure an existential type. Returns None if the type
+ is not existential. This function will pick a fresh name for the
+ existential to ensure that no name-clashes occur. The "plain"
+ version does not treat numeric types as existentials. *)
+val destruct_exist_plain : typ -> (kinded_id list * n_constraint * typ) option
+val destruct_exist : typ -> (kinded_id list * n_constraint * typ) option
-val add_existential : Ast.l -> kid list -> n_constraint -> Env.t -> Env.t
+val add_existential : Ast.l -> kinded_id list -> n_constraint -> Env.t -> Env.t
(** When the typechecker creates new type variables it gives them
fresh names of the form 'fvXXX#name, where XXX is a number (not
@@ -299,6 +305,8 @@ val prove : Env.t -> n_constraint -> bool
val solve : Env.t -> nexp -> Big_int.num option
+val canonicalize : Env.t -> typ -> typ
+
val subtype_check : Env.t -> typ -> typ -> bool
val bind_pat : Env.t -> unit pat -> typ -> tannot pat * Env.t * unit Ast.exp list
@@ -321,9 +329,8 @@ val env_of_annot : Ast.l * tannot -> Env.t
val typ_of : tannot exp -> typ
val typ_of_annot : Ast.l * tannot -> typ
-
-val pat_typ_of : tannot pat -> typ
-val pat_env_of : tannot pat -> Env.t
+val typ_of_pat : tannot pat -> typ
+val env_of_pat : tannot pat -> Env.t
val typ_of_pexp : tannot pexp -> typ
val env_of_pexp : tannot pexp -> Env.t
@@ -347,44 +354,33 @@ val expected_typ_of : Ast.l * tannot -> typ option
val destruct_atom_nexp : Env.t -> typ -> nexp option
-(** Safely destructure an existential type. Returns None if the type
- is not existential. This function will pick a fresh name for the
- existential to ensure that no name-clashes occur. *)
-val destruct_exist : Env.t -> typ -> (kid list * n_constraint * typ) option
-
val destruct_range : Env.t -> typ -> (kid list * n_constraint * nexp * nexp) option
-val destruct_numeric : Env.t -> typ -> (kid list * n_constraint * nexp) option
+val destruct_numeric : typ -> (kid list * n_constraint * nexp) option
val destruct_vector : Env.t -> typ -> (nexp * order * typ) option
-type uvar =
- | U_nexp of nexp
- | U_order of order
- | U_typ of typ
-
-val string_of_uvar : uvar -> string
-
-val subst_unifiers : uvar KBindings.t -> typ -> typ
-
-val typ_subst_nexp : kid -> nexp_aux -> typ -> typ
-val typ_subst_typ : kid -> typ_aux -> typ -> typ
-val typ_subst_order : kid -> order_aux -> typ -> typ
-val typ_subst_kid : kid -> kid -> typ -> typ
+val subst_unifiers : typ_arg KBindings.t -> typ -> typ
-val unify : l -> Env.t -> typ -> typ -> uvar KBindings.t * kid list * n_constraint option
+(** [unify l env goals typ1 typ2] returns set of typ_arg bindings such
+ that substituting those bindings using every type variable in goals
+ will make typ1 and typ2 equal. Will throw a Unification_error if
+ typ1 and typ2 cannot unification (although unification in Sail is
+ not complete). Will throw a type error if any goals appear in in
+ typ2 (occurs check). *)
+val unify : l -> Env.t -> KidSet.t -> typ -> typ -> typ_arg KBindings.t
val alpha_equivalent : Env.t -> typ -> typ -> bool
(** Throws Invalid_argument if the argument is not a E_app expression *)
-val instantiation_of : tannot exp -> uvar KBindings.t
+val instantiation_of : tannot exp -> typ_arg KBindings.t
(** Doesn't use the type of the expression when calculating instantiations.
May fail if the arguments aren't sufficient to calculate all unifiers. *)
-val instantiation_of_without_type : tannot exp -> uvar KBindings.t
+val instantiation_of_without_type : tannot exp -> typ_arg KBindings.t
(* Type variable instantiations that inference will extract from constraints *)
-val instantiate_simple_equations : quant_item list -> uvar KBindings.t
+val instantiate_simple_equations : quant_item list -> typ_arg KBindings.t
val propagate_exp_effect : tannot exp -> tannot exp
@@ -413,7 +409,7 @@ Some invariants that will hold of a fully checked AST are:
for them to have type annotations.
check throws type_errors rather than Sail generic errors from
- Reporting_basic. For a function that uses generic errors, use
+ Reporting. For a function that uses generic errors, use
Type_error.check *)
val check : Env.t -> 'a defs -> tannot defs * Env.t
diff --git a/src/type_error.ml b/src/type_error.ml
index 78db65bc..9144e993 100644
--- a/src/type_error.ml
+++ b/src/type_error.ml
@@ -58,35 +58,6 @@ let bullet f xs =
group (separate_map hardline (fun x -> string "* " ^^ nest 2 (f x)) xs)
let pp_nexp, pp_n_constraint =
- let rec string_of_nexp = function
- | Nexp_aux (nexp, _) -> string_of_nexp_aux nexp
- and string_of_nexp_aux = function
- | Nexp_id id -> string_of_id id
- | Nexp_var kid -> string_of_kid kid
- | Nexp_constant c -> Big_int.to_string c
- | Nexp_times (n1, n2) -> "(" ^ string_of_nexp n1 ^ " * " ^ string_of_nexp n2 ^ ")"
- | Nexp_sum (n1, n2) -> "(" ^ string_of_nexp n1 ^ " + " ^ string_of_nexp n2 ^ ")"
- | Nexp_minus (n1, n2) -> "(" ^ string_of_nexp n1 ^ " - " ^ string_of_nexp n2 ^ ")"
- | Nexp_app (id, nexps) -> string_of_id id ^ "(" ^ string_of_list ", " string_of_nexp nexps ^ ")"
- | Nexp_exp n -> "2 ^ " ^ string_of_nexp n
- | Nexp_neg n -> "- " ^ string_of_nexp n
- in
-
- let string_of_n_constraint = function
- | NC_aux (NC_equal (n1, n2), _) -> string_of_nexp n1 ^ " = " ^ string_of_nexp n2
- | NC_aux (NC_not_equal (n1, n2), _) -> string_of_nexp n1 ^ " != " ^ string_of_nexp n2
- | NC_aux (NC_bounded_ge (n1, n2), _) -> string_of_nexp n1 ^ " >= " ^ string_of_nexp n2
- | NC_aux (NC_bounded_le (n1, n2), _) -> string_of_nexp n1 ^ " <= " ^ string_of_nexp n2
- | NC_aux (NC_or (nc1, nc2), _) ->
- "(" ^ string_of_n_constraint nc1 ^ " | " ^ string_of_n_constraint nc2 ^ ")"
- | NC_aux (NC_and (nc1, nc2), _) ->
- "(" ^ string_of_n_constraint nc1 ^ " & " ^ string_of_n_constraint nc2 ^ ")"
- | NC_aux (NC_set (kid, ns), _) ->
- string_of_kid kid ^ " in {" ^ string_of_list ", " Big_int.to_string ns ^ "}"
- | NC_aux (NC_true, _) -> "true"
- | NC_aux (NC_false, _) -> "false"
- in
-
let pp_nexp' nexp =
string (string_of_nexp nexp)
in
@@ -94,39 +65,181 @@ let pp_nexp, pp_n_constraint =
let pp_n_constraint' nc =
string (string_of_n_constraint nc)
in
-
pp_nexp', pp_n_constraint'
+let rec nexp_subst sv subst (Nexp_aux (nexp, l)) = Nexp_aux (nexp_subst_aux sv subst nexp, l)
+and nexp_subst_aux sv subst = function
+ | Nexp_id v -> Nexp_id v
+ | Nexp_var kid -> if Kid.compare kid sv = 0 then subst else Nexp_var kid
+ | Nexp_constant c -> Nexp_constant c
+ | Nexp_times (nexp1, nexp2) -> Nexp_times (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
+ | Nexp_sum (nexp1, nexp2) -> Nexp_sum (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
+ | Nexp_minus (nexp1, nexp2) -> Nexp_minus (nexp_subst sv subst nexp1, nexp_subst sv subst nexp2)
+ | Nexp_app (id, nexps) -> Nexp_app (id, List.map (nexp_subst sv subst) nexps)
+ | Nexp_exp nexp -> Nexp_exp (nexp_subst sv subst nexp)
+ | Nexp_neg nexp -> Nexp_neg (nexp_subst sv subst nexp)
+
+let rec nexp_set_to_or l subst = function
+ | [] -> typ_error l "Cannot substitute into empty nexp set"
+ | [int] -> NC_equal (subst, nconstant int)
+ | (int :: ints) -> NC_or (mk_nc (NC_equal (subst, nconstant int)), mk_nc (nexp_set_to_or l subst ints))
+
+let rec nc_subst_nexp sv subst (NC_aux (nc, l)) = NC_aux (nc_subst_nexp_aux l sv subst nc, l)
+and nc_subst_nexp_aux l sv subst = function
+ | NC_equal (n1, n2) -> NC_equal (nexp_subst sv subst n1, nexp_subst sv subst n2)
+ | NC_bounded_ge (n1, n2) -> NC_bounded_ge (nexp_subst sv subst n1, nexp_subst sv subst n2)
+ | NC_bounded_le (n1, n2) -> NC_bounded_le (nexp_subst sv subst n1, nexp_subst sv subst n2)
+ | NC_not_equal (n1, n2) -> NC_not_equal (nexp_subst sv subst n1, nexp_subst sv subst n2)
+ | NC_set (kid, ints) as set_nc ->
+ if Kid.compare kid sv = 0
+ then nexp_set_to_or l (mk_nexp subst) ints
+ else set_nc
+ | NC_or (nc1, nc2) -> NC_or (nc_subst_nexp sv subst nc1, nc_subst_nexp sv subst nc2)
+ | NC_and (nc1, nc2) -> NC_and (nc_subst_nexp sv subst nc1, nc_subst_nexp sv subst nc2)
+ | NC_false -> NC_false
+ | NC_true -> NC_true
+
+type suggestion =
+ | Suggest_add_constraint of n_constraint
+ | Suggest_none
+
+(* Temporary hack while I work on using these suggestions in asl_parser *)
+let rec analyze_unresolved_quant2 locals ncs = function
+ | QI_aux (QI_const nc, _) ->
+ let gen_kids = List.filter is_kid_generated (KidSet.elements (tyvars_of_constraint nc)) in
+ if gen_kids = [] then
+ Suggest_add_constraint nc
+ else
+ (* If there are generated kind-identifiers in the constraint,
+ we don't want to make a suggestion based on them, so try to
+ look for generated kid free nexps in the set of constraints
+ that are equal to the generated identifier. This often
+ occurs due to how the type-checker introduces new type
+ variables. *)
+ let is_subst v = function
+ | NC_aux (NC_equal (Nexp_aux (Nexp_var v', _), nexp), _)
+ when Kid.compare v v' = 0 && not (KidSet.exists is_kid_generated (tyvars_of_nexp nexp)) ->
+ [(v, nexp)]
+ | NC_aux (NC_equal (nexp, Nexp_aux (Nexp_var v', _)), _)
+ when Kid.compare v v' = 0 && not (KidSet.exists is_kid_generated (tyvars_of_nexp nexp)) ->
+ [(v, nexp)]
+ | _ -> []
+ in
+ let substs = List.concat (List.map (fun v -> List.concat (List.map (fun nc -> is_subst v nc) ncs)) gen_kids) in
+ let nc = List.fold_left (fun nc (v, nexp) -> nc_subst_nexp v (unaux_nexp nexp) nc) nc substs in
+ if not (KidSet.exists is_kid_generated (tyvars_of_constraint nc)) then
+ Suggest_add_constraint nc
+ else
+ (* If we have a really anonymous type-variable, try to find a
+ regular variable that corresponds to it. *)
+ let is_linked v = function
+ | (id, (Immutable, (Typ_aux (Typ_app (ty_id, [A_aux (A_nexp (Nexp_aux (Nexp_var v', _)), _)]), _) as typ)))
+ when Id.compare ty_id (mk_id "atom") = 0 && Kid.compare v v' = 0 ->
+ [(v, nid id, typ)]
+ | (id, (mut, typ)) ->
+ []
+ in
+ let substs = List.concat (List.map (fun v -> List.concat (List.map (fun nc -> is_linked v nc) (Bindings.bindings locals))) gen_kids) in
+ let nc = List.fold_left (fun nc (v, nexp, _) -> nc_subst_nexp v (unaux_nexp nexp) nc) nc substs in
+ if not (KidSet.exists is_kid_generated (tyvars_of_constraint nc)) then
+ Suggest_none
+ else
+ Suggest_none
+
+ | QI_aux (QI_id kopt, _) ->
+ Suggest_none
+
+let rec analyze_unresolved_quant locals ncs = function
+ | QI_aux (QI_const nc, _) ->
+ let gen_kids = List.filter is_kid_generated (KidSet.elements (tyvars_of_constraint nc)) in
+ if gen_kids = [] then
+ string ("Try adding the constraint: " ^ string_of_n_constraint nc)
+ else
+ (* If there are generated kind-identifiers in the constraint,
+ we don't want to make a suggestion based on them, so try to
+ look for generated kid free nexps in the set of constraints
+ that are equal to the generated identifier. This often
+ occurs due to how the type-checker introduces new type
+ variables. *)
+ let is_subst v = function
+ | NC_aux (NC_equal (Nexp_aux (Nexp_var v', _), nexp), _)
+ when Kid.compare v v' = 0 && not (KidSet.exists is_kid_generated (tyvars_of_nexp nexp)) ->
+ [(v, nexp)]
+ | NC_aux (NC_equal (nexp, Nexp_aux (Nexp_var v', _)), _)
+ when Kid.compare v v' = 0 && not (KidSet.exists is_kid_generated (tyvars_of_nexp nexp)) ->
+ [(v, nexp)]
+ | _ -> []
+ in
+ let substs = List.concat (List.map (fun v -> List.concat (List.map (fun nc -> is_subst v nc) ncs)) gen_kids) in
+ let nc = List.fold_left (fun nc (v, nexp) -> nc_subst_nexp v (unaux_nexp nexp) nc) nc substs in
+ if not (KidSet.exists is_kid_generated (tyvars_of_constraint nc)) then
+ string ("Try adding the constraint " ^ string_of_n_constraint nc)
+ else
+ (* If we have a really anonymous type-variable, try to find a
+ regular variable that corresponds to it. *)
+ let is_linked v = function
+ | (id, (Immutable, (Typ_aux (Typ_app (ty_id, [A_aux (A_nexp (Nexp_aux (Nexp_var v', _)), _)]), _) as typ)))
+ when Id.compare ty_id (mk_id "atom") = 0 && Kid.compare v v' = 0 ->
+ [(v, nid id, typ)]
+ | (id, (mut, typ)) ->
+ []
+ in
+ let substs = List.concat (List.map (fun v -> List.concat (List.map (fun nc -> is_linked v nc) (Bindings.bindings locals))) gen_kids) in
+ (string "Try adding named type variables for"
+ ^//^ string (Util.string_of_list ", " (fun (_, nexp, typ) -> string_of_nexp nexp ^ " : " ^ string_of_typ typ) substs))
+ ^^ twice hardline ^^
+ let nc = List.fold_left (fun nc (v, nexp, _) -> nc_subst_nexp v (unaux_nexp nexp) nc) nc substs in
+ if not (KidSet.exists is_kid_generated (tyvars_of_constraint nc)) then
+ string ("The property " ^ string_of_n_constraint nc ^ " must hold")
+ else
+ empty
+
+ | QI_aux (QI_id kopt, _) ->
+ empty
+
let rec pp_type_error = function
- | Err_no_casts (exp, typ_from, typ_to, trigger, _) ->
+ | Err_no_casts (exp, typ_from, typ_to, trigger, reasons) ->
let coercion =
group (string "Tried performing type coercion from" ^/^ Pretty_print_sail.doc_typ typ_from
^/^ string "to" ^/^ Pretty_print_sail.doc_typ typ_to
^/^ string "on" ^/^ Pretty_print_sail.doc_exp exp)
in
- coercion ^^ hardline ^^ (string "Failed because" ^/^ pp_type_error trigger)
+ coercion ^^ hardline
+ ^^ (string "Coercion failed because:" ^//^ pp_type_error trigger)
+ ^^ if not (reasons = []) then
+ hardline
+ ^^ (string "Possible reasons:" ^//^ separate_map hardline pp_type_error reasons)
+ else
+ empty
| Err_no_overloading (id, errs) ->
string ("No overloadings for " ^ string_of_id id ^ ", tried:") ^//^
group (separate_map hardline (fun (id, err) -> string (string_of_id id) ^^ colon ^//^ pp_type_error err) errs)
| Err_subtype (typ1, typ2, constrs, locs) ->
- enclose (string (Util.termcode 1)) (string (Util.termcode 21))
- (separate space [ string (string_of_typ typ1);
- string "is not a subtype of";
- string (string_of_typ typ2) ])
+ (separate space [ string (string_of_typ typ1);
+ string "is not a subtype of";
+ string (string_of_typ typ2) ])
^/^ string "in context"
^/^ bullet pp_n_constraint constrs
^/^ string "where"
- ^/^ bullet (fun (kid, l) -> string (string_of_kid kid ^ " bound at " ^ Reporting_basic.loc_to_string l ^ "\n")) (KBindings.bindings locs)
+ ^/^ bullet (fun (kid, l) -> string (string_of_kid kid ^ " bound at " ^ Reporting.loc_to_string l ^ "\n")) (KBindings.bindings locs)
| Err_no_num_ident id ->
string "No num identifier" ^^ space ^^ string (string_of_id id)
- | Err_unresolved_quants (id, quants) ->
- string "Could not resolve quantifiers for" ^^ space ^^ string (string_of_id id)
- ^//^ group (separate_map hardline (fun quant -> string (string_of_quant_item quant)) quants)
+ | Err_unresolved_quants (id, quants, locals, ncs) ->
+ (string "Could not resolve quantifiers for" ^^ space ^^ string (string_of_id id)
+ ^//^ group (separate_map hardline (fun quant -> string (string_of_quant_item quant)) quants))
+ ^^ twice hardline
+ ^^ group (separate_map hardline (analyze_unresolved_quant locals ncs) quants)
+ (* We only got err, because of previous error, err' *)
+ | Err_because (err, err') ->
+ pp_type_error err
+ ^^ hardline ^^ string "This error occured because of a previous error:"
+ ^//^ pp_type_error err'
+
| Err_other str -> string str
let rec string_of_type_error err =
@@ -135,7 +248,25 @@ let rec string_of_type_error err =
ToBuffer.pretty 1. 400 b (pp_type_error err);
"\n" ^ Buffer.contents b
+let rec collapse_errors = function
+ | (Err_no_overloading (_, (err :: errs)) as no_collapse) ->
+ let err = collapse_errors (snd err) in
+ let errs = List.map (fun (_, err) -> collapse_errors err) errs in
+ let fold_equal msg err =
+ match msg, err with
+ | Some msg, Err_no_overloading _ -> Some msg
+ | Some msg, Err_other _ -> Some msg
+ | Some msg, Err_no_casts _ -> Some msg
+ | Some msg, err when msg = string_of_type_error err -> Some msg
+ | _, _ -> None
+ in
+ begin match List.fold_left fold_equal (Some (string_of_type_error err)) errs with
+ | Some _ -> err
+ | None -> no_collapse
+ end
+ | err -> err
+
let check : 'a. Env.t -> 'a defs -> tannot defs * Env.t =
fun env defs ->
try Type_check.check env defs with
- | Type_error (l, err) -> raise (Reporting_basic.err_typ l (string_of_type_error err))
+ | Type_error (l, err) -> raise (Reporting.err_typ l (string_of_type_error err))
diff --git a/src/util.ml b/src/util.ml
index e0366fe7..5e5654d1 100644
--- a/src/util.ml
+++ b/src/util.ml
@@ -232,6 +232,15 @@ let rec option_these = function
| None :: xs -> option_these xs
| [] -> []
+let rec option_all = function
+ | [] -> Some []
+ | None :: _ -> None
+ | Some x :: xs ->
+ begin match option_all xs with
+ | None -> None
+ | Some xs -> Some (x :: xs)
+ end
+
let changed2 f g x h y =
match (g x, h y) with
| (None,None) -> None
@@ -439,6 +448,14 @@ let zencode_string str = "z" ^ List.fold_left (fun s1 s2 -> s1 ^ s2) "" (List.ma
let zencode_upper_string str = "Z" ^ List.fold_left (fun s1 s2 -> s1 ^ s2) "" (List.map zchar (string_to_list str))
+(** Encode string for use as a filename. We can't use zencode directly
+ because some operating systems make the mistake of being
+ case-insensitive. *)
+let file_encode_string str =
+ let zstr = zencode_string str in
+ let md5 = Digest.to_hex (Digest.string zstr) in
+ String.lowercase_ascii zstr ^ String.lowercase_ascii md5
+
let warn str =
if !opt_warnings then
prerr_endline (("Warning" |> yellow |> clear) ^ ": " ^ str)
@@ -446,3 +463,5 @@ let warn str =
let log_line str line msg =
"\n[" ^ (str ^ ":" ^ string_of_int line |> blue |> clear) ^ "] " ^ msg
+
+let header str n = "\n" ^ str ^ "\n" ^ String.make (String.length str - 9 * n) '='
diff --git a/src/util.mli b/src/util.mli
index eb4b4bd2..fd0242a3 100644
--- a/src/util.mli
+++ b/src/util.mli
@@ -57,8 +57,8 @@ val opt_colors : bool ref
val butlast : 'a list -> 'a list
(** Mixed useful things *)
-module Duplicate(S : Set.S) : sig
- type dups =
+module Duplicate(S : Set.S) : sig
+ type dups =
| No_dups of S.t
| Has_dups of S.elt
val duplicates : S.elt list -> dups
@@ -105,6 +105,11 @@ val option_get_exn : exn -> 'a option -> 'a
wrapped in [Some]. *)
val option_these : 'a option list -> 'a list
+(** [option_all xs] extracts the elements of the list [xs] if all of
+ them are wrapped in Some. If any are None then the result is None is
+ None. [option_all []] is [Some []] *)
+val option_all : 'a option list -> 'a list option
+
(** [changed2 f g x h y] applies [g] to [x] and [h] to [y].
If both function applications return [None], then [None] is
returned. Otherwise [f] is applied to the results. For this
@@ -254,4 +259,7 @@ val warn : string -> unit
val zencode_string : string -> string
val zencode_upper_string : string -> string
+val file_encode_string : string -> string
+
val log_line : string -> int -> string -> string
+val header : string -> int -> string
diff --git a/src/value.ml b/src/value.ml
index 8e920377..261b0f4e 100644
--- a/src/value.ml
+++ b/src/value.ml
@@ -86,6 +86,12 @@ type value =
| V_ref of string
| V_ctor of string * value list
| V_record of value StringMap.t
+ (* When constant folding we disable reading registers, so a register
+ read will return a V_attempted_read value. If we try to do
+ anything with this value, we'll get an exception - but if all we
+ do is return it then we can replace the expression we are folding
+ with a direct register read. *)
+ | V_attempted_read of string
let rec eq_value v1 v2 =
match v1, v2 with
@@ -394,10 +400,11 @@ let rec string_of_value = function
| V_unit -> "()"
| V_string str -> "\"" ^ str ^ "\""
| V_ref str -> "ref " ^ str
- | V_real r -> "REAL" (* No Rational.to_string *)
+ | V_real r -> Sail_lib.string_of_real r
| V_ctor (str, vals) -> str ^ "(" ^ Util.string_of_list ", " string_of_value vals ^ ")"
| V_record record ->
"{" ^ Util.string_of_list ", " (fun (field, v) -> field ^ "=" ^ string_of_value v) (StringMap.bindings record) ^ "}"
+ | V_attempted_read _ -> assert false
let value_sign_extend = function
| [v1; v2] -> mk_vector (Sail_lib.sign_extend (coerce_bv v1, coerce_int v2))
@@ -506,6 +513,18 @@ let value_to_real = function
| [v] -> V_real (Sail_lib.to_real (coerce_int v))
| _ -> failwith "value to_real"
+let value_print_real = function
+ | [v1; v2] -> output_endline (coerce_string v1 ^ string_of_value v2); V_unit
+ | _ -> failwith "value print_real"
+
+let value_random_real = function
+ | [_] -> V_real (Sail_lib.random_real ())
+ | _ -> failwith "value random_real"
+
+let value_sqrt_real = function
+ | [v] -> V_real (Sail_lib.sqrt_real (coerce_real v))
+ | _ -> failwith "value sqrt_real"
+
let value_quotient_real = function
| [v1; v2] -> V_real (Sail_lib.quotient_real (coerce_real v1, coerce_real v2))
| _ -> failwith "value quotient_real"
@@ -526,6 +545,26 @@ let value_rem_round_zero = function
| [v1; v2] -> V_int (Sail_lib.rem_round_zero (coerce_int v1, coerce_int v2))
| _ -> failwith "value rem_round_zero"
+let value_add_real = function
+ | [v1; v2] -> V_real (Sail_lib.add_real (coerce_real v1, coerce_real v2))
+ | _ -> failwith "value add_real"
+
+let value_sub_real = function
+ | [v1; v2] -> V_real (Sail_lib.sub_real (coerce_real v1, coerce_real v2))
+ | _ -> failwith "value sub_real"
+
+let value_mult_real = function
+ | [v1; v2] -> V_real (Sail_lib.mult_real (coerce_real v1, coerce_real v2))
+ | _ -> failwith "value mult_real"
+
+let value_div_real = function
+ | [v1; v2] -> V_real (Sail_lib.div_real (coerce_real v1, coerce_real v2))
+ | _ -> failwith "value div_real"
+
+let value_abs_real = function
+ | [v] -> V_real (Sail_lib.abs_real (coerce_real v))
+ | _ -> failwith "value abs_real"
+
let value_eq_real = function
| [v1; v2] -> V_bool (Sail_lib.eq_real (coerce_real v1, coerce_real v2))
| _ -> failwith "value eq_real"
@@ -644,13 +683,21 @@ let primops =
("eq_real", value_eq_real);
("lt_real", value_lt_real);
("gt_real", value_gt_real);
- ("lteq_real", value_lt_real);
- ("gteq_real", value_gt_real);
+ ("lteq_real", value_lteq_real);
+ ("gteq_real", value_gteq_real);
+ ("add_real", value_add_real);
+ ("sub_real", value_sub_real);
+ ("mult_real", value_mult_real);
("round_up", value_round_up);
("round_down", value_round_down);
("quot_round_zero", value_quot_round_zero);
("rem_round_zero", value_rem_round_zero);
("quotient_real", value_quotient_real);
+ ("abs_real", value_abs_real);
+ ("div_real", value_div_real);
+ ("sqrt_real", value_sqrt_real);
+ ("print_real", value_print_real);
+ ("random_real", value_random_real);
("undefined_unit", fun _ -> V_unit);
("undefined_bit", fun _ -> V_bit Sail_lib.B0);
("undefined_int", fun _ -> V_int Big_int.zero);