123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178(* Copyright (C) 2021 Alan Hu <alanh@ccs.neu.edu>
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/. *)includeIntfletcounter=ref0moduleMake(Sort:Sort)(Operator:Operator)=structmoduleSort=SortmoduleOperator=OperatormoduleVariable=structtype'sortt={id:int;name:string;sort:'sortSort.t;}type'sortsort='sortSort.tletfreshsortname=letid=!counterincounter:=id+1;{id;name;sort}letsortvar=var.sortletnamevar=var.nameletequal:types1s2.s1t->s2t->(s1,s2)eqoption=funv1v2->matchSort.equalv1.sortv2.sortwith|LeftReflwhenv1.id=v2.id->SomeRefl|_->Noneendtype'valencet=|Bound:int*'sortSort.t->'sortvat|Free:'sortVariable.t->'sortvat|Abstr:string*'sortSort.t*'valencet->('sort->'valence)t|Oper:('arity,'sort)Operator.t*('arity,'sort)operands->'sortvatand('arity,'sort)operands=|[]:('sortar,'sort)operands|(::):'valencet*('arity,'sort)operands->('valence->'arity,'sort)operandstype'valenceview=|Abs:'sortVariable.t*'valencet->('sort->'valence)view|Op:('arity,'sort)Operator.t*('arity,'sort)operands->'sortvaview|Var:'sortVariable.t->'sortvaviewtypepoly={f:'v.'vt->'vt}[@@ocaml.unboxed]letrecmap_operands:typeas.poly->(a,s)operands->(a,s)operands=funpolyoperands->matchoperandswith|[]->[]|x::xs->poly.fx::map_operandspolyxsletrecbind:typesv.sVariable.t->int->vt->vt=funvit->matchtwith|Freev'->beginmatchVariable.equalvv'with|SomeRefl->Bound(i,Variable.sortv)|None->tend|Bound(b,sort)->ifb<ithentelseBound(b+1,sort)|Abstr(name,sort,body)->Abstr(name,sort,bindv(i+1)body)|Oper(ator,ands)->Oper(ator,map_operands{f=funx->bindvix}ands)letabsvbody=Abstr(Variable.namev,v.Variable.sort,bindv0body)letopatorands=Oper(ator,ands)letvarv=Freevletinto:typev.vview->vt=function|Abs(v,body)->absvbody|Op(ator,ands)->opatorands|Varv->varvletrecunbind:typesv.sVariable.t->int->vt->vt=funvit->matchtwith|Free_->t|Bound(b,sort)->ifb=ithenmatchSort.equalv.sortsortwith|LeftRefl->Freev|Right_->failwith"unbind: Sort mismatch!"elseifb<ithentelseBound(b-1,sort)|Abstr(name,sort,body)->Abstr(name,sort,unbindv(i+1)body)|Oper(ator,ands)->Oper(ator,map_operands{f=funx->unbindvix}ands)letout:typev.vt->vview=function|Freev->Varv|Bound_->failwith"out: Unbound variable!"|Abstr(name,sort,body)->letv=Variable.freshsortnameinAbs(v,unbindv0body)|Oper(ator,ands)->Op(ator,ands)letrecsubst:types1s2.s1Sort.t->(s1Variable.t->s1vatoption)->s2t->s2t=funsortsubabt->matchabtwith|Freevar->beginmatchSort.equalsortvar.sortwith|LeftRefl->beginmatchsubvarwith|Someabt->abt|None->abtend|Right_->abtend|Bound_->abt|Abstr(name,sort',body)->Abstr(name,sort',substsortsubbody)|Oper(ator,ands)->Oper(ator,map_operands{f=funx->substsortsubx}ands)letrecaequiv:typev.vt->vt->bool=funt1t2->matcht1,t2with|Freevar1,Freevar2->beginmatchVariable.equalvar1var2with|SomeRefl->true|None->falseend|Bound(var1,_),Bound(var2,_)->var1=var2|Abstr(_,_,body1),Abstr(_,_,body2)->aequivbody1body2|Oper(ator1,ands1),Oper(ator2,ands2)->beginmatchOperator.equalator1ator2with|SomeRefl->aequiv_operandsands1ands2|None->falseend|_,_->falseandaequiv_operands:typeas.(a,s)operands->(a,s)operands->bool=funands1ands2->matchands1,ands2with|[],[]->true|x::xs,y::ys->aequivxy&&aequiv_operandsxsysletpp_print_varppfvar=Format.fprintfppf"%s/%d"(Variable.namevar)var.idletrecpp_print:types.Format.formatter->st->unit=funppft->matchouttwith|Varvar->pp_print_varppfvar|Abs(var,body)->Format.fprintfppf"%a.%a"pp_print_varvarpp_printbody|Op(ator,[])->Format.fprintfppf"%a()"Operator.pp_printator|Op(ator,abt::ands)->Format.fprintfppf"%a(@[<hv>%a%a)@]"Operator.pp_printatorpp_printabtpp_print_operandsandsandpp_print_operands:typeas.Format.formatter->(a,s)operands->unit=funppfoperands->matchoperandswith|[]->()|abt::next->Format.fprintfppf";@,%a%a"pp_printabtpp_print_operandsnextend