123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120(*
Utilities for interpreting annotations of type Ast.annot.
*)openImporttypet=Ast.annotleterror_atlocs=failwith(sprintf"%s:\n%s"(Ast.string_of_locloc)s)letfield~section~fieldl=letfieldmatches=List.filter_map(fun(s,(_,fs))->ifs=sectionthenSomefselseNone)l|>List.map(funfs->List.filter_map(fun(f,(l,s))->iff=fieldthenSome(l,s)elseNone)fs)|>List.flatteninmatchfieldmatcheswith|[fieldmatch]->Somefieldmatch|(loc,_)::others->error_atloc(sprintf"Duplicate annotation %s.%s (also in:\n %s\n)"sectionfield(List.map(fun(loc,_)->(Ast.string_of_locloc))others|>String.concat",\n "))|_->Nonelethas_sectionkl=Option.is_some(List.assockl)lethas_field~sections:k~field:k2l=List.exists(funk1->field~section:k1~field:k2l|>Option.is_some)kletget_flag~sections:k~field:k2l=k|>List.find_map(funk1->field~section:k1~field:k2l|>Option.map(fun(loc,o)->matchowith|None|Some"true"->true|Some"false"->false|Somes->error_atloc(sprintf"Invalid value %S for flag %s.%s"sk1k2)))|>Option.value~default:falseletget_field~parse~default~sections:k~field:k2l=k|>List.find_map(funk1->letopenOption.Oinfieldl~section:k1~field:k2>>=fun(loc,o)->matchowith|Somes->(matchparseswithSome_asy->y|None->error_atloc(sprintf"Invalid annotation <%s %s=%S>"k1k2s))|None->error_atloc(sprintf"Missing value for annotation %s.%s"k1k2))|>Option.value~defaultletget_opt_field~parse~sections~fieldl=letparses=matchparseswith|None->None(* indicates parse error *)|Somev->Some(Somev)inget_field~parse~default:None~sections~fieldlletset_field~loc~section:k~field:k2vl:Ast.annot=matchList.assocklwith|None->(k,(loc,[k2,(loc,v)]))::l|Some(section_loc,section)->letsection_loc,section=List.assoc_exnklinletsection=matchList.assock2sectionwith|None->(k2,(loc,v))::section|Some_->List.assoc_updatek2(loc,v)sectioninList.assoc_updatek(section_loc,section)lletcollapsemergel=lettbl=Hashtbl.create10inletn=ref0inList.iter(fun(s1,f1)->incrn;trylet_,f2=Hashtbl.findtbls1inHashtbl.replacetbls1(!n,mergef1f2)withNot_found->Hashtbl.addtbls1(!n,f1))(List.revl);letl=Hashtbl.fold(funs(i,f)l->(i,(s,f))::l)tbl[]inletl=List.sort(fun(i,_)(j,_)->compareji)linList.mapsndlletoverride_valuesx1_=x1letoverride_fields(loc1,l1)(_,l2)=(loc1,collapseoverride_values(l1@l2))letmergel=collapseoverride_fieldslletcreate_id=letn=ref(-1)infun()->incrn;if!n<0thenfailwith"Annot.create_id: counter overflow"elsestring_of_int!n