123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216(*
Utilities for interpreting annotations of type Ast.annot.
*)openImporttypet=Ast.annotleterror_atlocs=failwith(sprintf"%s:\n%s"(Ast.string_of_locloc)s)letfields~section~fieldl=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.flattenletfield~section~fieldl=matchfields~section~fieldlwith|[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_fields~parse~sections~fieldl=List.find_map(funsection->Some(fieldsl~section~field|>List.map(fun(loc,o)->matchowith|None->error_atloc(sprintf"Missing value for annotation %s.%s"sectionfield)|Somes->(matchparseswith|None->error_atloc(sprintf"Invalid annotation <%s %s=%S>"sectionfields)|Somev->v))))sections|>Option.value~default:[]letget_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)lletget_loc~sections:k~field:k2l=k|>List.find_map(funk1->letopenOption.Oinfieldl~section:k1~field:k2>>=fun(loc,_o)->Someloc)letget_loc_exn~sections~fieldl=get_loc~sections~fieldl|>Option.value_exnletcollapsemergel=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!ntypenode_kind=|Module_head|Type_def|Type_expr|Variant|Cell|Fieldtypeschema_field=node_kind*stringtypeschema_section={section:string;fields:schema_fieldlist;}typeschema=schema_sectionlistletvalidate_sectionsecroot=(* split fields by location where they may occur *)letin_module_head=ref[]inletin_type_def=ref[]inletin_type_expr=ref[]inletin_variant=ref[]inletin_cell=ref[]inletin_field=ref[]insec.fields|>List.iter(fun(kind,field_name)->letacc=matchkindwith|Module_head->in_module_head|Type_def->in_type_def|Type_expr->in_type_expr|Variant->in_variant|Cell->in_cell|Field->in_fieldinacc:=field_name::!acc);letcheckacc=letallowed_fields=List.rev!accinfun_node(an:Ast.annot)()->an|>List.iter(fun((sec_name,(loc,fields)):Ast.annot_section)->ifsec_name=sec.sectionthenfields|>List.iter(fun(field_name,(loc2,_opt_val))->ifnot(List.memfield_nameallowed_fields)thenAst.error_atloc2(sprintf"Invalid or misplaced annotation <%s ... %s... >"sec_namefield_name)))inAst.fold_annot~module_head:(checkin_module_head)~type_def:(checkin_type_def)~type_expr:(checkin_type_expr)~variant:(checkin_variant)~cell:(checkin_cell)~field:(checkin_field)root()letvalidateschemaroot=List.iter(funsec->validate_sectionsecroot)schema