123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194(* This file is free software, part of Logtk. See file "license" for more details. *)(** {1 Positions in terms, clauses...} *)(** A position is a path in a tree *)typet=|Stop|Typeoft(** Switch to type *)|Leftoft(** Left term in curried application *)|Rightoft(** Right term in curried application, and subterm of binder *)|Headoft(** Head of uncurried term *)|Argofint*t(** argument term in uncurried term, or in multiset *)|Bodyoft(** Body of binder *)typeposition=tletstop=Stoplettype_pos=Typeposletleftpos=Leftposletrightpos=Rightposletheadpos=Headposletargipos=Arg(i,pos)letbodypos=Bodyposletcompare=Pervasives.compareletequalp1p2=comparep1p2=0lethashp=Hashtbl.hashpletrecsize=function|Stop->0|Typep|Leftp|Rightp|Headp|Arg(_,p)|Bodyp->1+sizepletrevpos=letrecauxaccpos=matchposwith|Stop->acc|Typepos'->aux(Typeacc)pos'|Leftpos'->aux(Leftacc)pos'|Rightpos'->aux(Rightacc)pos'|Headpos'->aux(Headacc)pos'|Arg(i,pos')->aux(Arg(i,acc))pos'|Bodypos'->aux(Bodyacc)pos'inauxStopposletopp=function|Leftp->Rightp|Rightp->Leftp|pos->pos(* Recursive append *)letrecappendp1p2=matchp1with|Stop->p2|Typep1'->Type(appendp1'p2)|Leftp1'->Left(appendp1'p2)|Rightp1'->Right(appendp1'p2)|Headp1'->Head(appendp1'p2)|Arg(i,p1')->Arg(i,appendp1'p2)|Bodyp1'->Body(appendp1'p2)letrecppoutpos=matchposwith|Stop->CCFormat.stringout"ε"|Typep'->CCFormat.stringout"τ.";ppoutp'|Leftp'->CCFormat.stringout"←.";ppoutp'|Rightp'->CCFormat.stringout"→.";ppoutp'|Headp'->CCFormat.stringout"@.";ppoutp'|Arg(i,p')->Format.fprintfout"%d."i;ppoutp'|Bodyp'->Format.fprintfout"β.";ppoutp'letto_string=CCFormat.to_stringppletrecis_prefixp1p2:bool=matchp1,p2with|Stop,_->true|Leftl1,Leftl2|Rightl1,Rightl2|Headl1,Headl2|Bodyl1,Bodyl2|Typel1,Typel2->is_prefixl1l2|Arg(i1,l1),Arg(i2,l2)->i1=i2&&is_prefixl1l2|Left_,_|Right_,_|Head_,_|Body_,_|Arg_,_|Type_,_->falseletis_strict_prefixp1p2=not(equalp1p2)&&is_prefixp1p2letrecuntil_first_fun=function|Stop->Stop|Typep->Type(until_first_funp)|Leftp->Left(until_first_funp)|Rightp->Right(until_first_funp)|Headp->Head(until_first_funp)|Arg(i,p)->Arg(i,until_first_funp)|Body_->Stopletrecnum_of_funs=function|Stop->0|Typep'|Leftp'|Rightp'|Headp'|Arg(_,p')->num_of_funsp'|Bodyp'->1+num_of_funsp'moduleMap=structincludeCCMap.Make(structtypet=positionletcompare=compareend)letprune_subsumed(m:_t):_t=filter(funk_->not(exists(funk'_->is_strict_prefixk'k)m))mend(** {2 Position builder}
We use an adaptation of difference lists for this tasks *)moduleBuild=structtypet=|E(** Empty (identity function) *)|Pofposition*t(** Pre-pend given position, then apply previous builder *)|Nof(position->position)*t(** Apply function to position, then apply linked builder *)letempty=Eletof_posp=P(p,E)(* how to apply a difference list to a tail list *)letrecapply_rectailb=matchbwith|E->tail|P(pos0,b')->apply_rec(appendpos0tail)b'|N(f,b')->apply_rec(ftail)b'letapply_flipbpos=apply_recposbletto_posb=apply_recstopbletsuffixbpos=(* given a suffix, first append pos to it, then apply b *)N((funpos0->appendpospos0),b)letprefixposb=(* tricky: this doesn't follow the recursive structure. Hence we
need to first apply b totally, then pre-prend pos *)N((funpos1->appendpos(apply_recpos1b)),E)letappendp1p2=N(apply_flipp2,p1)letleftb=N(left,b)letrightb=N(right,b)lettype_b=N(type_,b)letheadb=N(head,b)letargib=N(argi,b)letbodyb=N(body,b)letppoutt=ppout(to_post)letto_stringt=to_string(to_post)end(** {2 Pairing of value with Pos} *)moduleWith=structtype'at='a*positionletget=fstletpos=sndletmakexp:_t=x,pletof_pairp=pletmap_posf(x,pos)=x,fposletmapf(x,pos)=fx,posmoduleInfix=structlet(>|=)xf=mapfxendincludeInfixletequalft1t2=f(gett1)(gett2)&&equal(post1)(post2)letcompareft1t2=letc=f(gett1)(gett2)inifc=0thencompare(post1)(post2)elseclethashft=Hash.combine341(f(gett))(hash(post))letppfoutt=CCFormat.fprintfout"(@[:pos %a :in %a@])"pp(post)f(gett)end