123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103openPpxlibletis_gospelattr=attr.attr_name.txt="gospel"(* Prefix a string with whitespace the length of gospel special comment marker *)letalign=" "leteol_and_align="\n "letgospel_txt_of_attributesattr=letrecauxattr=ifis_gospelattrthenmatchattr.attr_payloadwith|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_constant(Pconst_string(txt,loc,_));_;},attrs);_;};]->{txt;loc}::(List.mapauxattrs|>List.flatten)|_->[]else[]inletreclast_loc_end=function|[]->failwith"unreachable case in last_loc_end"|[x]->x.loc.loc_end|_::xs->last_loc_endxsinmatchauxattrwith|[]->None|x::_asxs->lettxt=align^String.concateol_and_align((List.map(fun{txt;_}->txt))xs)andloc_end=last_loc_endxsinSome{txt;loc={x.locwithloc_end}}letwrap_gospelheadertxt=letheader=matchheaderwith|`Declaration->"Gospel declaration:\n"|`Specification->"Gospel specification:\n"inFmt.str"{@gospel[\n%s%s]}"headertxtletpayload_of_string~loctxt=letopenAst_helperinletcontent=Const.string~loctxtinletexpression=Pexp_constantcontent|>Exp.mk~locinletstructure_item=Str.eval~locexpressioninPStr[structure_item]letattr_label=function|`Declaration->"ocaml.text"|`Specification->"ocaml.doc"letdoc_of_gospelheaderattr=ifis_gospelattrthenletattr_name={txt=attr_labelheader;loc=attr.attr_loc}andinfo=gospel_txt_of_attributesattrinOption.map(funinfo->lettxt=wrap_gospelheaderinfo.txtinletattr_payload=payload_of_string~loc:info.loctxtandattr_loc=attr.attr_locin{attr_name;attr_payload;attr_loc})infoelseNoneletdoc_of_gospel_declaration=doc_of_gospel`Declarationletdoc_of_gospel_specification=doc_of_gospel`Specification(* Attributes with a gospel tag in a signature are gospel declarations,
that is gospel functions, predicates and axioms *)letrecsignature=function|[]->[]|({psig_desc=Psig_attributea;psig_loc=loc}asx)::xs->(matchdoc_of_gospel_declarationawith|Somea->x::{psig_desc=Psig_attributea;psig_loc=loc}::signaturexs|None->x::signaturexs)|x::xs->x::signaturexs(* Attributes with a gospel tag in the [attributes] node of the ast are
attached to an OCaml declaration (a value or a type). That means they are
specifications. *)letattributesattrs=attrs@List.filter_mapdoc_of_gospel_specificationattrsletmerge=objectinheritAst_traverse.mapassupermethod!signatures=super#signatures|>signaturemethod!attributesattrs=super#attributesattrs|>attributesendletpreprocess_intf=merge#signaturelet()=Driver.register_transformation~preprocess_intf"odoc_of_gospel"