diff options
Diffstat (limited to 'src/pretty_print_coq.ml')
| -rw-r--r-- | src/pretty_print_coq.ml | 172 |
1 files changed, 132 insertions, 40 deletions
diff --git a/src/pretty_print_coq.ml b/src/pretty_print_coq.ml index 35aa9e20..053020db 100644 --- a/src/pretty_print_coq.ml +++ b/src/pretty_print_coq.ml @@ -71,6 +71,7 @@ type context = { 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 +80,7 @@ let empty_ctxt = { kid_id_renames = KBindings.empty; bound_nvars = KidSet.empty; build_ex_return = false; + recursive_ids = IdSet.empty; debug = false; } @@ -605,11 +607,29 @@ let doc_quant_item_id ctx delimit (QI_aux (qi,_)) = 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_const nc -> None + let doc_quant_item_constr ctx delimit (QI_aux (qi,_)) = match qi with | 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 -> @@ -624,6 +644,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 ^/^ @@ -879,6 +907,11 @@ 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.err_unreachable let doc_exp, doc_let = @@ -1142,11 +1175,13 @@ let doc_exp, doc_let = | _ -> 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 + 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_orig f env 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 @@ -1198,7 +1233,16 @@ let doc_exp, doc_let = 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 @@ -1821,6 +1865,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 @@ -1844,10 +1894,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 @@ -1866,6 +1912,28 @@ 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. *) @@ -1963,7 +2031,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 @@ -1978,17 +2046,31 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) = 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 () = @@ -2009,27 +2091,11 @@ 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.expand_synonyms env full_typ) with | Some ([kopt], NC_aux (NC_true,_), @@ -2040,17 +2106,17 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) = | Some ([kopt], nc, Typ_aux (Typ_app (Id_aux (Id "atom",_), [A_aux (A_nexp (Nexp_aux (Nexp_var kid,_)),_)]),_)) - when Kid.compare (kopt_kid kopt) kid == 0 -> + 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 = @@ -2059,6 +2125,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 (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) _rec_limit")], + [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 @@ -2078,9 +2169,10 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) = "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 @@ -2091,7 +2183,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" @@ -2104,7 +2196,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" |
