diff options
Diffstat (limited to 'src/Translate.ml')
-rw-r--r-- | src/Translate.ml | 871 |
1 files changed, 0 insertions, 871 deletions
diff --git a/src/Translate.ml b/src/Translate.ml deleted file mode 100644 index 8f3b94c4..00000000 --- a/src/Translate.ml +++ /dev/null @@ -1,871 +0,0 @@ -open InterpreterStatements -open Interpreter -module L = Logging -module T = Types -module A = LlbcAst -module SA = SymbolicAst -module Micro = PureMicroPasses -open PureUtils -open TranslateCore - -(** The local logger *) -let log = TranslateCore.log - -type config = { - eval_config : Contexts.partial_config; - mp_config : Micro.config; - use_state : bool; - (** Controls whether we need to use a state to model the external world - (I/O, for instance). - *) - split_files : bool; - (** Controls whether we split the generated definitions between different - files for the types, clauses and functions, or if we group them in - one file. - *) - test_unit_functions : bool; - (** If true, insert tests in the generated files to check that the - unit functions normalize to [Success _]. - - For instance, in F* it generates code like this: - {[ - let _ = assert_norm (FUNCTION () = Success ()) - ]} - *) - extract_decreases_clauses : bool; - (** If [true], insert [decreases] clauses for all the recursive definitions. - - The body of such clauses must be defined by the user. - *) - extract_template_decreases_clauses : bool; - (** In order to help the user, we can generate "template" decrease clauses - (i.e., definitions with proper signatures but dummy bodies) in a - dedicated file. - *) -} - -(** The result of running the symbolic interpreter on a function: - - the list of symbolic values used for the input values - - the generated symbolic AST -*) -type symbolic_fun_translation = V.symbolic_value list * SA.expression - -(** Execute the symbolic interpreter on a function to generate a list of symbolic ASTs, - for the forward function and the backward functions. -*) -let translate_function_to_symbolics (config : C.partial_config) - (trans_ctx : trans_ctx) (fdef : A.fun_decl) : - (symbolic_fun_translation * symbolic_fun_translation list) option = - (* Debug *) - log#ldebug - (lazy - ("translate_function_to_symbolics: " - ^ Print.fun_name_to_string fdef.A.name)); - - let { type_context; fun_context; global_context } = trans_ctx in - let fun_context = { C.fun_decls = fun_context.fun_decls } in - - match fdef.body with - | None -> None - | Some _ -> - (* Evaluate *) - let synthesize = true in - let evaluate gid = - let inputs, symb = - evaluate_function_symbolic config synthesize type_context fun_context - global_context fdef gid - in - (inputs, Option.get symb) - in - (* Execute the forward function *) - let forward = evaluate None in - (* Execute the backward functions *) - let backwards = - T.RegionGroupId.mapi - (fun gid _ -> evaluate (Some gid)) - fdef.signature.regions_hierarchy - in - - (* Return *) - Some (forward, backwards) - -(** Translate a function, by generating its forward and backward translations. - - [fun_sigs]: maps the forward/backward functions to their signatures. In case - of backward functions, we also provide names for the outputs. - TODO: maybe we should introduce a record for this. -*) -let translate_function_to_pure (config : C.partial_config) - (mp_config : Micro.config) (trans_ctx : trans_ctx) - (fun_sigs : SymbolicToPure.fun_sig_named_outputs RegularFunIdMap.t) - (pure_type_decls : Pure.type_decl Pure.TypeDeclId.Map.t) (fdef : A.fun_decl) - : pure_fun_translation = - (* Debug *) - log#ldebug - (lazy - ("translate_function_to_pure: " ^ Print.fun_name_to_string fdef.A.name)); - - let { type_context; fun_context; global_context } = trans_ctx in - let def_id = fdef.def_id in - - (* Compute the symbolic ASTs, if the function is transparent *) - let symbolic_trans = translate_function_to_symbolics config trans_ctx fdef in - let symbolic_forward, symbolic_backwards = - match symbolic_trans with - | None -> (None, None) - | Some (fwd, backs) -> (Some fwd, Some backs) - in - - (* Convert the symbolic ASTs to pure ASTs: *) - - (* Initialize the context *) - let forward_sig = RegularFunIdMap.find (A.Regular def_id, None) fun_sigs in - let sv_to_var = V.SymbolicValueId.Map.empty in - let var_counter = Pure.VarId.generator_zero in - let state_var, var_counter = Pure.VarId.fresh var_counter in - let calls = V.FunCallId.Map.empty in - let abstractions = V.AbstractionId.Map.empty in - let type_context = - { - SymbolicToPure.types_infos = type_context.type_infos; - llbc_type_decls = type_context.type_decls; - type_decls = pure_type_decls; - } - in - let fun_context = - { - SymbolicToPure.llbc_fun_decls = fun_context.fun_decls; - fun_sigs; - fun_infos = fun_context.fun_infos; - } - in - let global_context = - { SymbolicToPure.llbc_global_decls = global_context.global_decls } - in - let ctx = - { - SymbolicToPure.bid = None; - (* Dummy for now *) - sg = forward_sig.sg; - (* Will need to be updated for the backward functions *) - sv_to_var; - var_counter; - state_var; - type_context; - fun_context; - global_context; - fun_decl = fdef; - forward_inputs = []; - (* Empty for now *) - backward_inputs = T.RegionGroupId.Map.empty; - (* Empty for now *) - backward_outputs = T.RegionGroupId.Map.empty; - (* Empty for now *) - calls; - abstractions; - } - in - - (* We need to initialize the input/output variables *) - let num_forward_inputs = List.length fdef.signature.inputs in - let add_forward_inputs input_svs ctx = - match fdef.body with - | None -> ctx - | Some body -> - let forward_input_vars = LlbcAstUtils.fun_body_get_input_vars body in - let forward_input_varnames = - List.map (fun (v : A.var) -> v.name) forward_input_vars - in - let input_svs = List.combine forward_input_varnames input_svs in - let ctx, forward_inputs = - SymbolicToPure.fresh_named_vars_for_symbolic_values input_svs ctx - in - { ctx with forward_inputs } - in - - (* The symbolic to pure config *) - let sp_config = - { - SymbolicToPure.filter_useless_back_calls = - mp_config.filter_useless_monadic_calls; - } - in - - (* Translate the forward function *) - let pure_forward = - match symbolic_forward with - | None -> SymbolicToPure.translate_fun_decl sp_config ctx None - | Some (fwd_svs, fwd_ast) -> - SymbolicToPure.translate_fun_decl sp_config - (add_forward_inputs fwd_svs ctx) - (Some fwd_ast) - in - - (* Translate the backward functions *) - let translate_backward (rg : T.region_var_group) : Pure.fun_decl = - (* For the backward inputs/outputs initialization: we use the fact that - * there are no nested borrows for now, and so that the region groups - * can't have parents *) - assert (rg.parents = []); - let back_id = rg.id in - - match symbolic_backwards with - | None -> - (* Initialize the context - note that the ret_ty is not really - * useful as we don't translate a body *) - let backward_sg = - RegularFunIdMap.find (A.Regular def_id, Some back_id) fun_sigs - in - let ctx = { ctx with bid = Some back_id; sg = backward_sg.sg } in - - (* Translate *) - SymbolicToPure.translate_fun_decl sp_config ctx None - | Some symbolic_backwards -> - let input_svs, symbolic = - T.RegionGroupId.nth symbolic_backwards back_id - in - let ctx = add_forward_inputs input_svs ctx in - (* TODO: the computation of the backward inputs is a bit awckward... *) - let backward_sg = - RegularFunIdMap.find (A.Regular def_id, Some back_id) fun_sigs - in - (* We need to ignore the forward inputs, and the state input (if there is) *) - let fun_info = - SymbolicToPure.get_fun_effect_info fun_context.fun_infos - (A.Regular def_id) (Some back_id) - in - let _, backward_inputs = - Collections.List.split_at backward_sg.sg.inputs - (num_forward_inputs + if fun_info.input_state then 1 else 0) - in - (* As we forbid nested borrows, the additional inputs for the backward - * functions come from the borrows in the return value of the rust function: - * we thus use the name "ret" for those inputs *) - let backward_inputs = - List.map (fun ty -> (Some "ret", ty)) backward_inputs - in - let ctx, backward_inputs = - SymbolicToPure.fresh_vars backward_inputs ctx - in - (* The outputs for the backward functions, however, come from borrows - * present in the input values of the rust function: for those we reuse - * the names of the input values. *) - let backward_outputs = - List.combine backward_sg.output_names backward_sg.sg.doutputs - in - let ctx, backward_outputs = - SymbolicToPure.fresh_vars backward_outputs ctx - in - let backward_inputs = - T.RegionGroupId.Map.singleton back_id backward_inputs - in - let backward_outputs = - T.RegionGroupId.Map.singleton back_id backward_outputs - in - - (* Put everything in the context *) - let ctx = - { - ctx with - bid = Some back_id; - sg = backward_sg.sg; - backward_inputs; - backward_outputs; - } - in - - (* Translate *) - SymbolicToPure.translate_fun_decl sp_config ctx (Some symbolic) - in - let pure_backwards = - List.map translate_backward fdef.signature.regions_hierarchy - in - - (* Return *) - (pure_forward, pure_backwards) - -let translate_module_to_pure (config : C.partial_config) - (mp_config : Micro.config) (use_state : bool) (crate : Crates.llbc_crate) : - trans_ctx * Pure.type_decl list * (bool * pure_fun_translation) list = - (* Debug *) - log#ldebug (lazy "translate_module_to_pure"); - - (* Compute the type and function contexts *) - let type_context, fun_context, global_context = - compute_type_fun_global_contexts crate - in - let fun_infos = - FA.analyze_module crate fun_context.C.fun_decls - global_context.C.global_decls use_state - in - let fun_context = { fun_decls = fun_context.fun_decls; fun_infos } in - let trans_ctx = { type_context; fun_context; global_context } in - - (* Translate all the type definitions *) - let type_decls = SymbolicToPure.translate_type_decls crate.types in - - (* Compute the type definition map *) - let type_decls_map = - Pure.TypeDeclId.Map.of_list - (List.map (fun (def : Pure.type_decl) -> (def.def_id, def)) type_decls) - in - - (* Translate all the function *signatures* *) - let assumed_sigs = - List.map - (fun (id, sg, _, _) -> - (A.Assumed id, List.map (fun _ -> None) (sg : A.fun_sig).inputs, sg)) - Assumed.assumed_infos - in - let local_sigs = - List.map - (fun (fdef : A.fun_decl) -> - let input_names = - match fdef.body with - | None -> List.map (fun _ -> None) fdef.signature.inputs - | Some body -> - List.map - (fun (v : A.var) -> v.name) - (LlbcAstUtils.fun_body_get_input_vars body) - in - (A.Regular fdef.def_id, input_names, fdef.signature)) - crate.functions - in - let sigs = List.append assumed_sigs local_sigs in - let fun_sigs = - SymbolicToPure.translate_fun_signatures fun_context.fun_infos - type_context.type_infos sigs - in - - (* Translate all the *transparent* functions *) - let pure_translations = - List.map - (translate_function_to_pure config mp_config trans_ctx fun_sigs - type_decls_map) - crate.functions - in - - (* Apply the micro-passes *) - let pure_translations = - List.map - (Micro.apply_passes_to_pure_fun_translation mp_config trans_ctx) - pure_translations - in - - (* Return *) - (trans_ctx, type_decls, pure_translations) - -(** Extraction context *) -type gen_ctx = { - crate : Crates.llbc_crate; - extract_ctx : PureToExtract.extraction_ctx; - trans_types : Pure.type_decl Pure.TypeDeclId.Map.t; - trans_funs : (bool * pure_fun_translation) A.FunDeclId.Map.t; - functions_with_decreases_clause : A.FunDeclId.Set.t; -} - -type gen_config = { - mp_config : Micro.config; - use_state : bool; - extract_types : bool; - extract_decreases_clauses : bool; - extract_template_decreases_clauses : bool; - extract_fun_decls : bool; - extract_transparent : bool; - (** If [true], extract the transparent declarations, otherwise ignore. *) - extract_opaque : bool; - (** If [true], extract the opaque declarations, otherwise ignore. *) - extract_state_type : bool; - (** If [true], generate a definition/declaration for the state type *) - interface : bool; - (** [true] if we generate an interface file, [false] otherwise. - For now, this only impacts whether we use [val] or [assume val] for the - opaque definitions. In the future, we might want to extract all the - declarations in an interface file, together with an implementation file - if needed. - *) - test_unit_functions : bool; -} - -(** Returns the pair: (has opaque type decls, has opaque fun decls) *) -let module_has_opaque_decls (ctx : gen_ctx) : bool * bool = - let has_opaque_types = - Pure.TypeDeclId.Map.exists - (fun _ (d : Pure.type_decl) -> - match d.kind with Opaque -> true | _ -> false) - ctx.trans_types - in - let has_opaque_funs = - A.FunDeclId.Map.exists - (fun _ ((_, (t_fwd, _)) : bool * pure_fun_translation) -> - Option.is_none t_fwd.body) - ctx.trans_funs - in - (has_opaque_types, has_opaque_funs) - -(** A generic utility to generate the extracted definitions: as we may want to - split the definitions between different files (or not), we can control - what is precisely extracted. - *) -let extract_definitions (fmt : Format.formatter) (config : gen_config) - (ctx : gen_ctx) : unit = - (* Export the definition groups to the file, in the proper order *) - let export_type (qualif : ExtractToFStar.type_decl_qualif) - (id : Pure.TypeDeclId.id) : unit = - (* Retrive the declaration *) - let def = Pure.TypeDeclId.Map.find id ctx.trans_types in - (* Update the qualifier, if the type is opaque *) - let is_opaque, qualif = - match def.kind with - | Enum _ | Struct _ -> (false, qualif) - | Opaque -> - let qualif = - if config.interface then ExtractToFStar.TypeVal - else ExtractToFStar.AssumeType - in - (true, qualif) - in - (* Extract, if the config instructs to do so (depending on whether the type - * is opaque or not) *) - if - (is_opaque && config.extract_opaque) - || ((not is_opaque) && config.extract_transparent) - then ExtractToFStar.extract_type_decl ctx.extract_ctx fmt qualif def - in - - (* Utility to check a function has a decrease clause *) - let has_decreases_clause (def : Pure.fun_decl) : bool = - A.FunDeclId.Set.mem def.def_id ctx.functions_with_decreases_clause - in - - (* In case of (non-mutually) recursive functions, we use a simple procedure to - * check if the forward and backward functions are mutually recursive. - *) - let export_functions (is_rec : bool) - (pure_ls : (bool * pure_fun_translation) list) : unit = - (* Concatenate the function definitions, filtering the useless forward - * functions. We also make pairs: (forward function, backward function) - * (the forward function contains useful information that we want to keep) *) - let fls = - List.concat - (List.map - (fun (keep_fwd, (fwd, back_ls)) -> - let back_ls = List.map (fun back -> (fwd, back)) back_ls in - if keep_fwd then (fwd, fwd) :: back_ls else back_ls) - pure_ls) - in - (* Extract the decrease clauses template bodies *) - if config.extract_template_decreases_clauses then - List.iter - (fun (_, (fwd, _)) -> - let has_decr_clause = has_decreases_clause fwd in - if has_decr_clause then - ExtractToFStar.extract_template_decreases_clause ctx.extract_ctx fmt - fwd) - pure_ls; - (* Extract the function definitions *) - (if config.extract_fun_decls then - (* Check if the functions are mutually recursive - this really works - * to check if the forward and backward translations of a single - * recursive function are mutually recursive *) - let is_mut_rec = - if is_rec then - if List.length pure_ls <= 1 then - not (PureUtils.functions_not_mutually_recursive (List.map fst fls)) - else true - else false - in - List.iteri - (fun i (fwd_def, def) -> - let is_opaque = Option.is_none fwd_def.Pure.body in - let qualif = - if is_opaque then - if config.interface then ExtractToFStar.Val - else ExtractToFStar.AssumeVal - else if not is_rec then ExtractToFStar.Let - else if is_mut_rec then - if i = 0 then ExtractToFStar.LetRec else ExtractToFStar.And - else ExtractToFStar.LetRec - in - let has_decr_clause = - has_decreases_clause def && config.extract_decreases_clauses - in - (* Check if the definition needs to be filtered or not *) - if - ((not is_opaque) && config.extract_transparent) - || (is_opaque && config.extract_opaque) - then - ExtractToFStar.extract_fun_decl ctx.extract_ctx fmt qualif - has_decr_clause def) - fls); - (* Insert unit tests if necessary *) - if config.test_unit_functions then - List.iter - (fun (keep_fwd, (fwd, _)) -> - if keep_fwd then - ExtractToFStar.extract_unit_test_if_unit_fun ctx.extract_ctx fmt fwd) - pure_ls - in - - (* TODO: Check correct behaviour with opaque globals *) - let export_global (id : A.GlobalDeclId.id) : unit = - let global_decls = ctx.extract_ctx.trans_ctx.global_context.global_decls in - let global = A.GlobalDeclId.Map.find id global_decls in - let _, (body, body_backs) = - A.FunDeclId.Map.find global.body_id ctx.trans_funs - in - assert (List.length body_backs = 0); - - let is_opaque = Option.is_none body.Pure.body in - if - ((not is_opaque) && config.extract_transparent) - || (is_opaque && config.extract_opaque) - then - ExtractToFStar.extract_global_decl ctx.extract_ctx fmt global body - config.interface - in - - let export_state_type () : unit = - let qualif = - if config.interface then ExtractToFStar.TypeVal - else ExtractToFStar.AssumeType - in - ExtractToFStar.extract_state_type fmt ctx.extract_ctx qualif - in - - let export_decl (decl : Crates.declaration_group) : unit = - match decl with - | Type (NonRec id) -> - if config.extract_types then export_type ExtractToFStar.Type id - | Type (Rec ids) -> - (* Rk.: we shouldn't have (mutually) recursive opaque types *) - if config.extract_types then - List.iteri - (fun i id -> - let qualif = - if i = 0 then ExtractToFStar.Type else ExtractToFStar.And - in - export_type qualif id) - ids - | Fun (NonRec id) -> - (* Lookup *) - let pure_fun = A.FunDeclId.Map.find id ctx.trans_funs in - (* Translate *) - export_functions false [ pure_fun ] - | Fun (Rec ids) -> - (* General case of mutually recursive functions *) - (* Lookup *) - let pure_funs = - List.map (fun id -> A.FunDeclId.Map.find id ctx.trans_funs) ids - in - (* Translate *) - export_functions true pure_funs - | Global id -> export_global id - in - - (* If we need to export the state type: we try to export it after we defined - * the type definitions, because if the user wants to define a model for the - * type, he might want to reuse them in the state type. - * More specifically: if we extract functions, we have no choice but to define - * the state type before the functions, because they may reuse this state - * type: in this case, we define/declare it at the very beginning. Otherwise, - * we define/declare it at the very end. - *) - if config.extract_state_type && config.extract_fun_decls then - export_state_type (); - List.iter export_decl ctx.crate.declarations; - if config.extract_state_type && not config.extract_fun_decls then - export_state_type () - -let extract_file (config : gen_config) (ctx : gen_ctx) (filename : string) - (rust_module_name : string) (module_name : string) (custom_msg : string) - (custom_imports : string list) (custom_includes : string list) : unit = - (* Open the file and create the formatter *) - let out = open_out filename in - let fmt = Format.formatter_of_out_channel out in - - (* Print the headers. - * Note that we don't use the OCaml formatter for purpose: we want to control - * line insertion (we have to make sure that some instructions like [open MODULE] - * are printed on one line!). - * This is ok as long as we end up with a line break, so that the formatter's - * internal count is consistent with the state of the file. - *) - (* Create the header *) - Printf.fprintf out "(** THIS FILE WAS AUTOMATICALLY GENERATED BY AENEAS *)\n"; - Printf.fprintf out "(** [%s]%s *)\n" rust_module_name custom_msg; - Printf.fprintf out "module %s\n" module_name; - Printf.fprintf out "open Primitives\n"; - (* Add the custom imports *) - List.iter (fun m -> Printf.fprintf out "open %s\n" m) custom_imports; - (* Add the custom includes *) - List.iter (fun m -> Printf.fprintf out "include %s\n" m) custom_includes; - (* Z3 options - note that we use fuel 1 because it its useful for the decrease clauses *) - Printf.fprintf out "\n#set-options \"--z3rlimit 50 --fuel 1 --ifuel 1\"\n"; - - (* From now onwards, we use the formatter *) - (* Set the margin *) - Format.pp_set_margin fmt 80; - - (* Create a vertical box *) - Format.pp_open_vbox fmt 0; - - (* Extract the definitions *) - extract_definitions fmt config ctx; - - (* Close the box and end the formatting *) - Format.pp_close_box fmt (); - Format.pp_print_newline fmt (); - - (* Some logging *) - log#linfo (lazy ("Generated: " ^ filename)); - - (* Flush and close the file *) - close_out out - -(** Translate a module and write the synthesized code to an output file. - TODO: rename to translate_crate - *) -let translate_module (filename : string) (dest_dir : string) (config : config) - (crate : Crates.llbc_crate) : unit = - (* Translate the module to the pure AST *) - let trans_ctx, trans_types, trans_funs = - translate_module_to_pure config.eval_config config.mp_config - config.use_state crate - in - - (* Initialize the extraction context - for now we extract only to F* *) - let names_map = - PureToExtract.initialize_names_map ExtractToFStar.fstar_names_map_init - in - let variant_concatenate_type_name = true in - let fstar_fmt = - ExtractToFStar.mk_formatter trans_ctx crate.name - variant_concatenate_type_name - in - let ctx = - { PureToExtract.trans_ctx; names_map; fmt = fstar_fmt; indent_incr = 2 } - in - - (* We need to compute which functions are recursive, in order to know - * whether we should generate a decrease clause or not. *) - let rec_functions = - A.FunDeclId.Set.of_list - (List.concat - (List.map - (fun decl -> - match decl with Crates.Fun (Rec ids) -> ids | _ -> []) - crate.declarations)) - in - - (* Register unique names for all the top-level types, globals and functions. - * Note that the order in which we generate the names doesn't matter: - * we just need to generate a mapping from identifier to name, and make - * sure there are no name clashes. *) - let ctx = - List.fold_left - (fun ctx def -> ExtractToFStar.extract_type_decl_register_names ctx def) - ctx trans_types - in - - let ctx = - List.fold_left - (fun ctx (keep_fwd, def) -> - (* We generate a decrease clause for all the recursive functions *) - let gen_decr_clause = - A.FunDeclId.Set.mem (fst def).Pure.def_id rec_functions - in - (* Register the names, only if the function is not a global body - - * those are handled later *) - let is_global = (fst def).Pure.is_global_decl_body in - if is_global then ctx - else - ExtractToFStar.extract_fun_decl_register_names ctx keep_fwd - gen_decr_clause def) - ctx trans_funs - in - - let ctx = - List.fold_left ExtractToFStar.extract_global_decl_register_names ctx - crate.globals - in - - (* Open the output file *) - (* First compute the filename by replacing the extension and converting the - * case (rust module names are snake case) *) - let module_name, extract_filebasename = - match Filename.chop_suffix_opt ~suffix:".llbc" filename with - | None -> - (* Note that we already checked the suffix upon opening the file *) - failwith "Unreachable" - | Some filename -> - (* Retrieve the file basename *) - let basename = Filename.basename filename in - (* Convert the case *) - let module_name = StringUtils.to_camel_case basename in - (* Concatenate *) - (module_name, Filename.concat dest_dir module_name) - in - - (* Put the translated definitions in maps *) - let trans_types = - Pure.TypeDeclId.Map.of_list - (List.map (fun (d : Pure.type_decl) -> (d.def_id, d)) trans_types) - in - let trans_funs = - A.FunDeclId.Map.of_list - (List.map - (fun ((keep_fwd, (fd, bdl)) : bool * pure_fun_translation) -> - (fd.def_id, (keep_fwd, (fd, bdl)))) - trans_funs) - in - - (* Create the directory, if necessary *) - if not (Sys.file_exists dest_dir) then ( - log#linfo (lazy ("Creating missing directory: " ^ dest_dir)); - (* Create a directory with *default* permissions *) - Core_unix.mkdir_p dest_dir); - - (* Copy "Primitives.fst" - I couldn't find a "cp" function in the OCaml - * libraries... *) - let _ = - let src = open_in "fstar/Primitives.fst" in - let tgt_filename = Filename.concat dest_dir "Primitives.fst" in - let tgt = open_out tgt_filename in - try - while true do - (* We copy line by line *) - let line = input_line src in - Printf.fprintf tgt "%s\n" line - done - with End_of_file -> - close_in src; - close_out tgt; - log#linfo (lazy ("Copied: " ^ tgt_filename)) - in - - (* Extract the file(s) *) - let gen_ctx = - { - crate; - extract_ctx = ctx; - trans_types; - trans_funs; - functions_with_decreases_clause = rec_functions; - } - in - - let use_state = config.use_state in - - (* Extract one or several files, depending on the configuration *) - if config.split_files then ( - let base_gen_config = - { - mp_config = config.mp_config; - use_state; - extract_types = false; - extract_decreases_clauses = config.extract_decreases_clauses; - extract_template_decreases_clauses = false; - extract_fun_decls = false; - extract_transparent = true; - extract_opaque = false; - extract_state_type = false; - interface = false; - test_unit_functions = false; - } - in - - (* Check if there are opaque types and functions - in which case we need - * to split *) - let has_opaque_types, has_opaque_funs = module_has_opaque_decls gen_ctx in - let has_opaque_types = has_opaque_types || use_state in - - (* Extract the types *) - (* If there are opaque types, we extract in an interface *) - let types_filename_ext = if has_opaque_types then ".fsti" else ".fst" in - let types_filename = extract_filebasename ^ ".Types" ^ types_filename_ext in - let types_module = module_name ^ ".Types" in - let types_config = - { - base_gen_config with - extract_types = true; - extract_opaque = true; - extract_state_type = use_state; - interface = has_opaque_types; - } - in - extract_file types_config gen_ctx types_filename crate.Crates.name - types_module ": type definitions" [] []; - - (* Extract the template clauses *) - let needs_clauses_module = - config.extract_decreases_clauses - && not (A.FunDeclId.Set.is_empty rec_functions) - in - (if needs_clauses_module && config.extract_template_decreases_clauses then - let clauses_filename = extract_filebasename ^ ".Clauses.Template.fst" in - let clauses_module = module_name ^ ".Clauses.Template" in - let clauses_config = - { base_gen_config with extract_template_decreases_clauses = true } - in - extract_file clauses_config gen_ctx clauses_filename crate.Crates.name - clauses_module ": templates for the decreases clauses" [ types_module ] - []); - - (* Extract the opaque functions, if needed *) - let opaque_funs_module = - if has_opaque_funs then ( - let opaque_filename = extract_filebasename ^ ".Opaque.fsti" in - let opaque_module = module_name ^ ".Opaque" in - let opaque_config = - { - base_gen_config with - extract_fun_decls = true; - extract_transparent = false; - extract_opaque = true; - interface = true; - } - in - extract_file opaque_config gen_ctx opaque_filename crate.Crates.name - opaque_module ": opaque function definitions" [] [ types_module ]; - [ opaque_module ]) - else [] - in - - (* Extract the functions *) - let fun_filename = extract_filebasename ^ ".Funs.fst" in - let fun_module = module_name ^ ".Funs" in - let fun_config = - { - base_gen_config with - extract_fun_decls = true; - test_unit_functions = config.test_unit_functions; - } - in - let clauses_module = - if needs_clauses_module then [ module_name ^ ".Clauses" ] else [] - in - extract_file fun_config gen_ctx fun_filename crate.Crates.name fun_module - ": function definitions" [] - ([ types_module ] @ opaque_funs_module @ clauses_module)) - else - let gen_config = - { - mp_config = config.mp_config; - use_state; - extract_types = true; - extract_decreases_clauses = config.extract_decreases_clauses; - extract_template_decreases_clauses = - config.extract_template_decreases_clauses; - extract_fun_decls = true; - extract_transparent = true; - extract_opaque = true; - extract_state_type = use_state; - interface = false; - test_unit_functions = config.test_unit_functions; - } - in - (* Add the extension for F* *) - let extract_filename = extract_filebasename ^ ".fst" in - extract_file gen_config gen_ctx extract_filename crate.Crates.name - module_name "" [] [] |