123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366(** Translate the parser-level AST to Coq.
There are two modes:
- raw_coq mode (option -o raw_coq): translation of the AST as it is
(lambdapi-calculus is a subset system of coq if we ignore rules)
- stt_coq mode (option -o stt_coq): translation of the AST as an encoding in
simple type theory.
The encoding can be specified through a lambdapi file (option --encoding).
In both modes, a renaming map can be provided to rename some identifiers.
The renaming map can be specified through a lambdapi file (option --renaming).
*)openLplibopenExtraopenCommonopenPosopenErroropenParsingopenSyntaxopenCoreletlog=Logger.make'x'"xprt""export"letlog=log.pp(** Symbols necessary to encode STT. *)typebuiltin=Set|Prop|Arr|El|Imp|All|Prf|Eq|Or|And|Ex|Notletindex_of_builtin=function|Set->0|Prop->1|Arr->2|El->3|Imp->4|All->5|Prf->6|Eq->7|Or->8|And->9|Ex->10|Not->11letnb_builtins=12letbuiltin_of_index=function|0->Set|1->Prop|2->Arr|3->El|4->Imp|5->All|6->Prf|7->Eq|8->Or|9->And|10->Ex|11->Not|_->assertfalselet_=(* sanity check *)fori=0tonb_builtins-1doassert(index_of_builtin(builtin_of_indexi)=i)doneletindex_of_name=function|"Set"->Some0|"prop"->Some1|"arr"->Some2|"El"->Some3|"imp"->Some4|"all"->Some5|"Prf"->Some6|"eq"->Some7|"or"->Some8|"and"->Some9|"ex"->Some10|"not"->Some11|_->Noneletname_of_index=function|0->"Set"|1->"prop"|2->"arr"|3->"El"|4->"imp"|5->"all"|6->"Prf"|7->"eq"|8->"or"|9->"and"|10->"ex"|11->"not"|_->assertfalselet_=(* sanity check *)fori=0tonb_builtins-1doassert(index_of_name(name_of_indexi)=Somei)doneletbuiltin:Term.qidentarray=letpath=["STTfa"]inArray.initnb_builtins(funi->path,name_of_indexi)letsymb=builtin.(index_of_builtinb)(** Set renaming map from file. *)letrmap=refStrMap.emptyletset_renaming:string->unit=funf->letconsume=function|{elt=P_builtin(coq_id,{elt=([],lp_id);_});_}->ifLogger.log_enabled()thenlog"rename %s into %s"lp_idcoq_id;rmap:=StrMap.addlp_idcoq_id!rmap|{pos;_}->fatalpos"Invalid command."inStream.iterconsume(Parser.parse_filef)(** Set symbols whose declarations have to be erased. *)leterase=refStrSet.emptymoduleQid=structtypet=Term.qidentletcompare=Stdlib.compareendmoduleQidMap=Map.Make(Qid)letmap_erased_qid_coq=refQidMap.emptyletset_mapping:string->unit=funf->letconsume=function|{elt=P_builtin(coq_id,lp_qid);_}->ifLogger.log_enabled()thenlog"rename %a into %s"Pretty.qidentlp_qidcoq_id;letid=sndlp_qid.eltinifLogger.log_enabled()thenlog"erase %s"id;erase:=StrSet.addid!erase;map_erased_qid_coq:=QidMap.addlp_qid.eltcoq_id!map_erased_qid_coq;iffstlp_qid.elt=[]&&id<>coq_idthenrmap:=StrMap.addidcoq_id!rmap|{pos;_}->fatalpos"Invalid command."inStream.iterconsume(Parser.parse_filef)(** Set encoding. *)letmap_qid_builtin=refQidMap.emptyletset_encoding:string->unit=funf->letfound=Array.makenb_builtinsfalseinletconsume=function|{elt=P_builtin(n,lp_qid);pos}->beginmatchindex_of_namenwith|Somei->ifLogger.log_enabled()thenlog"builtin \"%s\" = %a"nPretty.qidentlp_qid;builtin.(i)<-lp_qid.elt;found.(i)<-true;letb=builtin_of_indexiinmap_qid_builtin:=QidMap.addlp_qid.eltb!map_qid_builtin;ifb=El||b=Prfthen(ifLogger.log_enabled()thenlog"erase %s"(sndlp_qid.elt);erase:=StrSet.add(sndlp_qid.elt)!erase)|None->fatalpos"Unknown builtin."end|{pos;_}->fatalpos"Invalid command."inStream.iterconsume(Parser.parse_filef);Array.iteri(funib->ifnotbthenletpos=Some{fname=Somef;start_line=0;start_col=0;end_line=0;end_col=0}infatalpos"Builtin %s undefined."(name_of_indexi))found(** Basic printing functions. We use Printf for efficiency reasons. *)letout=Printf.printfletchar=output_charletstring=output_stringletprefixpreeltocx=stringocpre;eltocxletsuffixeltsufocx=eltocx;stringocsufletlisteltsepocxs=matchxswith|[]->()|x::xs->eltocx;List.iter(prefixsepeltoc)xs(** Translation of identifiers. *)lettranslate_ident:string->string=funs->tryStrMap.finds!rmapwithNot_found->sletraw_identocs=stringoc(translate_idents)letidentoc{elt;_}=raw_identoceltletparam_idocidopt=matchidoptwith|Someid->identocid|None->charoc'_'letparam_ids=listparam_id" "letraw_path=liststring"."letpathoc{elt;_}=raw_pathoceltletqidentoc{elt=(mp,s);_}=matchmpwith|[]->raw_identocs|_::_->raw_pathocmp;charoc'.';raw_identocs(** Translation of terms. *)letstt=Stdlib.reffalseletuse_implicits=Stdlib.reffalseletuse_notations=Stdlib.reffalse(* redefinition of p_get_args ignoring P_Wrap's. *)letp_get_args:p_term->p_term*p_termlist=funt->letrecp_get_argstacc=matcht.eltwith|P_Appl(t,u)->p_get_argst(u::acc)|P_Wrapt->p_get_argstacc|_->t,accinp_get_argst[]letapptdefaultcases=leth,ts=p_get_argstinif!sttthenmatchh.eltwith|P_Iden({elt;_},expl)->beginmatchQidMap.find_optelt!map_qid_builtinwith|None->defaulthts|Somebuiltin->caseshtsexplbuiltinend|_->defaulthtselsedefaulthtsletrectermoct=(*if Logger.log_enabled() then
log "pp %a" (*Pos.short t.pos*) Pretty.term t;*)matcht.eltwith|P_Meta_->wrnt.pos"TODO";assertfalse|P_Patt_->wrnt.pos"TODO";assertfalse|P_Expl_->wrnt.pos"TODO";assertfalse|P_SLit_->wrnt.pos"TODO";assertfalse|P_Type->stringoc"Type"|P_Wild->charoc'_'|P_NLiti->if!sttthenmatchQidMap.find_opt([],i)!map_erased_qid_coqwith|Somes->stringocs|None->raw_identocielseraw_identoci|P_Iden(qid,b)->ifbthencharoc'@';if!sttthenmatchQidMap.find_optqid.elt!map_erased_qid_coqwith|Somes->stringocs|None->qidentocqidelseqidentocqid|P_Arro(u,v)->arrowocuv|P_Abst(xs,u)->abstocxsu|P_Prod(xs,u)->prodocxsu|P_LLet(x,xs,a,u,v)->stringoc"let ";identocx;params_listocxs;typoptoca;stringoc" := ";termocu;stringoc" in ";termocv|P_Wrapu->termocu|P_Appl_->letdefaulthts=parenoch;charoc' ';listparen" "octsinapptdefault(funhtsexplbuiltin->match!use_notations,!use_implicits&¬expl,builtin,tswith|_,_,(El|Prf),[u]->termocu|_,_,(Arr|Imp),[u;v]->arrowocuv|_,_,All,[_;{elt=P_Wrap({elt=P_Abst([_]asxs,u);_});_}]|_,true,All,[{elt=P_Wrap({elt=P_Abst([_]asxs,u);_});_}]->prodocxsu|_,_,Ex,[_;{elt=P_Wrap({elt=P_Abst([x],u);_});_}]|_,true,Ex,[{elt=P_Wrap({elt=P_Abst([x],u);_});_}]->stringoc"exists ";raw_paramsocx;stringoc", ";termocu|true,_,Eq,[_;u;v]|true,true,Eq,[u;v]->parenocu;stringoc" = ";parenocv|true,_,Or,[u;v]->parenocu;stringoc" \\/ ";parenocv|true,_,And,[u;v]->parenocu;stringoc" /\\ ";parenocv|true,_,Not,[u]->stringoc"~ ";parenocu|_->defaulthts)andarrowocuv=parenocu;stringoc" -> ";termocvandabstocxsu=stringoc"fun";params_list_in_absocxs;stringoc" => ";termocuandprodocxsu=stringoc"forall";params_list_in_absocxs;stringoc", ";termocuandparenoct=letdefault()=charoc'(';termoct;charoc')'inmatcht.eltwith|P_Arro_|P_Abst_|P_Prod_|P_LLet_|P_Wrap_->default()|P_Appl_->appt(fun__->default())(fun_ts_builtin->matchbuiltin,tswith|(El|Prf),[u]->parenocu|_->default())|_->termoctandraw_paramsoc(ids,t,_)=param_idsocids;typoptoctandparamsoc((ids,t,b)asx)=matchb,twith|true,_->charoc'{';raw_paramsocx;charoc'}'|false,Some_->charoc'(';raw_paramsocx;charoc')'|false,None->param_idsocids(* starts with a space if the list is not empty *)andparams_listoc=List.iter(prefix" "paramsoc)(* starts with a space if the list is not empty *)andparams_list_in_absocl=matchlwith|[ids,t,false]->charoc' ';param_idsocids;typoptoct|_->params_listocl(* starts with a space if <> None *)andtypoptoct=Option.iter(prefix" : "termoc)t(** Translation of commands. *)letis_lemx=is_opaqx||is_privxletcommandoc{elt;pos}=beginmatcheltwith|P_open(true,ps)->stringoc"Import ";listpath" "ocps;stringoc".\n"|P_open(false,ps)->stringoc"Export ";listpath" "ocps;stringoc".\n"|P_require(None,ps)->stringoc"Require ";listpath" "ocps;stringoc".\n"|P_require(Sometrue,ps)->stringoc"Require Import ";listpath" "ocps;stringoc".\n"|P_require(Somefalse,ps)->stringoc"Require Export ";listpath" "ocps;stringoc".\n"|P_require_as(p,i)->stringoc"Module ";identoci;stringoc" := ";pathocp;stringoc".\n"|P_symbol{p_sym_mod;p_sym_nam;p_sym_arg;p_sym_typ;p_sym_trm;p_sym_prf=_;p_sym_def}->ifnot(StrSet.memp_sym_nam.elt!erase)thenletp_sym_arg=if!sttthenletpos=Nonein(* Parameters with no type are assumed to be of type [Set]. *)let_Set={elt=P_Iden({elt=symSet;pos},false);pos}inList.map(functionids,None,b->ids,Some_Set,b|x->x)p_sym_argelsep_sym_arginbeginmatchp_sym_def,p_sym_trm,p_sym_arg,p_sym_typwith|true,Somet,_,SomeawhenList.existsis_lemp_sym_mod->(* If they have a type, opaque or private defined symbols are
translated as Lemma's so that their definition is loaded in
memory only when it is necessary. *)stringoc"Lemma ";identocp_sym_nam;params_listocp_sym_arg;stringoc" : ";termoca;stringoc".\nProof. exact (";termoct;stringoc"). Qed.\n"|true,Somet,_,_->stringoc"Definition ";identocp_sym_nam;params_listocp_sym_arg;typoptocp_sym_typ;stringoc" := ";termoct;ifList.existsis_opaqp_sym_modthen(stringoc".\nOpaque ";identocp_sym_nam);stringoc".\n"|false,_,[],Somet->stringoc"Axiom ";identocp_sym_nam;stringoc" : ";termoct;stringoc".\n"|false,_,_,Somet->stringoc"Axiom ";identocp_sym_nam;stringoc" : forall";params_listocp_sym_arg;stringoc", ";termoct;stringoc".\n"|_->wrnpos"Command not translated."end|_->wrnpos"Command not translated."endletastoc=Stream.iter(commandoc)(** Set Coq required file. *)letrequire=refNoneletset_requiring:string->unit=funf->require:=Somefletprint:ast->unit=funs->letoc=stdoutinbeginmatch!requirewith|Somef->stringoc("Require Import "^f^".\n")|None->()end;astocs