aboutsummaryrefslogtreecommitdiff
path: root/pretyping
diff options
context:
space:
mode:
authorherbelin2000-01-07 22:32:14 +0000
committerherbelin2000-01-07 22:32:14 +0000
commit11263ccf0fabc1fe160c3c09b88dcb09e2cdaf6d (patch)
treedbd2370d455e20a4bc5bf549ad35cd525ae0034f /pretyping
parent049b4a8040e62e6734cb891f62881bafc81d936d (diff)
Traduction constr->rawconstr (avant dans Termast
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@271 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'pretyping')
-rw-r--r--pretyping/detyping.ml427
-rw-r--r--pretyping/detyping.mli27
2 files changed, 454 insertions, 0 deletions
diff --git a/pretyping/detyping.ml b/pretyping/detyping.ml
new file mode 100644
index 0000000000..d4dd1da18f
--- /dev/null
+++ b/pretyping/detyping.ml
@@ -0,0 +1,427 @@
+
+(* $Id$ *)
+
+open Pp
+open Util
+open Univ
+open Names
+open Generic
+open Term
+open Inductive
+open Sign
+open Declare
+open Impargs
+open Rawterm
+
+(* Nouvelle version de renommage des variables (DEC 98) *)
+(* This is the algorithm to display distinct bound variables
+
+ - Règle 1 : un nom non anonyme, même non affiché, contribue à la liste
+ des noms à éviter
+ - Règle 2 : c'est la dépendance qui décide si on affiche ou pas
+
+ Exemple :
+ si bool_ind = (P:bool->Prop)(f:(P true))(f:(P false))(b:bool)(P b), alors
+ il est affiché (P:bool->Prop)(P true)->(P false)->(b:bool)(P b)
+ mais f et f0 contribue à la liste des variables à éviter (en supposant
+ que les noms f et f0 ne sont pas déjà pris)
+ Intérêt : noms homogènes dans un but avant et après Intro
+*)
+
+type used_idents = identifier list
+
+let occur_id env id0 c =
+ let rec occur n = function
+ | VAR id -> id=id0
+ | DOPN (Const sp,cl) -> (basename sp = id0) or (array_exists (occur n) cl)
+ | DOPN (Abst sp,cl) -> (basename sp = id0) or (array_exists (occur n) cl)
+ | DOPN (MutInd ind_sp, cl) as t ->
+ (basename (path_of_inductive_path ind_sp) = id0)
+ or (array_exists (occur n) cl)
+ | DOPN (MutConstruct cstr_sp, cl) as t ->
+ (basename (path_of_constructor_path cstr_sp) = id0)
+ or (array_exists (occur n) cl)
+ | DOPN(_,cl) -> array_exists (occur n) cl
+ | DOP1(_,c) -> occur n c
+ | DOP2(_,c1,c2) -> (occur n c1) or (occur n c2)
+ | DOPL(_,cl) -> List.exists (occur n) cl
+ | DLAM(_,c) -> occur (n+1) c
+ | DLAMV(_,v) -> array_exists (occur (n+1)) v
+ | Rel p ->
+ p>n &
+ (try (fst (lookup_rel (p-n) env) = Name id0)
+ with Not_found -> false) (* Unbound indice : may happen in debug *)
+ | DOP0 _ -> false
+ in
+ occur 1 c
+
+let next_name_not_occuring name l env t =
+ let rec next id =
+ if List.mem id l or occur_id env id t then next (lift_ident id) else id
+ in
+ match name with
+ | Name id -> next id
+ | Anonymous -> id_of_string "_"
+
+(* Remark: Anonymous var may be dependent in Evar's contexts *)
+let concrete_name l env n c =
+ if n = Anonymous & not (dependent (Rel 1) c) then
+ (None,l)
+ else
+ let fresh_id = next_name_not_occuring n l env c in
+ let idopt = if dependent (Rel 1) c then (Some fresh_id) else None in
+ (idopt, fresh_id::l)
+
+ (* Returns the list of global variables and constants in a term *)
+let global_vars_and_consts t =
+ let rec collect acc = function
+ | VAR id -> id::acc
+ | DOPN (Const sp,cl) -> (basename sp)::(Array.fold_left collect acc cl)
+ | DOPN (Abst sp,cl) -> (basename sp)::(Array.fold_left collect acc cl)
+ | DOPN (MutInd ind_sp, cl) as t ->
+ (basename (path_of_inductive_path ind_sp))
+ ::(Array.fold_left collect acc cl)
+ | DOPN (MutConstruct cstr_sp, cl) as t ->
+ (basename (path_of_constructor_path cstr_sp))
+ ::(Array.fold_left collect acc cl)
+ | DOPN(_,cl) -> Array.fold_left collect acc cl
+ | DOP1(_,c) -> collect acc c
+ | DOP2(_,c1,c2) -> collect (collect acc c1) c2
+ | DOPL(_,cl) -> List.fold_left collect acc cl
+ | DLAM(_,c) -> collect acc c
+ | DLAMV(_,v) -> Array.fold_left collect acc v
+ | _ -> acc
+ in
+ list_uniquize (collect [] t)
+
+let used_of = global_vars_and_consts
+let ids_of_env = Sign.ids_of_env
+
+
+(****************************************************************************)
+(* Tools for printing of Cases *)
+(* These functions implement a light form of Termenv.mind_specif_of_mind *)
+(* specially for handle Cases printing; they respect arities but not typing *)
+
+let indsp_of_id id =
+ let (oper,_) =
+ try
+ let sp = Nametab.sp_of_id CCI id in global_operator sp id
+ with Not_found ->
+ error ("Cannot find reference "^(string_of_id id))
+ in
+ match oper with
+ | MutInd(sp,tyi) -> (sp,tyi)
+ | _ -> errorlabstrm "indsp_of_id"
+ [< 'sTR ((string_of_id id)^" is not an inductive type") >]
+
+let mind_specif_of_mind_light (sp,tyi) =
+ let mib = Global.lookup_mind sp in
+ (mib,mind_nth_type_packet mib tyi)
+
+let rec remove_indtypes = function
+ | (1, DLAMV(_,cl)) -> cl
+ | (n, DLAM (_,c)) -> remove_indtypes (n-1, c)
+ | _ -> anomaly "remove_indtypes: bad list of constructors"
+
+let rec remove_params n t =
+ if n = 0 then
+ t
+ else
+ match t with
+ | DOP2(Prod,_,DLAM(_,c)) -> remove_params (n-1) c
+ | DOP2(Cast,c,_) -> remove_params n c
+ | _ -> anomaly "remove_params : insufficiently quantified"
+
+let rec get_params = function
+ | DOP2(Prod,_,DLAM(x,c)) -> x::(get_params c)
+ | DOP2(Cast,c,_) -> get_params c
+ | _ -> []
+
+let lc_of_lmis (mib,mip) =
+ let lc = remove_indtypes (mib.mind_ntypes,mip.mind_lc) in
+ Array.map (remove_params mib.mind_nparams) lc
+
+let sp_of_spi ((sp,_) as spi) =
+ let (_,mip) = mind_specif_of_mind_light spi in
+ let (pa,_,k) = repr_path sp in
+ make_path pa (mip.mind_typename) k
+
+
+(* Parameterization of the translation from constr to ast *)
+
+(* Tables for Cases printing under a "if" form, a "let" form, *)
+
+let isomorphic_to_bool lc =
+ let lcparams = Array.map get_params lc in
+ Array.length lcparams = 2 & lcparams.(0) = [] & lcparams.(1) = []
+
+let isomorphic_to_tuple lc = (Array.length lc = 1)
+
+module PrintingCasesMake =
+ functor (Test : sig
+ val test : constr array -> bool
+ val error_message : string
+ val member_message : identifier -> bool -> string
+ val field : string
+ val title : string
+ end) ->
+ struct
+ type t = section_path * int
+ let encode = indsp_of_id
+ let check indsp =
+ if not (Test.test (lc_of_lmis (mind_specif_of_mind_light indsp))) then
+ errorlabstrm "check_encode" [< 'sTR Test.error_message >]
+ let decode = sp_of_spi
+ let key = Goptions.SecondaryTable ("Printing",Test.field)
+ let title = Test.title
+ let member_message = Test.member_message
+ let synchronous = true
+ end
+
+module PrintingCasesIf =
+ PrintingCasesMake (struct
+ let test = isomorphic_to_bool
+ let error_message = "This type cannot be seen as a boolean type"
+ let field = "If"
+ let title = "Types leading to pretty-printing of Cases using a `if' form: "
+ let member_message id = function
+ | true ->
+ "Cases on elements of " ^ (string_of_id id)
+ ^ " are printed using a `if' form"
+ | false ->
+ "Cases on elements of " ^ (string_of_id id)
+ ^ " are not printed using `if' form"
+ end)
+
+module PrintingCasesLet =
+ PrintingCasesMake (struct
+ let test = isomorphic_to_tuple
+ let error_message = "This type cannot be seen as a tuple type"
+ let field = "Let"
+ let title =
+ "Types leading to a pretty-printing of Cases using a `let' form:"
+ let member_message id = function
+ | true ->
+ "Cases on elements of " ^ (string_of_id id)
+ ^ " are printed using a `let' form"
+ | false ->
+ "Cases on elements of " ^ (string_of_id id)
+ ^ " are not printed using a `let' form"
+ end)
+
+module PrintingIf = Goptions.MakeTable(PrintingCasesIf)
+module PrintingLet = Goptions.MakeTable(PrintingCasesLet)
+
+let force_let indsp = PrintingLet.active indsp
+let force_if indsp = PrintingIf.active indsp
+
+(* Options for printing or not wildcard and synthetisable types *)
+
+open Goptions
+
+let wildcard_value = ref true
+let force_wildcard () = !wildcard_value
+
+let _ =
+ declare_async_bool_option
+ { optasyncname = "the forced wildcard option";
+ optasynckey = SecondaryTable ("Printing","Wildcard");
+ optasyncread = force_wildcard;
+ optasyncwrite = (fun v -> wildcard_value := v) }
+
+let synth_type_value = ref true
+let synthetize_type () = !synth_type_value
+
+let _ =
+ declare_async_bool_option
+ { optasyncname = "the synthesisablity";
+ optasynckey = SecondaryTable ("Printing","Synth");
+ optasyncread = synthetize_type;
+ optasyncwrite = (fun v -> synth_type_value := v) }
+
+(* Auxiliary function for MutCase printing *)
+(* [computable] tries to tell if the predicate typing the result is inferable*)
+
+let computable p k =
+ (* We first remove as many lambda as the arity, then we look
+ if it remains a lambda for a dependent elimination. This function
+ works for normal eta-expanded term. For non eta-expanded or
+ non-normal terms, it may affirm the pred is synthetisable
+ because of an undetected ultimate dependent variable in the second
+ clause, or else, it may affirms the pred non synthetisable
+ because of a non normal term in the fourth clause.
+ A solution could be to store, in the MutCase, the eta-expanded
+ normal form of pred to decide if it depends on its variables
+
+ Lorsque le prédicat est dépendant de manière certaine, on
+ ne déclare pas le prédicat synthétisable (même si la
+ variable dépendante ne l'est pas effectivement) parce que
+ sinon on perd la réciprocité de la synthèse (qui, lui,
+ engendrera un prédicat non dépendant) *)
+
+ let rec striprec = function
+ | (0,DOP2(Lambda,_,DLAM(_,d))) -> false
+ | (0,d ) -> noccur_bet 1 k d
+ | (n,DOP2(Lambda,_,DLAM(_,d))) -> striprec (n-1,d)
+ | _ -> false
+ in
+ striprec (k,p)
+
+let ids_of_var cl =
+ List.map
+ (function
+ | RRef (_,RVar id) -> id
+ | _-> anomaly "ids_of_var")
+ (Array.to_list cl)
+
+let lookup_name_as_renamed env t s =
+ let rec lookup avoid env n = function
+ DOP2(Prod,_,DLAM(name,c')) ->
+ (match concrete_name avoid env name c' with
+ (Some id,avoid') ->
+ if id=s then (Some n)
+ else lookup avoid' (add_rel (Name id,()) env) (n+1) c'
+ | (None,avoid') -> lookup avoid' env (n+1) (pop c'))
+ | DOP2(Cast,c,_) -> lookup avoid env n c
+ | _ -> None
+ in lookup (ids_of_env env) env 1 t
+
+let lookup_index_as_renamed t n =
+ let rec lookup n d = function
+ DOP2(Prod,_,DLAM(name,c')) ->
+ (match concrete_name [] (gLOB nil_sign) name c' with
+ (Some _,_) -> lookup n (d+1) c'
+ | (None ,_) -> if n=1 then Some d else lookup (n-1) (d+1) c')
+ | DOP2(Cast,c,_) -> lookup n d c
+ | _ -> None
+ in lookup n 1 t
+
+exception StillDLAM
+
+let rec detype avoid env t =
+ match collapse_appl t with
+ (* Not well-formed constructions *)
+ | DLAM _ | DLAMV _ -> raise StillDLAM
+ (* Well-formed constructions *)
+ | regular_constr ->
+ (match kind_of_term regular_constr with
+ | IsRel n ->
+ (try match fst (lookup_rel n env) with
+ | Name id -> RRef (dummy_loc, RVar id)
+ | Anonymous -> anomaly "detype: index to an anonymous variable"
+ with Not_found ->
+ let s = "[REL "^(string_of_int (n - List.length (get_rels env)))^"]"
+ in RRef (dummy_loc, RVar (id_of_string s)))
+ | IsMeta n -> RRef (dummy_loc,RMeta n)
+ | IsVar id -> RRef (dummy_loc,RVar id)
+ | IsXtra s -> warning "bdize: Xtra should no longer occur in constr";
+ RRef(dummy_loc,RVar (id_of_string ("XTRA"^s)))
+ (* ope("XTRA",((str s):: pl@(List.map detype cl)))*)
+ | IsSort (Prop c) -> RSort (dummy_loc,RProp c)
+ | IsSort (Type _) -> RSort (dummy_loc,RType)
+ | IsCast (c1,c2) ->
+ RCast(dummy_loc,detype avoid env c1,detype avoid env c2)
+ | IsProd (na,ty,c) -> detype_binder BProd avoid env na ty c
+ | IsLambda (na,ty,c) -> detype_binder BLambda avoid env na ty c
+ | IsAppL (f,args) ->
+ RApp (dummy_loc,detype avoid env f,List.map (detype avoid env) args)
+ | IsConst (sp,cl) ->
+ RRef(dummy_loc,RConst(sp,ids_of_var (Array.map (detype avoid env) cl)))
+ | IsEvar (ev,cl) ->
+ RRef(dummy_loc,REVar(ev,ids_of_var (Array.map (detype avoid env) cl)))
+ | IsAbst (sp,cl) ->
+ anomaly "bdize: Abst should no longer occur in constr"
+ | IsMutInd (ind_sp,cl) ->
+ let ids = ids_of_var (Array.map (detype avoid env) cl) in
+ RRef (dummy_loc,RInd (ind_sp,ids))
+ | IsMutConstruct (cstr_sp,cl) ->
+ let ids = ids_of_var (Array.map (detype avoid env) cl) in
+ RRef (dummy_loc,RConstruct (cstr_sp,ids))
+ | IsMutCase (annot,p,c,bl) ->
+ let synth_type = synthetize_type () in
+ let tomatch = detype avoid env c in
+ begin
+ match annot with
+(* | None -> (* Pas d'annotation --> affichage avec vieux Case *)
+ warning "Printing in old Case syntax";
+ ROldCase (dummy_loc,false,Some (detype avoid env p),
+ tomatch,Array.map (detype avoid env) bl)
+ | Some *) indsp ->
+ let (mib,mip as lmis) = mind_specif_of_mind_light indsp in
+ let lc = lc_of_lmis lmis in
+ let lcparams = Array.map get_params lc in
+ let k = (nb_prod mip.mind_arity.body) -
+ mib.mind_nparams in
+ let pred =
+ if synth_type & computable p k & lcparams <> [||] then
+ None
+ else
+ Some (detype avoid env p)
+ in
+ let constructs =
+ Array.init
+ (Array.length mip.mind_consnames)
+ (fun i -> ((indsp,i+1),[] (* on triche *))) in
+ let eqnv =
+ array_map3 (detype_eqn avoid env) constructs lcparams bl in
+ let eqnl = Array.to_list eqnv in
+ let tag =
+ if PrintingLet.active indsp then
+ PrintLet
+ else if PrintingIf.active indsp then
+ PrintIf
+ else
+ PrintCases
+ in
+ RCases (dummy_loc,tag,pred,[tomatch],eqnl)
+ end
+
+ | IsFix (nv,n,cl,lfn,vt) -> detype_fix (RFix (nv,n)) avoid env cl lfn vt
+ | IsCoFix (n,cl,lfn,vt) -> detype_fix (RCofix n) avoid env cl lfn vt)
+
+and detype_fix fk avoid env cl lfn vt =
+ let lfi = List.map (fun id -> next_name_away id avoid) lfn in
+ let def_avoid = lfi@avoid in
+ let def_env =
+ List.fold_left (fun env id -> add_rel (Name id,()) env) env lfi in
+ RRec(dummy_loc,fk,Array.of_list lfi,Array.map (detype avoid env) cl,
+ Array.map (detype def_avoid def_env) vt)
+
+
+and detype_eqn avoid env constr_id construct_params branch =
+ let make_pat x avoid env b ids =
+ if not (force_wildcard ()) or (dependent (Rel 1) b) then
+ let id = next_name_away_with_default "x" x avoid in
+ PatVar (dummy_loc,Name id),id::avoid,(add_rel (Name id,()) env),id::ids
+ else
+ PatVar (dummy_loc,Anonymous),avoid,(add_rel (Anonymous,()) env),ids
+ in
+ let rec buildrec ids patlist avoid env = function
+ | _::l, DOP2(Lambda,_,DLAM(x,b)) ->
+ let pat,new_avoid,new_env,new_ids = make_pat x avoid env b ids in
+ buildrec new_ids (pat::patlist) new_avoid new_env (l,b)
+
+ | l , DOP2(Cast,b,_) -> (* Oui, il y a parfois des cast *)
+ buildrec ids patlist avoid env (l,b)
+
+ | x::l, b -> (* eta-expansion : n'arrivera plus lorsque tous les
+ termes seront construits à partir de la syntaxe Cases *)
+ (* nommage de la nouvelle variable *)
+ let new_b = DOPN(AppL,[|lift 1 b; Rel 1|]) in
+ let pat,new_avoid,new_env,new_ids = make_pat x avoid env new_b ids in
+ buildrec new_ids (pat::patlist) new_avoid new_env (l,new_b)
+
+ | [] , rhs ->
+ (ids, [PatCstr(dummy_loc, constr_id, List.rev patlist,Anonymous)],
+ detype avoid env rhs)
+ in
+ buildrec [] [] avoid env (construct_params,branch)
+
+and detype_binder bk avoid env na ty c =
+ let na',avoid' = match concrete_name avoid env na c with
+ | (Some id,l') -> (Name id), l'
+ | (None,l') -> Anonymous, l' in
+ RBinder (dummy_loc,bk,
+ na',detype [] env ty,
+ detype avoid' (add_rel (na',()) env) c)
diff --git a/pretyping/detyping.mli b/pretyping/detyping.mli
new file mode 100644
index 0000000000..8f51823f49
--- /dev/null
+++ b/pretyping/detyping.mli
@@ -0,0 +1,27 @@
+
+(* $Id$ *)
+
+(*i*)
+open Names
+open Term
+open Sign
+open Rawterm
+(*i*)
+
+(* [detype avoid env c] turns [c], typed in [env], into a rawconstr. *)
+(* De Bruijn indexes are turned to bound names, avoiding names in [avoid] *)
+
+exception StillDLAM
+
+val detype : identifier list -> unit assumptions -> constr -> rawconstr
+
+(* look for the index of a named var or a nondep var as it is renamed *)
+val lookup_name_as_renamed :
+ unit assumptions -> constr -> identifier -> int option
+val lookup_index_as_renamed : constr -> int -> int option
+
+
+val force_wildcard : unit -> bool
+val synthetize_type : unit -> bool
+val force_if : inductive_path -> bool
+val force_let : inductive_path -> bool