summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ocaml_backend.ml221
-rw-r--r--src/sail.ml6
-rw-r--r--src/sail_lib.ml16
-rw-r--r--src/type_check.ml2
-rw-r--r--src/type_check.mli2
5 files changed, 241 insertions, 6 deletions
diff --git a/src/ocaml_backend.ml b/src/ocaml_backend.ml
index 479fc821..51c9638a 100644
--- a/src/ocaml_backend.ml
+++ b/src/ocaml_backend.ml
@@ -648,7 +648,211 @@ let val_spec_typs (Defs defs) =
ignore (vs_typs defs);
!typs
-let ocaml_defs (Defs defs) =
+let orig_types_for_ocaml_generator (Defs defs) =
+ Some (Util.map_filter (function
+ | DEF_type td -> Some td
+ | _ -> None) defs)
+
+let ocaml_pp_generators ctx defs orig_types required =
+ let add_def typemap td =
+ Bindings.add (id_of_type_def td) td typemap
+ in
+ let typemap = List.fold_left add_def Bindings.empty orig_types in
+ let required = IdSet.of_list required in
+ let rec always_add_req_from_id required id =
+let () = print_endline ("Looking at id " ^ string_of_id id) in
+ match Bindings.find id typemap with
+ | td -> add_req_from_td (IdSet.add id required) td
+ | exception Not_found ->
+ if Bindings.mem id Type_check.Env.builtin_typs
+ then IdSet.add id required
+ else
+ raise (Reporting_basic.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
+ else always_add_req_from_id required id
+ and add_req_from_typ required (Typ_aux (typ,_) as full_typ) =
+let () = print_endline ("Looking at " ^ string_of_typ full_typ) in
+ match typ with
+ | Typ_id id -> add_req_from_id required id
+ | Typ_var _
+ -> required
+ | Typ_internal_unknown
+ | Typ_fn _
+ | Typ_bidir _
+ -> raise (Reporting_basic.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)
+ ("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,_)) =
+ match arg with
+ | Typ_arg_typ typ -> add_req_from_typ required typ
+ | Typ_arg_nexp _
+ | Typ_arg_order _
+ -> required
+ and add_req_from_td required (TD_aux (td,(l,_))) =
+ match td with
+ | TD_abbrev (_, _, TypSchm_aux (TypSchm_ts (_,typ),_)) ->
+let () = print_endline ("Looking at alias " ^ string_of_typ typ) in
+ add_req_from_typ required typ
+ | TD_record (_, _, _, fields, _) ->
+let () = print_endline ("Looking at " ^ string_of_int (List.length fields) ^ " fields") in
+ List.fold_left (fun req (typ,_) -> add_req_from_typ req typ) required fields
+ | TD_variant (_, _, _, variants, _) ->
+let () = print_endline ("Looking at " ^ string_of_int (List.length variants) ^ " variants") in
+ List.fold_left (fun req (Tu_aux (Tu_ty_id (typ,_),_)) ->
+ add_req_from_typ req typ) required variants
+ | TD_enum _ ->
+let () = print_endline "Nothing to do for enum" in
+required
+ | TD_bitfield _ -> raise (Reporting_basic.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
+ let make_gen_field id =
+ let allquants =
+ match Bindings.find id typemap with
+ | TD_aux (td,_) ->
+ (match td with
+ | TD_abbrev (_,_,TypSchm_aux (TypSchm_ts (tqs,typ),_)) -> tqs
+ | TD_record (_,_,tqs,_,_) -> tqs
+ | TD_variant (_,_,tqs,_,_) -> tqs
+ | TD_enum _ -> TypQ_aux (TypQ_no_forall,Unknown)
+ | TD_bitfield _ -> assert false)
+ | exception Not_found ->
+ Bindings.find id Type_check.Env.builtin_typs
+ in
+ let tquants = quant_kopts allquants in
+ let gen_tyvars = List.map (fun k -> kopt_kid k |> zencode_kid)
+ (List.filter is_typ_kopt tquants) in
+ let print_quant kindedid =
+ if is_nat_kopt kindedid then string "int" else
+ if is_order_kopt kindedid then string "bool" else
+ parens (separate space [string "generators"; string "->"; zencode_kid (kopt_kid kindedid)])
+ in
+ 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)))
+ 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))))
+ in
+ let targs = List.map make_tyarg tquants in
+ let gen_tyvars_pp, out_typ = match gen_tyvars with
+ | [] -> empty, mk_id_typ id
+ | _ -> separate space gen_tyvars ^^ dot ^^ space, mk_typ (Typ_app (id,targs))
+ in
+ let out_typ = Rewrites.simple_typ out_typ in
+ let types = string "generators" :: List.map print_quant tquants @ [ocaml_typ ctx out_typ] in
+ string name ^^ colon ^^ space ^^
+ gen_tyvars_pp ^^ separate (string " -> ") types ^^
+ string ";"
+ in
+ let fields = separate hardline (List.map make_gen_field (IdSet.elements required)) in
+ let gen_record_type_pp =
+ string "type generators = {" ^^ hardline ^^ fields ^^ hardline ^^ string "}"
+ in
+ let make_rand_gen id =
+ if Bindings.mem id Type_check.Env.builtin_typs
+ then empty
+ else
+ let name = string ("rand_" ^ type_name id) in
+ let mk_arg kid = string (zencode_string (string_of_kid kid)) in
+ let rec gen_type (Typ_aux (typ,l) as full_typ) =
+ 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
+ ("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,_)) =
+ match arg with
+ | Typ_arg_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
+ ("Unsupported nexp for generators: " ^ string_of_nexp full_nexp)))
+ | Typ_arg_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)
+ 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
+ ("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) ^^ space ^^ string "g" ^^ space ^^ args_pp
+ in
+ let make_variant (Tu_aux (Tu_ty_id (typ,id),_)) =
+ let arg_typs = match typ with
+ | Typ_aux (Typ_fn (Typ_aux (Typ_tup typs,_),_,_),_) -> typs
+ | Typ_aux (Typ_fn (typ,_,_),_) -> [typ]
+ | Typ_aux (Typ_tup typs,_) -> typs
+ | _ -> [typ]
+ in
+ parens (string "fun g -> " ^^ zencode_upper ctx id ^^ space ^^
+ parens (separate (string ", ") (List.map make_subgen arg_typs)))
+ in
+ let make_args tqs =
+ separate space (string "g"::
+ List.map (fun kdid -> mk_arg (kopt_kid kdid)) (quant_kopts tqs))
+ in
+ let top_args, body =
+ let TD_aux (td,_) = Bindings.find id typemap in
+ match td with
+ | TD_abbrev (_,_,TypSchm_aux (TypSchm_ts (tqs,typ),_)) ->
+ make_args tqs, gen_type typ
+ | TD_variant (_,_,tqs,variants,_) ->
+ empty, string "let c = rand_choice [" ^^ hardline ^^
+ separate (string ";" ^^ hardline)
+ (List.map make_variant variants) ^^ hardline ^^
+ string "] in fun " ^^ make_args tqs ^^ string " -> c () g" ^^ hardline
+ | TD_enum (_,_,variants,_) ->
+ empty,
+ string "let c = rand_choice [" ^^ hardline ^^
+ separate (string ";" ^^ hardline)
+ (List.map (zencode_upper ctx) variants) ^^ hardline ^^
+ string "] in fun g -> c ()" ^^ hardline
+ | _ -> empty, string "TODO"
+ in
+ separate space [string "let"; name; top_args] ^^ space ^^ equals ^^ hardline ^^
+ body ^^ hardline
+ in
+ let rand_record_pp =
+ string "let rand_gens : generators = {" ^^ hardline ^^
+ separate (string ";" ^^ hardline)
+ (List.map (fun id ->
+ string ("gen_" ^ type_name id) ^^ space ^^ equals ^^ space ^^
+ string ("rand_" ^ type_name id)) (IdSet.elements required)) ^^
+ hardline ^^ string "}" ^^ hardline
+ in
+ gen_record_type_pp ^^ hardline ^^ hardline ^^
+ separate hardline (List.map make_rand_gen (IdSet.elements required)) ^^
+ rand_record_pp
+
+let ocaml_defs (Defs defs) generator_types =
let ctx = { register_inits = get_initialize_registers defs;
externs = get_externs (Defs defs);
val_specs = val_spec_typs (Defs defs)
@@ -661,10 +865,16 @@ let ocaml_defs (Defs defs) =
^^ ocaml_def_end
else empty
in
+ let gen_pp =
+ match generator_types with
+ | None -> empty
+ | Some types -> ocaml_pp_generators ctx defs types [mk_id "ast"]
+ in
(string "open Sail_lib;;" ^^ hardline)
^^ (string "module Big_int = Nat_big_num" ^^ ocaml_def_end)
^^ concat (List.map (ocaml_def ctx) defs)
^^ empty_reg_init
+ ^^ gen_pp
let ocaml_main spec sail_dir =
let lines = ref [] in
@@ -685,8 +895,9 @@ let ocaml_main spec sail_dir =
" try zmain () with _ -> prerr_endline(\"Exiting due to uncaught exception\")\n";])
|> String.concat "\n"
-let ocaml_pp_defs f defs =
- ToChannel.pretty 1. 80 f (ocaml_defs defs)
+let ocaml_pp_defs f defs generator_types =
+ ToChannel.pretty 1. 80 f (ocaml_defs defs generator_types)
+
let system_checked str =
match Unix.system str with
@@ -701,7 +912,7 @@ let system_checked str =
prerr_endline (str ^ " was stopped by a signal");
exit 1
-let ocaml_compile spec defs =
+let ocaml_compile spec defs generator_types =
let sail_dir =
try Sys.getenv "SAIL_DIR" with
| Not_found ->
@@ -722,7 +933,7 @@ let ocaml_compile spec defs =
let out_chan = open_out (spec ^ ".ml") in
if !opt_ocaml_coverage then
ignore(Unix.system ("cp -r " ^ sail_dir ^ "/lib/myocamlbuild_coverage.ml myocamlbuild.ml"));
- ocaml_pp_defs out_chan defs;
+ ocaml_pp_defs out_chan defs generator_types;
close_out out_chan;
if IdSet.mem (mk_id "main") (Initial_check.val_spec_ids defs)
then
diff --git a/src/sail.ml b/src/sail.ml
index fc01d3b4..b535d1d3 100644
--- a/src/sail.ml
+++ b/src/sail.ml
@@ -299,6 +299,10 @@ let main() =
| None, _ -> ()
end;
+ let orig_types_for_ocaml_generator =
+ Ocaml_backend.orig_types_for_ocaml_generator ast
+ in
+
(*let _ = Printf.eprintf "Type checked, next to pretty print" in*)
begin
(if !(opt_interactive)
@@ -317,7 +321,7 @@ let main() =
then
let ast_ocaml = rewrite_ast_ocaml ast in
let out = match !opt_file_out with None -> "out" | Some s -> s in
- Ocaml_backend.ocaml_compile out ast_ocaml
+ Ocaml_backend.ocaml_compile out ast_ocaml orig_types_for_ocaml_generator
else ());
(if !(opt_print_c)
then
diff --git a/src/sail_lib.ml b/src/sail_lib.ml
index fbe700aa..22f55e62 100644
--- a/src/sail_lib.ml
+++ b/src/sail_lib.ml
@@ -1121,3 +1121,19 @@ let load_raw (paddr, file) =
(* XXX this could count cycles and exit after given limit *)
let cycle_count () = ()
+
+(* TODO range, atom, register(?), int, nat, bool, real(!), list, string, itself(?) *)
+let rand_zvector (g : 'generators) (size : int) (order : bool) (elem_gen : 'generators -> 'a) : 'a list =
+ List.init size (fun _ -> elem_gen g)
+
+let rand_zbit (g : 'generators) : bit =
+ if Random.bool() then B0 else B1
+
+let rand_zbool (g : 'generators) : bool =
+ Random.bool()
+
+let rand_zunit (g : 'generators) : unit = ()
+
+let rand_choice l =
+ let n = List.length l in
+ fun () -> (List.nth l (Random.int n))
diff --git a/src/type_check.ml b/src/type_check.ml
index 0e9f7dd8..71028f96 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -427,6 +427,8 @@ module Env : sig
val empty : t
val pattern_completeness_ctx : t -> Pattern_completeness.ctx
+
+ val builtin_typs : typquant Bindings.t
end = struct
type t =
{ top_val_specs : (typquant * typ) Bindings.t;
diff --git a/src/type_check.mli b/src/type_check.mli
index ff67b765..4fe6711c 100644
--- a/src/type_check.mli
+++ b/src/type_check.mli
@@ -195,6 +195,8 @@ module Env : sig
val empty : t
val pattern_completeness_ctx : t -> Pattern_completeness.ctx
+
+ val builtin_typs : typquant Bindings.t
end
(** Push all the type variables and constraints from a typquant into