123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631(**************************************************************************)(* *)(* ACG development toolkit *)(* *)(* Copyright 2008-2023 INRIA *)(* *)(* More information on "https://acg.loria.fr/" *)(* License: CeCILL, see the LICENSE file or "http://www.cecill.info" *)(* Authors: see the AUTHORS file *)(* *)(* *)(* *)(* *)(* *)(**************************************************************************)openUtilsLibopenTableopenLogic.LambdaopenLogic.Abstract_syntaxtypesig_entry=|Type_declarationofstring*int*Lambda.kind|Type_definitionofstring*int*Lambda.kind*Lambda.stype|Term_declarationofstring*int*Abstract_syntax.syntactic_behavior*Lambda.stype|Term_definitionofstring*int*Abstract_syntax.syntactic_behavior*Lambda.stype*Lambda.termmoduleLog=Xlog.Make(structletname="Signature"end)moduleMake(Symbols:TABLEwithtypekey=String.t)(Id:TABLEwithtypekey=int)=structexceptionDuplicate_type_definitionexceptionDuplicate_term_definitionexceptionNot_foundexceptionNot_functional_type(* exception Not_yet_implemented *)typeentry=sig_entrytypeid=int[@@@warning"-69"]typet={name:string*id;loc:string*Abstract_syntax.location;(* name of the file where
the signature is
defined and its
location *)size:int;terms:entrySymbols.t;types:entrySymbols.t;precedence:(float*stringoption)Symbols.t;(* indicates the precedence and a link to the previous one *)max_pred:float*stringoption;(* indicates the greatest precedence and a link to the previous one *)ids:entryId.t;is_2nd_order:bool;extension_timestamp:float;definition_timestamp:float;}[@@@warning"+69"]typeterm=Lambda.termtypestype=Lambda.stypetypedata=Typeofstype|Termof(term*stype)letfind_termsym{terms=syms;_}=matchSymbols.findsymsymswith|Term_declaration(x,id,_,const_type)whensym=x->(Lambda.Constid,const_type)|Term_declaration_->failwith"Bug in find_term"(* x should match the symbol *)|Term_definition(x,id,_,const_type,_)whensym=x->(Lambda.DConstid,const_type)|Term_definition_->failwith"Bug in find_term"(* x should match the symbol *)|_->failwith"Bug in find_term"(* x should return a Term, not a type *)|exceptionSymbols.Not_found->raiseNot_foundletid_to_string{ids;_}i=matchId.findiidswith|Type_declaration(s,_,_)->(Abstract_syntax.Default,s)|Type_definition(s,_,_,_)->(Abstract_syntax.Default,s)|Term_declaration(s,_,behavior,_)->(behavior,s)|Term_definition(s,_,behavior,_,_)->(behavior,s)letpp_typesgppfty=Lambda.pp_type(id_to_stringsg)ppftyletpp_termsgppft=Lambda.pp_term(id_to_stringsg)ppftletempty~filename(n,l)=lettimestamp=Unix.time()in{name=(n,Random.(let()=self_init()inbits()));loc=filename,l;size=0;terms=Symbols.empty;types=Symbols.empty;ids=Id.empty;is_2nd_order=true;precedence=Symbols.empty;max_pred=(0.,None);definition_timestamp=timestamp;extension_timestamp=timestamp;}letname{name=n,_;loc=_,l;_}=n,lletfull_name{name=n;loc=filename,_;_}=n,filenameletfind_atomic_types{types=syms;_}=(* TODO : Replace by an assert within IFDEFDEBUG *)matchSymbols.findssymswith|Type_declaration(x,id,_)whenx=s->Lambda.Atomid|Type_declaration_->failwith"Bug in find_atomic_type"(* x and s should match if something is returned *)|Type_definition(x,id,_,_)whenx=s->Lambda.DAtomid|Type_definition_->failwith"Bug in find_atomic_type"(* x and s should match if something is returned *)|_->failwith"Bug in find_atomic_type"(* A type, not a term should be returned *)|exceptionSymbols.Not_found->failwith"Bug in find_atomic_type"letfind_typessg=(* TODO : Replace by an assert within IFDEFDEBUG *)matchSymbols.findssg.typeswith|Type_declaration(x,id,_)whenx=s->Lambda.Atomid|Type_definition(x,id,_,_)whenx=s->Lambda.DAtomid|_->failwith"Bug in find_type"(* A type, not a term should be returned and x and s should match *)|exceptionSymbols.Not_found->raiseNot_found[@@warning"-32"]letrecconvert_typetysg=matchtywith|Abstract_syntax.Type_atom(s,_,_)->find_atomic_typessg|Abstract_syntax.Linear_arrow(ty1,ty2,_)->Lambda.LFun(convert_typety1sg,convert_typety2sg)|Abstract_syntax.Arrow(ty1,ty2,_)->Lambda.Fun(convert_typety1sg,convert_typety2sg)letabstract_on_dependent_typeslstsg=List.fold_right(funxacc->Lambda.Depend(convert_typexsg,acc))lstLambda.Typeletadd_sig_typete({size=s;types=syms;ids;_}assg)=try(* First perform addition on the functional data structure *)letnew_symbols=Symbols.addtesymsin(* timestamps modified at add_entry function *){sgwithsize=s+1;types=new_symbols;ids=Id.addseids}with|Symbols.Conflict->raiseDuplicate_type_definition|Id.Conflict->raiseDuplicate_type_definitionletadd_sig_termte({size=s;terms=syms;ids;_}assg)=try(* First perform addition on the functional data structure *)letnew_symbols=Symbols.addtesymsin(* timestamps modified at add_entry function *){sgwithsize=s+1;terms=new_symbols;ids=Id.addseids}with|Symbols.Conflict->raiseDuplicate_term_definition|Id.Conflict->raiseDuplicate_term_definitionletrecexpand_typety({ids;_}assg)=matchtywith|Lambda.Atom_->ty|Lambda.DAtomi->(matchId.findiidswith|Type_definition(_,_,_,ty1)->expand_typety1sg|_->failwith"Bug in expand type")|Lambda.LFun(ty1,ty2)->Lambda.LFun(expand_typety1sg,expand_typety2sg)|Lambda.Fun(ty1,ty2)->Lambda.Fun(expand_typety1sg,expand_typety2sg)|_->failwith"Not yet implemented"letrecexpand_termt({ids;_}assg)=matchtwith|Lambda.Var_|Lambda.LVar_|Lambda.Const_->t|Lambda.DConsti->(matchId.findiidswith|Term_definition(_,_,_,_,u)->expand_termusg|_->failwith"Bug in expand term")|Lambda.Abs(x,u)->Lambda.Abs(x,expand_termusg)|Lambda.LAbs(x,u)->Lambda.LAbs(x,expand_termusg)|Lambda.App(u,v)->Lambda.App(expand_termusg,expand_termvsg)|_->failwith"Not yet implemented"letunfold_type_definitioni({ids;_}assg)=matchId.findiidswith|Type_definition(_,_,_,ty1)->expand_typety1sg|_->failwith"Bug in unfold_type_definition"letunfold_term_definitioni({ids;_}assg)=matchId.findiidswith|Term_definition(_,_,_,_,t)->expand_termtsg|_->failwith"Bug in unfold_term_definition"letget_type_of_const_idi({ids;_}assg)=matchId.findiidswith|Term_declaration(_,_,_,ty)->expand_typetysg|Term_definition(_,_,_,ty,_)->expand_typetysg|_->failwith"Should be applied only on constants"|exceptionId.Not_found->failwith"Bug in get_type_of_const_id"letrecdecompose_functional_typety({ids;_}assg)=matchtywith|Lambda.LFun(ty1,ty2)->(ty1,ty2,Abstract_syntax.Linear)|Lambda.Fun(ty1,ty2)->(ty1,ty2,Abstract_syntax.Non_linear)|Lambda.DAtomi->(matchId.findiidswith|Type_definition(_,_,_,ty1)->decompose_functional_typety1sg|_->failwith"Bug in decompose_functional_type")|_->raiseNot_functional_typeletget_binder_argument_functional_typex({terms;_}assg)=letty=matchSymbols.findxtermswith|Term_declaration(_,_,_,ty)->ty|Term_definition(_,_,_,ty,_)->ty|_->failwith(Printf.sprintf"Bug: Request of the type of the non constant \"%s\""x)intryletty1,_,_=decompose_functional_typetysginlet_,_,lin=decompose_functional_typety1sginSomelinwithNot_functional_type->None(* We assume here that [term] is well typed and in beta-normal form
and that types and terms definitions have been unfolded*)leteta_long_formtermstypesg=letexpanded_type=expand_typestypesginletexpanded_term=expand_termtermsginletres=Lambda.eta_long_formexpanded_termexpanded_type(funid->get_type_of_const_ididsg)inletf1=pp_termsginletf2=pp_typesginLog.debug(funm->m"term: %a:%a"f1termf2stype);Log.debug(funm->m"eta_long_form: %a:%a"f1resf2expanded_type);resletunfoldtsg=Lambda.normalize(expand_termtsg)letis_atomictsg=Lambda.is_atomict(funi->unfold_type_definitionisg)typetemp_t=t(* type temp_entry=entry *)moduleType_System=Type_system.Type_System.Make(structexceptionNot_foundtypet=temp_tletunfold_type_definition=unfold_type_definitionletexpand_type=expand_typeletfind_term=find_termletpp_type=pp_typeletpp_term=pp_termend)lettypecheck=Type_System.typecheckletstamp_declarationsg={sgwithextension_timestamp=Unix.time()}letstamp_definitionsg={sgwithdefinition_timestamp=Unix.time()}letadd_entrye({size=s;_}assg)=matchewith|Abstract_syntax.Type_decl(t,_,Abstract_syntax.Kk)->stamp_declaration(add_sig_typet(Type_declaration(t,s,abstract_on_dependent_typesksg))sg)|Abstract_syntax.Type_def(t,_,ty,Abstract_syntax.Kk)->stamp_definition(add_sig_typet(Type_definition(t,s,abstract_on_dependent_typesksg,convert_typetysg))sg)|Abstract_syntax.Term_decl(t,behavior,_,ty)->lett_type=convert_typetysginletsg_is_2nd_order=sg.is_2nd_order&&Lambda.is_2nd_ordert_type(funi->unfold_type_definitionisg)instamp_declaration(add_sig_termt(Term_declaration(t,s,behavior,convert_typetysg)){sgwithis_2nd_order=sg_is_2nd_order})|Abstract_syntax.Term_def(t,behavior,_,term,ty)->lett_type=convert_typetysginlett_term,_=typechecktermt_typesginstamp_definition(add_sig_termt(Term_definition(t,s,behavior,t_type,t_term))sg)letis_type?(atomic=false)s{types=syms;_}=matchSymbols.findssymswith|Type_declaration_->true|Type_definition_whennotatomic->true|_->false|exceptionSymbols.Not_found->falseletis_constants({terms=syms;_}assg)=matchSymbols.findssymswith|Term_declaration(_,_,behavior,ty)->(true,Some(behavior,false,is_atomic(expand_typetysg)sg))|Term_definition(_,_,behavior,ty,_)->(true,Some(behavior,true,is_atomic(expand_typetysg)sg))|_->(false,None)|exceptionSymbols.Not_found->(false,None)(*
let precedence s {precedence;_} =
match Symbols.find s precedence with
| f,_ -> Some f
| exception Symbols.Not_found -> None
*)letnew_precedence?beforeidsg=match(before,sg.max_pred)with|None,(f,None)->letp=f+.1.in(p,{sgwithmax_pred=(p,Someid);precedence=Symbols.addid(p,None)sg.precedence;})|None,(f,(Some_asmax))->letp=f+.1.in(p,{sgwithmax_pred=(p,Someid);precedence=Symbols.addid(p,max)sg.precedence;})|Some_,(f,None)->(* Strange to give an upper bound when there is no max. Behaves
like introducing the first element *)letp=f+.1.in(p,{sgwithmax_pred=(p,Someid);precedence=Symbols.addid(p,None)sg.precedence;})|Someupper_bound,_->(matchSymbols.findupper_boundsg.precedencewith|f_up,None->letf_down=0.inletp=(f_up+.f_down)/.2.inletnew_pred=Symbols.add~overwrite:trueupper_bound(f_up,Someid)(Symbols.addid(p,None)sg.precedence)in(p,{sgwithprecedence=new_pred})|f_up,Somelower_bound->letf_down,_=Symbols.findlower_boundsg.precedenceinletp=(f_up+.f_down)/.2.inletnew_pred=Symbols.addupper_bound(f_up,Someid)(Symbols.addid(p,Somelower_bound)sg.precedence)in(p,{sgwithprecedence=new_pred})|exceptionNot_found->failwith"Bug: Shouldn't happen")letraw_to_stringt=Lambda.raw_to_stringt[@@warning"-32"]letbehavior_to_string=function|Abstract_syntax.Default->""|Abstract_syntax.Prefix->"prefix "|Abstract_syntax.Infix_->"infix "|Abstract_syntax.Binder->"binder "letpp_entryffmtdecl=letpp_kind=Lambda.pp_kindfinletpp_type=Lambda.pp_typefinletpp_term=Lambda.pp_termfinmatchdeclwith|Type_declaration(s,_,k)->Format.fprintffmt"@[<hov 4>%s :@ @[%a@];@]"spp_kindk|Type_definition(s,_,k,ty)->Format.fprintffmt"@[<hov 4>%s =@ @[%a :@ @[%a@];@]@]"spp_typetypp_kindk|Term_declaration(s,_,behavior,ty)->Format.fprintffmt"@[<hov 4>%s%s :@ @[%a@];@]"(behavior_to_stringbehavior)spp_typety|Term_definition(s,_,behavior,ty,t)->Format.fprintffmt"@[<hov 4>%s%s =@ @[%a :@ @[%a@];@]@]"(behavior_to_stringbehavior)spp_termtpp_typetyletppfmt({name=n,_;ids;_}assg)=Format.fprintffmt"signature %s =@,@[<v 2>@[%a@]@]@,end@."n(Id.pp(funfmt_entry->pp_entry(id_to_stringsg)fmtentry))idsletconvert_termttysg=lett_type=convert_typetysginlett,_=typechecktt_typesgin(t,t_type)lettype_of_constantx{terms=syms;_}=matchSymbols.findxsymswith|Term_declaration(s,_,_,ty)whenx=s->ty|Term_definition(s,_,_,ty,_)whenx=s->ty|_->failwith"Bug in type_of_constant"|exceptionSymbols.Not_found->failwith"Bug in type_of_constant"letfoldfa{ids;_}=Id.fold(fun_attacc->fattacc)aidsletis_declarede_=matchewith|Type_declaration(s,_,_)->Somes|Term_declaration(s,_,_,_)->Somes|_->Noneletis_2nd_order{is_2nd_order;_}=is_2nd_orderletentry_to_datae=matchewith|Type_declaration(_,id,_)->Type(Lambda.Atomid)|Type_definition(_,_,_,stype)->Typestype|Term_declaration(_,id,_,stype)->Term(Lambda.Constid,stype)|Term_definition(_,_,_,stype,term)->Term(term,stype)letgen_term_listsgtymin_depthmax_depthshuffle=letincr_varsvars=List.map(fune->let(args,t,tc)=einmatchtcwith|Lambda.Varn->(args,t,Lambda.Var(n+1))|Lambda.LVarn->(args,t,Lambda.LVar(n+1))|_->e)varsin(* This function decrements the indexes of all linear variables in the list
"vars". We use it when the term of a linear abstraction has been built,
because we need to return the linear variables list (which contains those
which don't appear in the term) to the caller. At the same time, we check
that we don't have a linear variable with an index of 0 in the list,
because this would mean that it has not been used in the term, so it is
invalid. *)letrecdecr_varsvars=matchvarswith|(args,t,tc)::t_vars->(matchtcwith|Lambda.LVarn->ifn=0thenNoneelseOption.map(funvars->(args,t,Lambda.LVar(n-1))::vars)(decr_varst_vars)|_->Option.map(funvars->(args,t,tc)::vars)(decr_varst_vars))|[]->Some[]inletshuffle_rulesrules=letpairs=List.map(funr->(Random.bits(),r))rulesinletsorted_pairs=List.sort(funp1p2->compare(fstp1)(fstp2))pairsinList.mapsndsorted_pairsinletget_letteri=String.make1(Char.chr(97+(imod26)))inlettype_to_ruletyterm=letty=expand_typetysginletrecgen_arg_listtyacc=matchtywith|Lambda.Atom_->(acc,ty)|Lambda.Fun(ty1,ty2)->gen_arg_listty2((ty1,false)::acc)|Lambda.LFun(ty1,ty2)->gen_arg_listty2((ty1,true)::acc)|_->failwith"Not implemented"inlet(arg_list,ty_f)=gen_arg_listty[]in(arg_list,ty_f,term)in(* This builds a rule list from all term declarations in the signature. A
rule is of type "((stype, bool) list, stype, term)" and if
"(arg_list, ty, te)" is a rule, it says "to build a term of type "ty"",
one needs to compute a term of each type in the list "arg_list", add
apply all theses terms to "te". The type "ty" is always an atom. The
boolean associated to each type in the list "arg_list" is true iff free
linear variables are allowed in the corresponding term to build. In
other words, the rule "([(A, true), (B, true), (A, false)], C, build_c)"
corresponds to this signature entry : "build_c : A -> B -> A => C". *)letenv=fold(funel->matchewith|Term_declaration(_,i,_,t)->(type_to_rulet(Lambda.Consti))::l|_->l)[]sginletterm_deptht=letrecterm_depth_rectadd=matchtwith|Lambda.Abs(_,t)->term_depth_rect1|Lambda.LAbs(_,t)->term_depth_rect1|Lambda.App(t1,t2)->add+max(term_depth_rect10)(term_depth_rect21)|_->1interm_depth_rect1inletreccompute_arg(ty,lin)varslvars_lletterfuel=LazyList.join_mix(LazyList.map(funlvars_b->(LazyList.map(fun(lvars_a,term)->((iflinthenlvars_aelselvars_b),term))(gen_term_rectyvars(iflinthenlvars_belse[])letter(fuel-1))))lvars_l)andapply_ruleargstermvarslvarsletterfuel=matchargswith|arg::args->LazyList.bind_mix(fun(lvars,arg_term)->LazyList.map(fun(lvars,term)->(lvars,Lambda.App(term,arg_term)))(apply_ruleargstermvarslvarsletterfuel))(compute_argargvars(LazyList.onelvars)letterfuel)|[]->LazyList.one(lvars,term)(* This function builds all possible terms using the rules in the list
"rules". The rules are tried one by one (by calling the function
"apply_rule"). When a rule corresponds to a linear variable (when it is
of the form "(_, _, Lvar _)"), we need to remove its corresponding rule
from the current context. *)andapply_rulesrulesvarslvarsletterfuel=matchruleswith|(args,_,tc)::rules->letlvars_f=(matchtcwith|Lambda.LVari->List.filter(fun(_,_,term)->matchtermwith|Lambda.LVarj->not(i=j)|_->false)lvars|_->lvars)inLazyList.append_mix(apply_ruleargstcvarslvars_fletterfuel)(fun()->apply_rulesrulesvarslvarsletterfuel)|[]->LazyList.Nil(* To generate the terms of type "t" with the rules in the list "env", the
variables in the list "vars" and the linear variables in the list
"l_vars", we have three cases :
- The type "t" is an atom, so we select all the rules which give a
term of type "t" from the environment "env" and the list of linear
variables "l_vars", shuffle them in a random order, and try all of
them to build all possible terms.
- The type is a normal arrow, "A -> B", so we add a new rule
corresponding to A in the variables list, and try to build all
possible terms of type B with this new environment. We apply an
abstraction to all generated terms.
- The type is a linear arrow, "A => B", so we add a new rule
corresponding to A in the linear variables list, and try to build all
possible terms of type B. We then return all generated terms in which
this linear variable has been used, with a linear abstraction. *)andgen_term_rectyvarslvarsletterfuel=letty=expand_typetysginiffuel=0thenLazyList.Nilelsematchtywith|Lambda.Atom_->letrules=List.filter(fun(_,ty_rule,_)->ty=ty_rule)(env@vars@lvars)inletres=ifshufflethenapply_rules(shuffle_rulesrules)varslvarsletterfuelelseapply_rulesrulesvarslvarsletterfuelinres|Lambda.Fun(ty1,ty2)->LazyList.map(fun(lvars,term)->(lvars,Lambda.Abs(get_letterletter,term)))(gen_term_recty2((type_to_rulety1(Lambda.Var0))::(incr_varsvars))lvars(letter+1)fuel)|Lambda.LFun(ty1,ty2)->LazyList.filter_map(fun(lvars,term)->Option.map(funlvars->(lvars,Lambda.LAbs(get_letterletter,term)))(decr_varslvars))(gen_term_recty2vars((type_to_rulety1(Lambda.LVar0))::(incr_varslvars))(letter+1)fuel)|_->LazyList.NilinLazyList.filter_map(fun(_,t)->ifterm_deptht>=min_depththenSometelseNone)(gen_term_recty[][]0max_depth)endmoduleTable=Table.Make_table(structletb=10end)(*module Table =
struct
module IntMap = Map.Make(struct type t=int let compare i j = i-j end)
type 'a t = 'a IntMap.t
type key = int
exception Conflict
let empty = IntMap.empty
let add ?(overwrite=false) k v t =
try
let _ = IntMap.find k t in
if overwrite then IntMap.add k v t else raise Conflict
with
| Not_found -> IntMap.add k v t
exception Not_found
let find k t =
try
IntMap.find k t
with
| Not_found -> raise Not_found
let fold f acc t = IntMap.fold f t acc
end
*)moduleData_Signature=Make(Tries.Tries)(Table)