(* $Id$ *) open Pp open Util open Options open Generic open Term open Declarations open Inductive open Reduction open Tacred open Declare open Names open Coqast open Ast open Library open Libobject open Astterm let mkCastC(c,t) = ope("CAST",[c;t]) let mkLambdaC(x,a,b) = ope("LAMBDA",[a;slam(Some (string_of_id x),b)]) let mkLambdaCit = List.fold_right (fun (x,a) b -> mkLambdaC(x,a,b)) let mkProdC (x,a,b) = ope("PROD",[a;slam(Some (string_of_id x),b)]) let mkProdCit = List.fold_right (fun (x,a) b -> mkProdC(x,a,b)) (* Commands of the interface *) (* 1| Constant definitions *) let constant_entry_of_com (com,comtypopt) = let sigma = Evd.empty in let env = Global.env() in match comtypopt with None -> { const_entry_body = Cooked (interp_constr sigma env com); const_entry_type = None } | Some comtyp -> let typ = interp_type sigma env comtyp in { const_entry_body = Cooked (interp_casted_constr sigma env com typ); const_entry_type = Some typ } let red_constant_entry ce = function | None -> ce | Some red -> let body = match ce.const_entry_body with | Cooked c -> c | Recipe _ -> assert false in { const_entry_body = Cooked (reduction_of_redexp red (Global.env()) Evd.empty body); const_entry_type = ce.const_entry_type } let definition_body_red ident n com comtypeopt red_option = let ce = constant_entry_of_com (com,comtypeopt) in let ce' = red_constant_entry ce red_option in declare_constant ident (ce',n); if is_verbose() then message ((string_of_id ident) ^ " is defined") let definition_body ident n com typ = definition_body_red ident n com typ None let syntax_definition ident com = let c = interp_rawconstr Evd.empty (Global.env()) com in Syntax_def.declare_syntactic_definition ident c; if is_verbose() then message ((string_of_id ident) ^ " is now a syntax macro") (***TODO let abstraction_definition ident arity com = let c = raw_interp_constrpattern Evd.empty (Global.env()) com in machine_abstraction ident arity c ***) (* 2| Variable definitions *) let parameter_def_var ident c = let c = interp_type Evd.empty (Global.env()) c in declare_parameter (id_of_string ident) c; if is_verbose() then message (ident ^ " is assumed") let hypothesis_def_var is_refining ident n c = let warning () = mSGERRNL [< 'sTR"Warning: "; 'sTR ident; 'sTR" is declared as a parameter"; 'sTR" because it is at a global level" >] in match n with | NeverDischarge -> warning(); parameter_def_var ident c | DischargeAt disch_sp -> if Lib.is_section_p disch_sp then begin declare_variable (id_of_string ident) (interp_type Evd.empty (Global.env()) c,n,false); if is_verbose() then message (ident ^ " is assumed"); if is_refining then mSGERRNL [< 'sTR"Warning: Variable "; 'sTR ident; 'sTR" is not visible from current goals" >] end else begin warning(); parameter_def_var ident c end (* 3| Mutual Inductive definitions *) let minductive_message = function | [] -> anomaly "no inductive definition" | [x] -> [< print_id x; 'sTR " is defined">] | l -> hOV 0 [< prlist_with_sep pr_coma print_id l; 'sPC; 'sTR "are defined">] let recursive_message = function | [] -> anomaly "no recursive definition" | [x] -> [< print_id x; 'sTR " is recursively defined">] | l -> hOV 0 [< prlist_with_sep pr_coma print_id l; 'sPC; 'sTR "are recursively defined">] let corecursive_message = function | [] -> anomaly "no corecursive definition" | [x] -> [< print_id x; 'sTR " is corecursively defined">] | l -> hOV 0 [< prlist_with_sep pr_coma print_id l; 'sPC; 'sTR "are corecursively defined">] let build_mutual lparams lnamearconstrs finite = let allnames = List.fold_left (fun acc (id,_,l) -> id::(List.map fst l)@acc) [] lnamearconstrs in if not (list_distinct allnames) then error "Two inductive objects have the same name"; let lrecnames = List.map (fun (x,_,_)->x) lnamearconstrs and nparams = List.length lparams and sigma = Evd.empty and env0 = Global.env() in (* let fs = States.freeze() in*) try let mispecvec = let (ind_env,arityl) = List.fold_left (fun (env,arl) (recname,arityc,_) -> let arity = typed_type_of_com Evd.empty env (mkProdCit lparams arityc) in let env' = Environ.push_var (recname,arity) env in (* A quoi cela sert ? declare_variable recname (arity.body,NeverDischarge,false);*) (env', (arity::arl))) (env0,[]) lnamearconstrs in List.map2 (fun ar (name,_,lname_constr) -> let consconstrl = List.map (fun (_,constr) -> interp_constr sigma ind_env (mkProdCit lparams constr)) lname_constr in (name, (body_of_type ar), List.map fst lname_constr, put_DLAMSV_subst (List.rev lrecnames) (Array.of_list consconstrl))) (List.rev arityl) lnamearconstrs in let mie = { mind_entry_nparams = nparams; mind_entry_finite = finite; mind_entry_inds = mispecvec } in (* States.unfreeze fs;*) let sp = declare_mind mie in if is_verbose() then pPNL(minductive_message lrecnames); for i = 0 to List.length mispecvec - 1 do declare_eliminations sp i done with e -> (* States.unfreeze fs; *)raise e (* try to find non recursive definitions *) let list_chop_hd i l = match list_chop i l with | (l1,x::l2) -> (l1,x,l2) | _ -> assert false let collect_non_rec = let rec searchrec lnonrec lnamerec ldefrec larrec nrec = try let i = list_try_find_i (fun i f -> if List.for_all (fun def -> not (occur_var f def)) ldefrec then i else failwith "try_find_i") 0 lnamerec in let (lf1,f,lf2) = list_chop_hd i lnamerec in let (ldef1,def,ldef2) = list_chop_hd i ldefrec in let (lar1,ar,lar2) = list_chop_hd i larrec in let newlnv = try match list_chop i nrec with | (lnv1,_::lnv2) -> (lnv1@lnv2) | _ -> [] (* nrec=[] for cofixpoints *) with Failure "list_chop" -> [] in searchrec ((f,DOP2(Cast,def,body_of_type ar))::lnonrec) (lf1@lf2) (ldef1@ldef2) (lar1@lar2) newlnv with Failure "try_find_i" -> (lnonrec, (lnamerec,ldefrec,larrec,nrec)) in searchrec [] let build_recursive lnameargsardef = let lrecnames = List.map (fun (f,_,_,_) -> f) lnameargsardef and sigma = Evd.empty and env0 = Global.env() and nv = Array.of_list (List.map (fun (_,la,_,_) -> (List.length la) -1) lnameargsardef) in let fs = States.freeze() in let (rec_sign,arityl) = try List.fold_left (fun (env,arl) (recname,lparams,arityc,_) -> let arity = typed_type_of_com Evd.empty env (mkProdCit lparams arityc) in declare_variable recname (body_of_type arity,NeverDischarge,false); (Environ.push_var (recname,arity) env, (arity::arl))) (env0,[]) lnameargsardef with e -> States.unfreeze fs; raise e in let recdef = try List.map (fun (_,lparams,arityc,def) -> interp_constr sigma rec_sign (mkLambdaCit lparams (mkCastC(def,arityc)))) lnameargsardef with e -> States.unfreeze fs; raise e in States.unfreeze fs; let (lnonrec,(lnamerec,ldefrec,larrec,nvrec)) = collect_non_rec lrecnames recdef (List.rev arityl) (Array.to_list nv) in let n = NeverDischarge in if lnamerec <> [] then begin let recvec = [|put_DLAMSV_subst (List.rev lnamerec) (Array.of_list ldefrec)|] in let varrec = Array.of_list larrec in let rec declare i = function | fi::lf -> let ce = { const_entry_body = Cooked (mkFixDlam (Array.of_list nvrec) i varrec recvec); const_entry_type = None } in declare_constant fi (ce, n); declare (i+1) lf | _ -> () in (* declare the recursive definitions *) declare 0 lnamerec; if is_verbose() then pPNL(recursive_message lnamerec) end; (* The others are declared as normal definitions *) let var_subst id = (id,make_substituend (global_reference CCI id)) in let _ = List.fold_left (fun subst (f,def) -> let ce = { const_entry_body = Cooked (Generic.replace_vars subst def); const_entry_type = None } in declare_constant f (ce,n); warning ((string_of_id f)^" is non-recursively defined"); (var_subst f) :: subst) (List.map var_subst lnamerec) lnonrec in () let build_corecursive lnameardef = let lrecnames = List.map (fun (f,_,_) -> f) lnameardef and sigma = Evd.empty and env0 = Global.env() in let fs = States.freeze() in let (rec_sign,arityl) = try List.fold_left (fun (env,arl) (recname,arityc,_) -> let arity = typed_type_of_com Evd.empty env0 arityc in declare_variable recname (body_of_type arity,NeverDischarge,false); (Environ.push_var (recname,arity) env, (arity::arl))) (env0,[]) lnameardef with e -> States.unfreeze fs; raise e in let recdef = try List.map (fun (_,arityc,def) -> interp_constr sigma rec_sign (mkCastC(def,arityc))) lnameardef with e -> States.unfreeze fs; raise e in States.unfreeze fs; let (lnonrec,(lnamerec,ldefrec,larrec,_)) = collect_non_rec lrecnames recdef (List.rev arityl) [] in let n = NeverDischarge in if lnamerec <> [] then begin let recvec = if lnamerec = [] then [||] else [|put_DLAMSV_subst (List.rev lnamerec) (Array.of_list ldefrec)|] in let rec declare i = function | fi::lf -> let ce = { const_entry_body = Cooked (mkCoFixDlam i (Array.of_list larrec) recvec); const_entry_type = None } in declare_constant fi (ce,n); declare (i+1) lf | _ -> () in declare 0 lnamerec; if is_verbose() then pPNL(corecursive_message lnamerec) end; let var_subst id = (id,make_substituend (global_reference CCI id)) in let _ = List.fold_left (fun subst (f,def) -> let ce = { const_entry_body = Cooked (Generic.replace_vars subst def); const_entry_type = None } in declare_constant f (ce,n); warning ((string_of_id f)^" is non-recursively defined"); (var_subst f) :: subst) (List.map var_subst lnamerec) lnonrec in () let inductive_of_ident id = let c = try global_reference CCI id with Not_found -> errorlabstrm "inductive_of_ident" [< 'sTR ((string_of_id id) ^ " not found") >] in match kind_of_term (global_reference CCI id) with | IsMutInd ind -> ind | _ -> errorlabstrm "inductive_of_ident" [< 'sTR (string_of_id id); 'sPC; 'sTR "is not an inductive type" >] let build_scheme lnamedepindsort = let lrecnames = List.map (fun (f,_,_,_) -> f) lnamedepindsort and sigma = Evd.empty and env0 = Global.env() in let lrecspec = List.map (fun (_,dep,indid,sort) -> let s = destSort (interp_constr sigma env0 sort) in (inductive_of_ident indid,dep,s)) lnamedepindsort in let n = NeverDischarge in let listdecl = Indrec.build_mutual_indrec env0 sigma lrecspec in let rec declare decl fi = let ce = { const_entry_body = Cooked decl; const_entry_type = None } in declare_constant fi (ce,n) in List.iter2 declare listdecl lrecnames; if is_verbose() then pPNL(recursive_message lrecnames) let start_proof_com s stre com = let env = Global.env () in Pfedit.start_proof s stre env (interp_type Evd.empty env com) let get_current_context () = try Pfedit.get_current_goal_context () with e when Logic.catchable_exception e -> (Evd.empty, Global.env())