123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379moduleLsp=Fleche_lspopenFleche(** TODO:
- new edge "defined_in" object file
- new edge "uses" for Require
- new attributes "uses" "in_body" / "in_type" *)(* Put these in an utility function for plugins *)(* Duplicated with rq_document *)let_of_execution~io~what(v:(_,_)Coq.Protect.E.t)=matchvwith|{r;feedback=_}->(matchrwith|Coq.Protect.R.Completed(Okgoals)->goals|Coq.Protect.R.Completed(Error(Anomaly{msg;_}))|Coq.Protect.R.Completed(Error(User{msg;_}))->letlvl=Io.Level.ErrorinIo.Report.msg~io~lvl"error when retrieving %s: %a"whatPp.pp_withmsg;None|Coq.Protect.R.Interrupted->None)moduleKind=structtypet=|Notation|Definition|Theorem|Otherofstring|Unknown|Lemma[@@derivingto_yojson]letto_string=function|Notation->"Notation"|Definition->"Definition"|Theorem->"Theorem"|Others->"Other("^s^")"|Unknown->"Unknown"|Lemma->"Lemma"letof_rocq_logic_kind=function|Decls.Theorem->Theorem|Lemma->Lemma|Fact->Other"Fact"|Remark->Other"Remark"|Property->Other"Property"|Proposition->Other"Proposition"|Corollary->Other"Corollary"letof_rocq_decl_kind=function|Decls.Definition->Definition|Coercion->Other"Coercion"|SubClass->Other"SubClass"|CanonicalStructure->Other"CanonicalStructure"|Example->Other"Example"|Fixpoint->Other"Fixpoint"|CoFixpoint->Other"CoFixpoint"|Scheme->Other"Scheme"|StructureComponent->Other"StructureComponent"|IdentityCoercion->Other"IdentityCoercion"|Instance->Other"Instance"|Method->Other"Method"|Let->Other"Let"|LetContext->Other"LetContext"(* For Lang.Ast.Info.t *)let_of_detail=function|Some"Notation"->Notation|Some"Definition"->Definition|Some"Lemma"->Lemma|Some"Theorem"->Theorem|Somes->Others|None->Unknownend(* extract refs and notations *)letrecanalyze_constr_expr_acc()depl(e:Constrexpr.constr_expr):stringlist=letopenConstrexprin(matche.vwith|CRef(qid,_)->[Libnames.string_of_qualidqid]|CFix(_,_)->[]|CCoFix(_,_)->[]|CProdN(_,_)->[]|CLambdaN(_,_)->[]|CLetIn(_,_,_,_)->[]|CAppExpl(_,_)->[]|CApp(_,_)->[]|CProj(_,_,_,_)->[]|CRecord_->[]|CCases(_,_,_,_)->[]|CLetTuple(_,_,_,_)->[]|CIf(_,_,_,_)->[]|CHole_->[]|CGenarg_->[]|CGenargGlob_->[]|CPatVar_->[]|CEvar(_,_)->[]|CSort_->[]|CCast(_,_,_)->[]|CNotation(_,(_,ntn_key),(l,ll,_,_))->(* Constrexpr_ops.fold_constr_expr_with_binders doesn't recurse properly
here *)letf=Constrexpr_ops.fold_constr_expr_with_binders(fun_()->())analyze_constr_expr_acc()[]in[ntn_key]@List.concat_mapf(l@List.flattenll)|CGeneralization(_,_)->[]|CPrim_->[]|CDelimiters(_,_,_)->[]|CArray(_,_,_,_)->[])|>List.appenddeplletanalyze_constr_expr(e:Constrexpr.constr_expr)=Constrexpr_ops.fold_constr_expr_with_binders(fun_()->())analyze_constr_expr_acc()[]e(* *)letanalyze_definition_exprde=letopenVernacexprinletty=matchdewith|ProveBody(_bl,e)->e|DefineBody(_bl,_rr,e,_)->einanalyze_constr_exprtyletname_to_string=function|Names.Anonymous->None|Names.Nameid->Some(Names.Id.to_stringid)(* Better Rocq analysis, for example extract the list of notations *)letanalyze(CAst.{loc=_;v}:Vernacexpr.vernac_control):_option=letopenVernacexprinlet{control=_;attrs=_;expr}=vinmatchexprwith|VernacSynterpe->(matchewith|VernacLoad(_,_)->None|VernacReservedNotation(_,_)->None|VernacNotation(_,_)->None|VernacDeclareCustomEntry_->None|VernacBeginSection_->None|VernacEndSegment_->None|VernacRequire(_,_,_)->None|VernacImport(_,_)->None|VernacDeclareModule(_,_,_,_)->None|VernacDefineModule(_,_,_,_,_)->None|VernacDeclareModuleType(_,_,_,_)->None|VernacInclude_->None|VernacDeclareMLModule_->None|VernacChdir_->None|VernacExtraDependency(_,_,_)->None|VernacSetOption(_,_,_)->None|VernacProofMode_->None|VernacExtend(_,_)->None)|VernacSynPuree->(matchewith|VernacOpenCloseScope(_,_)->None|VernacDeclareScope_->None|VernacDelimiters(_,_)->None|VernacBindScope(_,_)->None|VernacEnableNotation(_,_,_,_,_)->None|VernacDefinition((_,kind),(name,_),expr)->letname=name_to_stringname.vinletkind=Kind.of_rocq_decl_kindkindinletdeps=analyze_definition_exprexprinSome(name,kind,deps)|VernacStartTheoremProof(_,[])->None|VernacStartTheoremProof(kind,((name,_),(_,ty))::_)->letname=Some(Names.Id.to_stringname.v)inletkind=Kind.of_rocq_logic_kindkindinletdeps=analyze_constr_exprtyinSome(name,kind,deps)|VernacEndProof_->None|VernacExactProof_->None|VernacAssumption(_,_,_)->None|VernacSymbol_->None|VernacInductive(_,_)->None|VernacFixpoint(_,_)->None|VernacCoFixpoint(_,_)->None|VernacScheme_->None|VernacSchemeEquality(_,_)->None|VernacCombinedScheme(_,_)->None|VernacUniverse_->None|VernacSort_->None|VernacConstraint_->None|VernacAddRewRule(_,_)->None|VernacCanonical_->None|VernacCoercion(_,_)->None|VernacIdentityCoercion(_,_,_)->None|VernacNameSectionHypSet(_,_)->None|VernacInstance(_,_,_,_,_)->None|VernacDeclareInstance(_,_,_,_)->None|VernacContext_->None|VernacExistingInstance_->None|VernacExistingClass_->None|VernacResetName_->None|VernacResetInitial->None|VernacBack_->None|VernacCreateHintDb(_,_)->None|VernacRemoveHints(_,_)->None|VernacHints(_,_)->None|VernacSyntacticDefinition(_,_,_)->None|VernacArguments(_,_,_,_)->None|VernacReserve_->None|VernacGeneralizable_->None|VernacSetOpacity(_,_)->None|VernacSetStrategy_->None|VernacMemOption(_,_)->None|VernacPrintOption_->None|VernacCheckMayEval(_,_,_)->None|VernacGlobalCheck_->None|VernacDeclareReduction(_,_)->None|VernacPrint_->None|VernacSearch(_,_,_)->None|VernacLocate_->None|VernacRegister(_,_)->None|VernacPrimitive(_,_,_)->None|VernacComments_->None|VernacAttributes_->None|VernacAbort->None|VernacAbortAll->None|VernacRestart->None|VernacUndo_->None|VernacUndoTo_->None|VernacFocus_->None|VernacUnfocus->None|VernacUnfocused->None|VernacBullet_->None|VernacSubproof_->None|VernacEndSubproof->None|VernacShow_->None|VernacCheckGuard->None|VernacValidateProof->None|VernacProof(_,_)->None|VernacAddOption(_,_)->None|VernacRemoveOption(_,_)->None)letanalyze(node:Doc.Node.t)=matchnode.astwith|Some{v;_}->analyze(Coq.Ast.to_coqv)|_->None(* We output a record for each object we can recognize in the document, linear
order. *)moduleNode_info=struct(* Just to bring the serializers in scope *)moduleLang=Lsp.JLangmoduleCoq=Lsp.JCoqtypet={uri:Lang.LUri.File.t;range:Lang.Range.t;kind:Kind.t;name:string;raw:string;deps:stringlist}[@@derivingto_yojson]letof_node~io:_~token:_~uri~(contents:Contents.t)(node:Doc.Node.t)=matchanalyzenodewith|None->None|Some(name,kind,deps)->(* let uuid = "TODO" in *)letrange=node.rangeinletname=matchnamewith|Somename->name|None->"anonymous"inletdeps=List.sort_uniqString.comparedepsinletraw=Fleche.Contents.extract_raw~contents~rangeinSome{uri;range;kind;name;raw;deps}endmoduleGDB=struct(* Object identifier *)moduleId=structtypet=string[@@derivingto_yojson]endmoduleAttr=structtypet=stringlist[@@derivingto_yojson]endmoduleNode=structtypet={id:Id.t;attrs:Attr.t}[@@derivingto_yojson]endmoduleEdge=structtypet={from:Id.t;to_:Id.t[@key"to"];attrs:Attr.t;label:string}[@@derivingto_yojson]endmoduleLabels=structtypet=(Id.t*string)listletto_yojsonl=letf(id,label)=(id,`Stringlabel)inletfields=List.mapflin`AssocfieldsendendmoduleMeta=structopenGDBtypet=Node.tlist*Edge.tlist*Labels.tletmk_edges~from~deps~attrs=letfto_={Edge.from;to_;attrs;label="USES"}inList.mapfdepsletrecto_graph_db(nl,el,ll)(l:Node_info.tlist):t=matchlwith|[]->(List.revnl,List.revel,List.revll)|n::l->let{Node_info.uri=_;range=_;kind;name;raw=_;deps}=ninletattrs=[]inletnn={Node.id=name;attrs}inletne=mk_edges~from:name~deps~attrsinletnll=(name,Kind.to_stringkind)into_graph_db(nn::nl,ne@el,nll::ll)lletto_graph_db(l:Node_info.tlist):t=to_graph_db([],[],[])l(* Create nodes for orphan deps in the graph *)letto_graph_dbl=letnl,el,ll=to_graph_dblin(nl,el,ll)letppfmt(nl,el,l)=letnl=`List(List.mapNode.to_yojsonnl)inletel=`List(List.mapEdge.to_yojsonel)inletl=Labels.to_yojsonlinletobj=`Assoc[("edges",el);("nodes",nl);("node_labels",l)]inletobj=`Assoc[("graph",obj)]inFormat.fprintffmt"@[%a@]@\n"(Yojson.Safe.pretty_print~std:true)objendletdump_meta~io~token~out_file~(doc:Doc.t)=leturi,contents=(doc.uri,doc.contents)inletll=List.filter_map(Node_info.of_node~io~token~uri~contents)doc.nodesinletll=Meta.to_graph_dbllinletffmtmeta=Meta.ppfmtmetainCoq.Compat.format_to_file~file:out_file~fllletdump_meta~io~token~(doc:Doc.t)=leturi=doc.uriinleturi_str=Lang.LUri.File.to_string_uriuriinletlvl=Io.Level.InfoinIo.Report.msg~io~lvl"[metanejo plugin] dumping metadata for %s ..."uri_str;letout_file_j=Lang.LUri.File.to_string_fileuri^".meta.json"inlet()=dump_meta~io~token~out_file:out_file_j~docin(* let out_file_s = Lang.LUri.File.to_string_file uri ^ ".sexp.goaldump" in *)(* let () = dump_goals ~out_file:out_file_s ~doc pp_sexp in *)Io.Report.msg~io~lvl"[metanejo plugin] dumping metadata for %s was completed!"uri_str;()letmain()=Theory.Register.Completed.adddump_metalet()=main()