summaryrefslogtreecommitdiff
path: root/parsing/termast.ml
diff options
context:
space:
mode:
Diffstat (limited to 'parsing/termast.ml')
-rw-r--r--parsing/termast.ml503
1 files changed, 503 insertions, 0 deletions
diff --git a/parsing/termast.ml b/parsing/termast.ml
new file mode 100644
index 00000000..47e45d42
--- /dev/null
+++ b/parsing/termast.ml
@@ -0,0 +1,503 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: termast.ml,v 1.78.2.1 2004/07/16 19:30:42 herbelin Exp $ *)
+
+open Pp
+open Util
+open Univ
+open Names
+open Nameops
+open Term
+open Termops
+open Inductive
+open Sign
+open Environ
+open Libnames
+open Declare
+open Impargs
+open Coqast
+open Ast
+open Rawterm
+open Pattern
+open Nametab
+
+(* In this file, we translate rawconstr to ast, in order to print constr *)
+
+(**********************************************************************)
+(* Parametrization *)
+open Constrextern
+(*
+(* This governs printing of local context of references *)
+let print_arguments = ref false
+
+(* If true, prints local context of evars, whatever print_arguments *)
+let print_evar_arguments = ref false
+*)
+
+(* This forces printing of cast nodes *)
+let print_casts = ref true
+
+(*
+(* This governs printing of implicit arguments. When
+ [print_implicits] is on then [print_implicits_explicit_args] tells
+ how implicit args are printed. If on, implicit args are printed
+ prefixed by "!" otherwise the function and not the arguments is
+ prefixed by "!" *)
+let print_implicits = ref false
+*)
+let print_implicits_explicit_args = ref false
+
+(*
+(* This forces printing of coercions *)
+let print_coercions = ref false
+
+(* This forces printing universe names of Type{.} *)
+let print_universes = ref false
+
+
+let with_option o f x =
+ let old = !o in o:=true;
+ try let r = f x in o := old; r
+ with e -> o := old; raise e
+
+let with_arguments f = with_option print_arguments f
+let with_casts f = with_option print_casts f
+let with_implicits f = with_option print_implicits f
+let with_coercions f = with_option print_coercions f
+let with_universes f = with_option print_universes f
+*)
+(**********************************************************************)
+(* conversion of references *)
+
+let ids_of_ctxt ctxt =
+ Array.to_list
+ (Array.map
+ (function c -> match kind_of_term c with
+ | Var id -> id
+ | _ ->
+ error
+ "Termast: arbitrary substitution of references not yet implemented")
+ ctxt)
+
+let ast_of_ident id = nvar id
+
+let ast_of_name = function
+ | Name id -> nvar id
+ | Anonymous -> nvar wildcard
+
+let idopt_of_name = function
+ | Name id -> Some id
+ | Anonymous -> None
+
+let ast_of_binders bl =
+ List.map (fun (nal,isdef,ty) ->
+ if isdef then ope("LETBINDER",ty::List.map ast_of_name nal)
+ else ope("BINDER",ty::List.map ast_of_name nal)) bl
+
+let ast_type_of_binder bl t =
+ List.fold_right (fun (nal,isdef,ty) ast ->
+ if isdef then
+ ope("LETIN",[ty;slam(idopt_of_name (List.hd nal),ast)])
+ else
+ ope("PROD",[ty;List.fold_right
+ (fun na ast -> slam(idopt_of_name na,ast)) nal ast]))
+ bl t
+
+let ast_body_of_binder bl t =
+ List.fold_right (fun (nal,isdef,ty) ast ->
+ if isdef then
+ ope("LETIN",[ty;slam(idopt_of_name (List.hd nal),ast)])
+ else
+ ope("LAMBDA",[ty;List.fold_right
+ (fun na ast -> slam(idopt_of_name na,ast)) nal ast]))
+ bl t
+
+let ast_of_constant_ref sp =
+ ope("CONST", [path_section dummy_loc sp])
+
+let ast_of_existential_ref ev =
+(*
+ let ev =
+ try int_of_string (string_of_id ev)
+ with _ -> warning "cannot find existential variable number"; 0 in
+*)
+ ope("EVAR", [num ev])
+
+let ast_of_constructor_ref ((sp,tyi),n) =
+ ope("MUTCONSTRUCT",[path_section dummy_loc sp; num tyi; num n])
+
+let ast_of_inductive_ref (sp,tyi) =
+ ope("MUTIND", [path_section dummy_loc sp; num tyi])
+
+let ast_of_section_variable_ref s =
+ ope("SECVAR", [nvar s])
+
+let ast_of_qualid p =
+ let dir, s = repr_qualid p in
+ let args = List.map nvar ((List.rev(repr_dirpath dir))@[s]) in
+ ope ("QUALID", args)
+
+let ast_of_ref = function
+ | ConstRef sp -> ast_of_constant_ref sp
+ | IndRef sp -> ast_of_inductive_ref sp
+ | ConstructRef sp -> ast_of_constructor_ref sp
+ | VarRef id -> ast_of_section_variable_ref id
+
+(**********************************************************************)
+(* conversion of patterns *)
+
+let rec ast_of_cases_pattern = function (* loc is thrown away for printing *)
+ | PatVar (loc,Name id) -> nvar id
+ | PatVar (loc,Anonymous) -> nvar wildcard
+ | PatCstr(loc,cstrsp,args,Name id) ->
+ let args = List.map ast_of_cases_pattern args in
+ ope("PATTAS",
+ [nvar id;
+ ope("PATTCONSTRUCT", (ast_of_constructor_ref cstrsp)::args)])
+ | PatCstr(loc,cstrsp,args,Anonymous) ->
+ ope("PATTCONSTRUCT",
+ (ast_of_constructor_ref cstrsp)
+ :: List.map ast_of_cases_pattern args)
+
+let ast_dependent na aty =
+ match na with
+ | Name id -> occur_var_ast id aty
+ | Anonymous -> false
+
+let decompose_binder = function
+ | RProd(_,na,ty,c) -> Some (BProd,na,ty,c)
+ | RLambda(_,na,ty,c) -> Some (BLambda,na,ty,c)
+ | RLetIn(_,na,b,c) -> Some (BLetIn,na,b,c)
+ | _ -> None
+
+(* Implicit args indexes are in ascending order *)
+let explicitize impl args =
+ let n = List.length args in
+ let rec exprec q = function
+ | a::args, imp::impl when is_status_implicit imp ->
+ let tail = exprec (q+1) (args,impl) in
+ let visible =
+ (!print_implicits & !print_implicits_explicit_args)
+ or not (is_inferable_implicit false n imp) in
+ if visible then ope("EXPL", [num q; a]) :: tail else tail
+ | a::args, _::impl -> a :: exprec (q+1) (args,impl)
+ | args, [] -> args (* In case of polymorphism *)
+ | [], _ -> []
+ in exprec 1 (args,impl)
+
+let rec skip_coercion dest_ref (f,args as app) =
+ if !print_coercions then app
+ else
+ try
+ match dest_ref f with
+ | Some r ->
+ (match Classops.hide_coercion r with
+ | Some n ->
+ if n >= List.length args then app
+ else (* We skip a coercion *)
+ let fargs = list_skipn n args in
+ skip_coercion dest_ref (List.hd fargs,List.tl fargs)
+ | None -> app)
+ | None -> app
+ with Not_found -> app
+
+let ast_of_app impl f args =
+ if !print_implicits & not !print_implicits_explicit_args then
+ ope("APPLISTEXPL", f::args)
+ else
+ let args = explicitize impl args in
+ if args = [] then f else ope("APPLIST", f::args)
+
+let rec ast_of_raw = function
+ | RRef (_,ref) -> ast_of_ref ref
+ | RVar (_,id) -> ast_of_ident id
+ | REvar (_,n,_) -> (* we drop args *) ast_of_existential_ref n
+ | RPatVar (_,(_,n)) -> ope("META",[ast_of_ident n])
+ | RApp (_,f,args) ->
+ let (f,args) =
+ skip_coercion (function RRef(_,r) -> Some r | _ -> None) (f,args) in
+ let astf = ast_of_raw f in
+ let astargs = List.map ast_of_raw args in
+ (match f with
+ | RRef (_,ref) -> ast_of_app (implicits_of_global ref) astf astargs
+ | _ -> ast_of_app [] astf astargs)
+
+ | RProd (_,Anonymous,t,c) ->
+ (* Anonymous product are never factorized *)
+ ope("ARROW",[ast_of_raw t; slam(None,ast_of_raw c)])
+
+ | RLetIn (_,na,t,c) ->
+ ope("LETIN",[ast_of_raw t; slam(idopt_of_name na,ast_of_raw c)])
+
+ | RProd (_,na,t,c) ->
+ let (n,a) = factorize_binder 1 BProd na (ast_of_raw t) c in
+ (* PROD et PRODLIST doivent être distingués à cause du cas *)
+ (* non dépendant, pour isoler l'implication; peut-être un *)
+ (* constructeur ARROW serait-il plus justifié ? *)
+ let tag = if n=1 then "PROD" else "PRODLIST" in
+ ope(tag,[ast_of_raw t;a])
+
+ | RLambda (_,na,t,c) ->
+ let (n,a) = factorize_binder 1 BLambda na (ast_of_raw t) c in
+ (* LAMBDA et LAMBDALIST se comportent pareil ... Non ! *)
+ (* Pour compatibilité des theories, il faut LAMBDALIST partout *)
+ ope("LAMBDALIST",[ast_of_raw t;a])
+
+ | RCases (_,(typopt,_),tml,eqns) ->
+ let pred = ast_of_rawopt typopt in
+ let tag = "CASES" in
+ let asttomatch =
+ ope("TOMATCH", List.map (fun (tm,_) -> ast_of_raw tm) tml) in
+ let asteqns = List.map ast_of_eqn eqns in
+ ope(tag,pred::asttomatch::asteqns)
+
+ | ROrderedCase (_,LetStyle,typopt,tm,[|bv|],_) ->
+ let nvar' = function Anonymous -> nvar wildcard | Name id -> nvar id in
+ let rec f l = function
+ | RLambda (_,na,RHole _,c) -> f (nvar' na :: l) c
+ | RLetIn (_,na,RHole _,c) -> f (nvar' na :: l) c
+ | c -> List.rev l, ast_of_raw c in
+ let l,c = f [] bv in
+ let eqn = ope ("EQN", [c;ope ("PATTCONSTRUCT",(nvar wildcard)::l)]) in
+ ope ("FORCELET",[(ast_of_rawopt typopt);(ast_of_raw tm);eqn])
+
+ | ROrderedCase (_,st,typopt,tm,bv,_) ->
+ let tag = match st with
+ | IfStyle -> "FORCEIF"
+ | RegularStyle -> "CASE"
+ | MatchStyle | LetStyle -> "MATCH"
+ in
+
+ (* warning "Old Case syntax"; *)
+ ope(tag,(ast_of_rawopt typopt)
+ ::(ast_of_raw tm)
+ ::(Array.to_list (Array.map ast_of_raw bv)))
+
+ | RLetTuple _ | RIf _ ->
+ error "Let tuple not supported in v7"
+
+ | RRec (_,fk,idv,blv,tyv,bv) ->
+ let alfi = Array.map ast_of_ident idv in
+ (match fk with
+ | RFix (nv,n) ->
+ let rec split_lambda binds = function
+ | (0, t) -> (List.rev binds,ast_of_raw t)
+ | (n, RLetIn (_,na,b,c)) ->
+ let bind = ope("LETBINDER",[ast_of_raw b;ast_of_name na]) in
+ split_lambda (bind::binds) (n,c)
+ | (n, RLambda (_,na,t,b)) ->
+ let bind = ope("BINDER",[ast_of_raw t;ast_of_name na]) in
+ split_lambda (bind::binds) (n-1,b)
+ | _ -> anomaly "ast_of_rawconst: ill-formed fixpoint body" in
+ let rec split_product = function
+ | (0, t) -> ast_of_raw t
+ | (n, RLetIn (_,na,_,c)) -> split_product (n,c)
+ | (n, RProd (_,na,t,b)) -> split_product (n-1,b)
+ | _ -> anomaly "ast_of_rawconst: ill-formed fixpoint type" in
+ let listdecl =
+ Array.mapi
+ (fun i fi ->
+ if List.length blv.(i) >= nv.(i)+1 then
+ let (oldfixp,factb) = list_chop (nv.(i)+1) blv.(i) in
+ let bl = factorize_local_binder oldfixp in
+ let factb = factorize_local_binder factb in
+ let asttyp = ast_type_of_binder factb
+ (ast_of_raw tyv.(i)) in
+ let astdef = ast_body_of_binder factb
+ (ast_of_raw bv.(i)) in
+ ope("FDECL",[fi;ope("BINDERS",ast_of_binders bl);
+ asttyp; astdef])
+ else
+ let n = nv.(i)+1 - List.length blv.(i) in
+ let (lparams,astdef) =
+ split_lambda [] (n,bv.(i)) in
+ let bl = factorize_local_binder blv.(i) in
+ let lparams = ast_of_binders bl @ lparams in
+ let asttyp = split_product (n,tyv.(i)) in
+ ope("FDECL",
+ [fi; ope ("BINDERS",lparams);
+ asttyp; astdef]))
+ alfi
+ in
+ ope("FIX", alfi.(n)::(Array.to_list listdecl))
+ | RCoFix n ->
+ let listdecl =
+ Array.mapi
+ (fun i fi ->
+ let bl = factorize_local_binder blv.(i) in
+ let asttyp = ast_type_of_binder bl (ast_of_raw tyv.(i)) in
+ let astdef = ast_body_of_binder bl (ast_of_raw bv.(i)) in
+ ope("CFDECL",[fi; asttyp; astdef]))
+ alfi
+ in
+ ope("COFIX", alfi.(n)::(Array.to_list listdecl)))
+
+ | RSort (_,s) ->
+ (match s with
+ | RProp Null -> ope("PROP",[])
+ | RProp Pos -> ope("SET",[])
+ | RType (Some u) when !print_universes -> ope("TYPE",[ide(Univ.string_of_univ u)])
+ | RType _ -> ope("TYPE",[]))
+ | RHole _ -> ope("ISEVAR",[])
+ | RCast (_,c,t) -> ope("CAST",[ast_of_raw c;ast_of_raw t])
+ | RDynamic (loc,d) -> Dynamic (loc,d)
+
+and ast_of_eqn (_,ids,pl,c) =
+ ope("EQN", (ast_of_raw c)::(List.map ast_of_cases_pattern pl))
+
+and ast_of_rawopt = function
+ | None -> (string "SYNTH")
+ | Some p -> ast_of_raw p
+
+and factorize_binder n oper na aty c =
+ let (p,body) = match decompose_binder c with
+ | Some (oper',na',ty',c')
+ when (oper = oper') & (aty = ast_of_raw ty')
+ & not (ast_dependent na aty) (* To avoid na in ty' escapes scope *)
+ & not (na' = Anonymous & oper = BProd)
+ -> factorize_binder (n+1) oper na' aty c'
+ | _ -> (n,ast_of_raw c)
+ in
+ (p,slam(idopt_of_name na, body))
+
+and factorize_local_binder = function
+ [] -> []
+ | (na,Some bd,ty)::l ->
+ ([na],true,ast_of_raw bd) :: factorize_local_binder l
+ | (na,None,ty)::l ->
+ let ty = ast_of_raw ty in
+ (match factorize_local_binder l with
+ (lna,false,ty') :: l when ty=ty' ->
+ (na::lna,false,ty') :: l
+ | l -> ([na],false,ty) :: l)
+
+
+let ast_of_rawconstr = ast_of_raw
+
+(******************************************************************)
+(* Main translation function from constr -> ast *)
+
+let ast_of_constr at_top env t =
+ let t' =
+ if !print_casts then t
+ else Reductionops.local_strong strip_outer_cast t in
+ let avoid = if at_top then ids_of_context env else [] in
+ ast_of_raw
+ (Detyping.detype (at_top,env) avoid (names_of_rel_context env) t')
+
+let ast_of_constant env sp =
+ let a = ast_of_constant_ref sp in
+ a
+
+let ast_of_existential env (ev,ids) =
+ let a = ast_of_existential_ref ev in
+ if !print_arguments or !print_evar_arguments then
+ ope("INSTANCE",a::(array_map_to_list (ast_of_constr false env) ids))
+ else a
+
+let ast_of_constructor env cstr_sp =
+ let a = ast_of_constructor_ref cstr_sp in
+ a
+
+let ast_of_inductive env ind_sp =
+ let a = ast_of_inductive_ref ind_sp in
+ a
+
+let decompose_binder_pattern = function
+ | PProd(na,ty,c) -> Some (BProd,na,ty,c)
+ | PLambda(na,ty,c) -> Some (BLambda,na,ty,c)
+ | PLetIn(na,b,c) -> Some (BLetIn,na,b,c)
+ | _ -> None
+
+let rec ast_of_pattern tenv env = function
+ | PRef ref -> ast_of_ref ref
+
+ | PVar id -> ast_of_ident id
+
+ | PEvar (n,_) -> ast_of_existential_ref n
+
+ | PRel n ->
+ (try match lookup_name_of_rel n env with
+ | Name id -> ast_of_ident id
+ | Anonymous ->
+ anomaly "ast_of_pattern: index to an anonymous variable"
+ with Not_found ->
+ nvar (id_of_string ("[REL "^(string_of_int n)^"]")))
+
+ | PApp (f,args) ->
+ let (f,args) =
+ skip_coercion (function PRef r -> Some r | _ -> None)
+ (f,Array.to_list args) in
+ let astf = ast_of_pattern tenv env f in
+ let astargs = List.map (ast_of_pattern tenv env) args in
+ (match f with
+ | PRef ref -> ast_of_app (implicits_of_global ref) astf astargs
+ | _ -> ast_of_app [] astf astargs)
+
+ | PSoApp (n,args) ->
+ ope("SOAPP",(ope ("META",[ast_of_ident n]))::
+ (List.map (ast_of_pattern tenv env) args))
+
+ | PLetIn (na,b,c) ->
+ let c' = ast_of_pattern tenv (add_name na env) c in
+ ope("LETIN",[ast_of_pattern tenv env b;slam(idopt_of_name na,c')])
+
+ | PProd (Anonymous,t,c) ->
+ ope("PROD",[ast_of_pattern tenv env t;
+ slam(None,ast_of_pattern tenv env c)])
+ | PProd (na,t,c) ->
+ let env' = add_name na env in
+ let (n,a) =
+ factorize_binder_pattern tenv env' 1 BProd na
+ (ast_of_pattern tenv env t) c in
+ (* PROD et PRODLIST doivent être distingués à cause du cas *)
+ (* non dépendant, pour isoler l'implication; peut-être un *)
+ (* constructeur ARROW serait-il plus justifié ? *)
+ let tag = if n=1 then "PROD" else "PRODLIST" in
+ ope(tag,[ast_of_pattern tenv env t;a])
+ | PLambda (na,t,c) ->
+ let env' = add_name na env in
+ let (n,a) =
+ factorize_binder_pattern tenv env' 1 BLambda na
+ (ast_of_pattern tenv env t) c in
+ (* LAMBDA et LAMBDALIST se comportent pareil *)
+ let tag = if n=1 then "LAMBDA" else "LAMBDALIST" in
+ ope(tag,[ast_of_pattern tenv env t;a])
+
+ | PCase (st,typopt,tm,bv) ->
+ warning "Old Case syntax";
+ ope("MUTCASE",(ast_of_patopt tenv env typopt)
+ ::(ast_of_pattern tenv env tm)
+ ::(Array.to_list (Array.map (ast_of_pattern tenv env) bv)))
+
+ | PSort s ->
+ (match s with
+ | RProp Null -> ope("PROP",[])
+ | RProp Pos -> ope("SET",[])
+ | RType _ -> ope("TYPE",[]))
+
+ | PMeta (Some n) -> ope("META",[ast_of_ident n])
+ | PMeta None -> ope("ISEVAR",[])
+ | PFix f -> ast_of_raw (Detyping.detype (false,tenv) [] env (mkFix f))
+ | PCoFix c -> ast_of_raw (Detyping.detype (false,tenv) [] env (mkCoFix c))
+
+and ast_of_patopt tenv env = function
+ | None -> (string "SYNTH")
+ | Some p -> ast_of_pattern tenv env p
+
+and factorize_binder_pattern tenv env n oper na aty c =
+ let (p,body) = match decompose_binder_pattern c with
+ | Some (oper',na',ty',c')
+ when (oper = oper') & (aty = ast_of_pattern tenv env ty')
+ & not (na' = Anonymous & oper = BProd)
+ ->
+ factorize_binder_pattern tenv (add_name na' env) (n+1) oper na' aty c'
+ | _ -> (n,ast_of_pattern tenv env c)
+ in
+ (p,slam(idopt_of_name na, body))