123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234(* elpi: embedded lambda prolog interpreter *)(* license: GNU Lesser General Public License Version 2.1 or later *)(* ------------------------------------------------------------------------- *)openElpi_utilopenUtilopenElpi_parseropenAstopenCompiler_datamoduleC=ConstantsexceptionStopCheck(* TYPE DECLARATION FOR FUNCTIONALITY *)typef=|Functionalofflist(* Used for functional preds, the f list represents the functionality relation of the arguments *)|Relationalofflist(* Used for non-functional preds, the f list represents the functionality relation of the arguments *)|NoProp(* Used for kinds like list, int, string... and abstractions not being props like: (int -> list bool), (string -> nat -> string) *)|AssumedFunctional(* Currently used for variadic functions, like print, halt... *)|BoundVarofF.t[@@derivingshow,ord]typet'=LamofF.t*t'|Foff[@@derivingshow,ord]typet=Loc.t*t'[@@derivingshow,ord]typefunc_map={ty_abbr:Scope.type_decl_idF.Map.t;(* Invariant every type_abbrev const is already in cmap *)cmap:(F.t*t)C.Map.t}[@@derivingshow,ord]typefname=F.t*t[@@derivingshow,ord]letpp_locsfmt(l:tlist)=Format.fprintffmt"[%a]"(pplist(funfmt->Format.fprintffmt"%a"Loc.pp)",")(List.mapfstl)letcompare_t(a:t)(b:t)=compare_t'(snda)(sndb)letcompare_fnameab=compare_t(snda)(sndb)letmk_func_mapty_abbrcmap={ty_abbr;cmap}letempty_fmap={ty_abbr=F.Map.empty;cmap=C.Map.empty}letget_functionality_tabbr_optmapk=matchF.Map.find_optkmap.ty_abbrwithNone->None|Somee->Some(C.Map.findemap.cmap)letget_functionalitymapk=C.Map.findkmap.cmap(* AUXILIARY FUNCTIONS *)letrecsubst~locsigma:f->f=function|BoundVarkast->beginmatchF.Map.find_optksigmawith|None->t|Some(Ff)->f|Some(Lam(_,b))->error~loc"type_abbrev not fully applied"end|Functionall->Functional(List.map(subst~locsigma)l)|AssumedFunctional|Relational_|NoPropast->tletrecbind~locsigma:(t'*flist)->f=function|Lam(n,b),x::xs->bind~loc(F.Map.addn(Fx)sigma)(b,xs)|Lam(_,b),[]->error~loc"type_abbrev is not fully applied"|Ft,[]->subst~locsigmat|F_,_::_->anomaly~loc"type_abbrev is too much applied"(* COMPILATION from SCOPE_TYPE_EXPRESSION TO FUNCTIONALITY *)moduleCompilation=structletadd_typeis_type_abbrfmap~n~idv=(* if F.Map.mem n fmap.ty_abbr then
error (Format.asprintf "Adding again type_abbrev %a" F.pp n); *)letcmap=C.Map.addid(n,v)fmap.cmapinletty_abbr=ifis_type_abbrthenF.Map.addnidfmap.ty_abbrelsefmap.ty_abbrinmk_func_mapty_abbrcmapletmergef1f2=letunion_samepkpecmpeke1e2=(* if cmpe e1 e2 = 0 then *)Somee1(* else error (Format.asprintf "The key %a has two different values (v1:%a) (v2:%a)" pk k pe e1 pe e2) *)inletcmap=C.Map.union(union_samepp_intpp_fnamecompare_fname)f1.cmapf2.cmapinletty_abbr=F.Map.union(union_sameF.pppp_intInt.compare)f1.ty_abbrf2.ty_abbrinmk_func_mapty_abbrcmapletmap_sndf=List.map(fun(_,ScopedTypeExpression.{it})->fit)letrectype2func_ty_abbr~locbound_vars(fmap:func_map)cargs=matchget_functionality_tabbr_optfmapcwith|None->NoProp(* -> c is a kind (like list, int, ...) *)|Some(_,f)->(* -> c is a type-abbrev *)bind~locF.Map.empty(sndf,List.map(type2func_loc~locbound_varsfmap)args)andtype2func~locbound_vars(fmap:func_map):ScopedTypeExpression.t_->f=function|Pred(Function,xs)->Functional(map_snd(type2func~locbound_varsfmap)xs)|Pred(Relation,xs)->Relational(map_snd(type2func~locbound_varsfmap)xs)|Const(_,c)whenF.Set.memcbound_vars->BoundVarc|Const(_,c)->type2func_ty_abbr~locbound_varsfmapc[]|App(_,c,x,xs)->type2func_ty_abbr~locbound_varsfmapc(x::xs)|Arrow(Variadic,_,_)->AssumedFunctional(* Invariant: the rightmost type in the right branch is not a prop due flatten_arrows in compiler *)|Arrow(NotVariadic,_,_)->NoProp|Any->NoPropandtype2func_loc~locbvarsfmapScopedTypeExpression.{it}=type2func~locbvarsfmapitletrectype2func_lambound_varstype_abbrevs:ScopedTypeExpression.v_->t=function|Lam(n,t)->let(loc,r)=type2func_lam(F.Set.addnbound_vars)type_abbrevstinloc,Lam(n,r)|Ty{it;loc}->loc,F(type2func~locbound_varstype_abbrevsit)lettype2funcf(x:ScopedTypeExpression.t)=type2func_lamF.Set.emptyfx.valueendletmerge=Compilation.mergeletrecfunctionalities_leql1l2=matchl1,l2with|_,[]->true(* l2 can be any length (due to partial application) *)|x::xs,y::ys->functionality_leqxy&&functionalities_leqxsys|[],_->error"the first list of functional args is can't been smaller then the second one: type error"andfunctionality_leqab=matcha,bwith|AssumedFunctional,AssumedFunctional->true|AssumedFunctional,t->error(Format.asprintf"Cannot compare %a with %a"pp_fapp_fb)(* TODO: print could be passed in a functional position *)|_,AssumedFunctional->error(Format.asprintf"Cannot compare %a with %a"pp_fapp_fb)|Relationalxs,Relationalys->functionalities_leqxsys|_,Relational_->true|Relational_,_->false|Functionalxs,Functionalys->functionalities_leqxsys|BoundVar_,_|_,BoundVar_->true(* TODO: this is not correct... *)|NoProp,NoProp->true|NoProp,_|_,NoProp->error"Type error, expected noProp found predicate"letfunctionality_leq_err~loccf'f=ifnot(functionality_leqf'f)thenerror~loc(Format.asprintf"Functionality of %a is %a and is not included in %a"F.ppcpp_ff'pp_ff)letreceat_lambdas=function|Lam(_,b)->eat_lambdasb|Fb->bletget_functionality_bvarsmapk=F.Map.findkmap|>eat_lambdas(*
Invariant every constant in the map is functional:
i.e. for each k in the domain, map[k] = Functional [...]
*)letis_functionalmapk=matchget_functionality_bvarsmapkwith|Functional_|NoProp|AssumedFunctional->true|Relational_|BoundVar_->falseletrechead_ag_func_pairingfunctional_predsargsfs=letfunc_vars=refF.Map.emptyinletrecaux~locf=function|ScopedTerm.Const(Global_,c)->(* Look into type_abbrev for global symbols *)(* Format.eprintf "1Looking for the constant %a\n%!" F.pp c; *)beginmatchget_functionality_bvarsfunctional_predscwith|(f')->functionality_leq_err~loccf'f(* | Lam _ -> failwith "Error not fully applied" *)end|Const_->failwith"TODO"|App(_,hd,x,xs)->Format.eprintf"2Looking for the constant %a -- %a\n%!"F.pphd(pplistScopedTerm.pp",")(x::xs);letf'=get_functionality_bvarsfunctional_predshdin(* let f' = bind functional_preds (f', List.map (get_functionality functional_preds) (x::xs)) in *)functionality_leq_err~lochdf'f;beginmatchf'with|Functionall->aux'(x::xs)l|_->()end|Impl_->error"TODO"(* Example p (a => b) *)|Discard->()|Var(v,ag)->beginmatchF.Map.find_optv!func_varswith|None->func_vars:=F.Map.addvf!func_vars(* -> First appereance of the variable in the head *)|Somef'->functionality_leq_err~locvf'fend|Lam(None,_type,{it})->failwith"TODO"|Lam(Some(e,_),_type,{it})->failwith"TODO"|CData_->assert(f=NoProp)(* note that this is also true, otherwise we would have a type error *)|Spill_->error"Spill in the head of a clause forbidden"|Cast({it},_)->aux~locfitandaux'argsfs=matchargs,fswith|[],[]->()|ScopedTerm.{it;loc}::xs,y::ys->aux~locyit;aux'xsys|_->failwith"Partial application ??"inaux'argsfs;!func_varsandcheck_headfunctional_predsfunc_varshead_namehead_args=matchget_functionality_bvarsfunctional_predshead_namewith|NoProp->raiseStopCheck|AssumedFunctional->raiseStopCheck|Functionall|Relationall->head_ag_func_pairingfunctional_predshead_argsl|BoundVarv->error"unreachable branch"andcheck_bodyfunc_vars=func_varsletreccheck_clause~loc~functional_predsfunc_varsScopedTerm.{it}=matchitwith|Impl(false,hd,body)->check_clause~loc~functional_predsfunc_varshd|>check_body|App(_,c,x,xs)->beginifString.starts_with~prefix:"std.map."(F.showc)thenfunc_varselsefunc_vars(* TODO: activate the check by uncommenting the following lines... *)(* try check_head functional_preds func_vars c (x::xs)
with StopCheck -> func_vars *)end|Const(_,_)->func_vars(* a predicate with arity 0 is functional *)|_->error~loc"invalid type"letcheck_clause~loc~functional_predst=check_clause~loc~functional_predsF.Map.emptyt|>ignoreclassmerger(all_func:func_map)=object(self)valmutableall_func=all_funcvalmutablelocal_func=empty_fmapmethodprivateadd_funcis_ty_abbrnidty=letfunc=Compilation.type2funcall_functyinifis_ty_abbrthenall_func<-Compilation.add_typeis_ty_abbr~id~nall_funcfunc;local_func<-Compilation.add_typeis_ty_abbr~id~nlocal_funcfunc;methodget_all_func=all_funcmethodget_local_func=local_funcmethodadd_ty_abbr=self#add_functruemethodadd_func_ty_listnamety(ty_w_id:TypeAssignment.overloaded_skema_with_id)=letid_list=matchty_w_idwithSinglee->[fste]|Overloadedl->List.mapfstlinList.iter2(self#add_funcfalsename)id_listtyend