123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(*s Production of Haskell syntax. *)openPpopenCErrorsopenUtilopenNamesopenTableopenMinimlopenMlutilopenCommon(*s Haskell renaming issues. *)letpr_lower_idid=str(String.uncapitalize_ascii(Id.to_stringid))letpr_upper_idid=str(String.capitalize_ascii(Id.to_stringid))letkeywords=List.fold_right(funs->Id.Set.add(Id.of_strings))["Any";"case";"class";"data";"default";"deriving";"do";"else";"family";"forall";"foreign";"if";"import";"in";"infix";"infixl";"infixr";"instance";"let";"mdo";"module";"newtype";"of";"proc";"rec";"then";"type";"where";"_";"__";"as";"qualified";"hiding";"unit";"unsafeCoerce"]Id.Set.emptyletpp_comments=str"-- "++s++fnl()letpp_bracket_comments=str"{- "++hov0s++str" -}"(* Note: do not shorten [str "foo" ++ fnl ()] into [str "foo\n"],
the '\n' character interacts badly with the Format boxing mechanism *)letpreamblemod_namecommentused_modulesusf=letpp_importmp=str("import qualified "^string_of_modfilemp)++fnl()in(ifnot(usf.magic||usf.tunknown)thenmt()elsestr"{-# OPTIONS_GHC -cpp -XMagicHash #-}"++fnl()++str"{- For Hugs, use the option -F\"cpp -P -traditional\" -}"++fnl2())++(matchcommentwith|None->mt()|Somecom->pp_bracket_commentcom++fnl2())++str"module "++pr_upper_idmod_name++str" where"++fnl2()++str"import qualified Prelude"++fnl()++prlistpp_importused_modules++fnl()++(ifnot(usf.magic||usf.tunknown)thenmt()elsestr"#ifdef __GLASGOW_HASKELL__"++fnl()++str"import qualified GHC.Base"++fnl()++str"#if __GLASGOW_HASKELL__ >= 900"++fnl()++str"import qualified GHC.Exts"++fnl()++str"#endif"++fnl()++str"#else"++fnl()++str"-- HUGS"++fnl()++str"import qualified IOExts"++fnl()++str"#endif"++fnl2())++(ifnotusf.magicthenmt()elsestr"#ifdef __GLASGOW_HASKELL__"++fnl()++str"unsafeCoerce :: a -> b"++fnl()++str"#if __GLASGOW_HASKELL__ >= 900"++fnl()++str"unsafeCoerce = GHC.Exts.unsafeCoerce#"++fnl()++str"#else"++fnl()++str"unsafeCoerce = GHC.Base.unsafeCoerce#"++fnl()++str"#endif"++fnl()++str"#else"++fnl()++str"-- HUGS"++fnl()++str"unsafeCoerce :: a -> b"++fnl()++str"unsafeCoerce = IOExts.unsafeCoerce"++fnl()++str"#endif"++fnl2())++(ifnotusf.tunknownthenmt()elsestr"#ifdef __GLASGOW_HASKELL__"++fnl()++str"type Any = GHC.Base.Any"++fnl()++str"#else"++fnl()++str"-- HUGS"++fnl()++str"type Any = ()"++fnl()++str"#endif"++fnl2())++(ifnotusf.mldummythenmt()elsestr"__ :: any"++fnl()++str"__ = Prelude.error \"Logical or arity value used\""++fnl2())letpp_abst=function|[]->(mt())|l->(str"\\"++prlist_with_sep(fun()->(str" "))Id.printl++str" ->"++spc())(*s The pretty-printer for haskell syntax *)letpp_globalkr=ifis_inline_customrthenstr(find_customr)elsestr(Common.pp_globalkr)(*s Pretty-printing of types. [par] is a boolean indicating whether parentheses
are needed or not. *)letrecpp_typeparvlt=letrecpp_recpar=function|Tmeta_|Tvar'_->assertfalse|Tvari->(tryId.print(List.nthvl(predi))withFailure_->(str"a"++inti))|Tglob(r,[])->pp_globalTyper|Tglob(gr,l)whennot(keep_singleton())&&Coqlib.check_refsig_type_namegr->pp_typetruevl(List.hdl)|Tglob(r,l)->pp_parpar(pp_globalTyper++spc()++prlist_with_sepspc(pp_typetruevl)l)|Tarr(t1,t2)->pp_parpar(pp_rectruet1++spc()++str"->"++spc()++pp_recfalset2)|Tdummy_->str"()"|Tunknown->str"Any"|Taxiom->str"() -- AXIOM TO BE REALIZED"++fnl()inhov0(pp_recpart)(*s Pretty-printing of expressions. [par] indicates whether
parentheses are needed or not. [env] is the list of names for the
de Bruijn variables. [args] is the list of collected arguments
(already pretty-printed). *)letexpr_needs_par=function|MLlam_->true|MLcase_->false(* now that we use the case ... of { ... } syntax *)|_->falseletrecpp_exprparenvargs=letapplyst=pp_applystparargsandapply2st=pp_apply2stparargsinfunction|MLreln->letid=get_db_namenenvin(* Try to survive to the occurrence of a Dummy rel.
TODO: we should get rid of this hack (cf. BZ#592) *)letid=ifId.equaliddummy_namethenId.of_string"__"elseidinapply(Id.printid)|MLapp(f,args')->letstl=List.map(pp_exprtrueenv[])args'inpp_exprparenv(stl@args)f|MLlam_asa->letfl,a'=collect_lamsainletfl,env'=push_vars(List.mapid_of_mlidfl)envinletst=(pp_abst(List.revfl)++pp_exprfalseenv'[]a')inapply2st|MLletin(id,a1,a2)->leti,env'=push_vars[id_of_mlidid]envinletpp_id=Id.print(List.hdi)andpp_a1=pp_exprfalseenv[]a1andpp_a2=pp_expr(notpar&&expr_needs_para2)env'[]a2inletpp_def=str"let {"++cut()++hov1(pp_id++str" = "++pp_a1++str"}")inapply2(hv0(hv0(hv1pp_def++spc()++str"in")++spc()++hov0pp_a2))|MLglobr->apply(pp_globalTermr)|MLcons(_,r,a)asc->assert(List.is_emptyargs);beginmatchawith|_whenis_native_charc->pp_native_charc|_whenis_native_stringc->pp_native_stringc|[]->pp_globalConsr|[a]->pp_parpar(pp_globalConsr++spc()++pp_exprtrueenv[]a)|_->pp_parpar(pp_globalConsr++spc()++prlist_with_sepspc(pp_exprtrueenv[])a)end|MLtuplel->assert(List.is_emptyargs);pp_boxed_tuple(pp_exprtrueenv[])l|MLcase(_,t,pv)whenis_custom_matchpv->ifnot(is_regular_matchpv)thenuser_errPp.(str"Cannot mix yet user-given match and general patterns.");letmkfun(ids,_,e)=ifnot(List.is_emptyids)thennamed_lams(List.revids)eelsedummy_lams(ast_lift1e)1inletpp_branchtr=pp_exprtrueenv[](mkfuntr)++fnl()inletinner=str(find_custom_matchpv)++fnl()++prvectpp_branchpv++pp_exprtrueenv[]tinapply2(hov2inner)|MLcase(typ,t,pv)->apply2(v0(str"case "++pp_exprfalseenv[]t++str" of {"++fnl()++pp_patenvpv))|MLfix(i,ids,defs)->letids',env'=push_vars(List.rev(Array.to_listids))envinpp_fixparenv'i(Array.of_list(List.revids'),defs)args|MLexns->(* An [MLexn] may be applied, but I don't really care. *)pp_parpar(str"Prelude.error"++spc()++qss)|MLdummyk->(* An [MLdummy] may be applied, but I don't really care. *)(matchmsg_of_implicitkwith|""->str"__"|s->str"__"++spc()++pp_bracket_comment(strs))|MLmagica->pp_apply(str"unsafeCoerce")par(pp_exprtrueenv[]a::args)|MLaxioms->pp_parpar(str"Prelude.error \"AXIOM TO BE REALIZED ("++strs++str")\"")|MLuint_->pp_parpar(str"Prelude.error \"EXTRACTION OF UINT NOT IMPLEMENTED\"")|MLfloat_->pp_parpar(str"Prelude.error \"EXTRACTION OF FLOAT NOT IMPLEMENTED\"")|MLstring_->pp_parpar(str"Prelude.error \"EXTRACTION OF STRING NOT IMPLEMENTED\"")|MLparray_->pp_parpar(str"Prelude.error \"EXTRACTION OF ARRAY NOT IMPLEMENTED\"")andpp_cons_patparrppl=pp_parpar(pp_globalConsr++space_if(not(List.is_emptyppl))++prlist_with_sepspcidentityppl)andpp_gen_patparidsenv=function|Pcons(r,l)->pp_cons_patparr(List.map(pp_gen_pattrueidsenv)l)|Pusualr->pp_cons_patparr(List.mapId.printids)|Ptuplel->pp_boxed_tuple(pp_gen_patfalseidsenv)l|Pwild->str"_"|Preln->Id.print(get_db_namenenv)andpp_one_patenv(ids,p,t)=letids',env'=push_vars(List.rev_mapid_of_mlidids)envinhov2(str" "++pp_gen_patfalse(List.revids')env'p++str" ->"++spc()++pp_expr(expr_needs_part)env'[]t)andpp_patenvpv=prvecti(funix->pp_one_patenvpv.(i)++ifInt.equali(Array.lengthpv-1)thenstr"}"else(str";"++fnl()))pv(*s names of the functions ([ids]) are already pushed in [env],
and passed here just for convenience. *)andpp_fixparenvi(ids,bl)args=pp_parpar(v0(v1(str"let {"++fnl()++prvect_with_sep(fun()->str";"++fnl())(fun(fi,ti)->pp_functionenv(Id.printfi)ti)(Array.map2(funab->a,b)idsbl)++str"}")++fnl()++str"in "++pp_apply(Id.printids.(i))falseargs))andpp_functionenvft=letbl,t'=collect_lamstinletbl,env'=push_vars(List.mapid_of_mlidbl)envin(f++pr_binding(List.revbl)++str" ="++fnl()++str" "++hov2(pp_exprfalseenv'[]t'))(*s Pretty-printing of inductive types declaration. *)letpp_logical_indpacket=pp_bracket_comment(Id.printpacket.ip_typename++str" : logical inductive"++fnl()++str"with constructors : "++prvect_with_sepspcId.printpacket.ip_consnames)letpp_singletonknpacket=letname=pp_globalType(GlobRef.IndRef(kn,0))inletl=rename_tvarskeywordspacket.ip_varsinhov2(str"type "++name++spc()++prlist_with_sepspcId.printl++(ifnot(List.is_emptyl)thenstr" "elsemt())++str"="++spc()++pp_typefalsel(List.hdpacket.ip_types.(0))++fnl()++pp_comment(str"singleton inductive, whose constructor was "++Id.printpacket.ip_consnames.(0)))letpp_one_indipplcv=letpl=rename_tvarskeywordsplinletpp_constructor(r,l)=(pp_globalConsr++matchlwith|[]->(mt())|_->(str" "++prlist_with_sep(fun()->(str" "))(pp_typetruepl)l))instr(ifArray.is_emptycvthen"type "else"data ")++pp_globalType(GlobRef.IndRefip)++prlist_strict(funid->str" "++pr_lower_idid)pl++str" ="++ifArray.is_emptycvthenstr" () -- empty inductive"else(fnl()++str" "++v0(str" "++prvect_with_sep(fun()->fnl()++str"| ")pp_constructor(Array.mapi(funic->GlobRef.ConstructRef(ip,i+1),c)cv)))letrecpp_indfirstkniind=ifi>=Array.lengthind.ind_packetstheniffirstthenmt()elsefnl()elseletip=(kn,i)inletp=ind.ind_packets.(i)inifis_custom(GlobRef.IndRef(kn,i))thenpp_indfirstkn(i+1)indelseifp.ip_logicalthenpp_logical_indp++pp_indfirstkn(i+1)indelsepp_one_indipp.ip_varsp.ip_types++fnl()++pp_indfalsekn(i+1)ind(*s Pretty-printing of a declaration. *)letpp_decl=function|Dind(kn,i)wheni.ind_kind==Singleton->pp_singletonkni.ind_packets.(0)++fnl()|Dind(kn,i)->hov0(pp_indtruekn0i)|Dtype(r,l,t)->ifis_inline_customrthenmt()elseletl=rename_tvarskeywordslinletst=tryletids,s=find_type_customrinprlist(funid->str(id^" "))ids++str"="++spc()++strswithNot_found->prlist(funid->Id.printid++str" ")l++ift==Taxiomthenstr"= () -- AXIOM TO BE REALIZED"++fnl()elsestr"="++spc()++pp_typefalseltinhov2(str"type "++pp_globalTyper++spc()++st)++fnl2()|Dfix(rv,defs,typs)->letnames=Array.map(funr->ifis_inline_customrthenmt()elsepp_globalTermr)rvinprvecti(funir->letvoid=is_inline_customr||(not(is_customr)&&matchdefs.(i)withMLexn"UNUSED"->true|_->false)inifvoidthenmt()elsehov2(names.(i)++str" :: "++pp_typefalse[]typs.(i))++fnl()++(ifis_customrthen(names.(i)++str" = "++str(find_customr))else(pp_function(empty_env())names.(i)defs.(i)))++fnl2())rv|Dterm(r,a,t)->ifis_inline_customrthenmt()elselete=pp_globalTermrinhov2(e++str" :: "++pp_typefalse[]t)++fnl()++ifis_customrthenhov0(e++str" = "++str(find_customr)++fnl2())elsehov0(pp_function(empty_env())ea++fnl2())letrecpp_structure_elem=function|(l,SEdecld)->pp_decld|(l,SEmodulem)->pp_module_exprm.ml_mod_expr|(l,SEmodtypem)->mt()(* for the moment we simply discard module type *)andpp_module_expr=function|MEstruct(mp,sel)->prlist_strictpp_structure_elemsel|MEfunctor_->mt()(* for the moment we simply discard unapplied functors *)|MEident_|MEapply_->assertfalse(* should be expanded in extract_env *)letpp_struct=letpp_sel(mp,sel)=push_visiblemp[];letp=prlist_strictpp_structure_elemselinpop_visible();pinprlist_strictpp_sellethaskell_descr={keywords=keywords;file_suffix=".hs";file_naming=string_of_modfile;preamble=preamble;pp_struct=pp_struct;sig_suffix=None;sig_preamble=(fun____->mt());pp_sig=(fun_->mt());pp_decl=pp_decl;}