123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323(* elpi: embedded lambda prolog interpreter *)(* license: GNU Lesser General Public License Version 2.1 or later *)(* ------------------------------------------------------------------------- *)openElpi_util.UtilopenCompiler_datamoduleC=ConstantsopenScopedTermtypespill={vars_names:binderlist;expr:t}typespills=spilllistletargs_missing_to_prop~type_abbrevsx=letty=TypeAssignment.derefxinletrecauxextra=function|TypeAssignment.Prop_->Some(List.revextra)(* | TypeAssignment.(App(f,Prop _,[])) when F.show f = "list" -> true hack since the type checker unifies prop with list prop *)|TypeAssignment.Arr(_,Elpi_parser.Ast.Structured.NotVariadic,ty,t)asarrow->aux((TypeAssignment.createty,TypeAssignment.createarrow)::extra)t|TypeAssignment.Arr(_,Elpi_parser.Ast.Structured.Variadic,_,t)->auxextrat|TypeAssignment.UVarrwhenMutableOnce.is_setr->auxextra(TypeAssignment.derefr)|TypeAssignment.App(c,x,xs)whenF.Map.memctype_abbrevs->lett=TypeAssignment.apply(fst@@F.Map.findctype_abbrevs)(x::xs)inauxextrat|TypeAssignment.ConscwhenF.Map.memctype_abbrevs->lett=TypeAssignment.apply(fst@@F.Map.findctype_abbrevs)[]inauxextrat|_->Noneinaux[]tyleteat~type_abbrevsargsty=letty=TypeAssignment.dereftyinletrecauxargsty=matchargswith|[]->ty|_::argsasorig_args->matchtywith|TypeAssignment.Arr(_,Elpi_parser.Ast.Structured.Variadic,_,t)->ifargs=[]thenauxargstelsety|TypeAssignment.Arr(_,Elpi_parser.Ast.Structured.NotVariadic,_,t)->auxargst|TypeAssignment.UVarrwhenMutableOnce.is_setr->auxorig_args(TypeAssignment.derefr)|TypeAssignment.App(c,x,xs)whenF.Map.memctype_abbrevs->lett=TypeAssignment.apply(fst@@F.Map.findctype_abbrevs)(x::xs)inauxorig_argst|TypeAssignment.ConscwhenF.Map.memctype_abbrevs->lett=TypeAssignment.apply(fst@@F.Map.findctype_abbrevs)[]inauxorig_argst|_->anomaly("eat args: "^TypeAssignment.(show@@Valty))inTypeAssignment.create@@auxargstyletis_prop~type_abbrevsx=matchargs_missing_to_prop~type_abbrevsxwith|Somen->List.lengthn=0|None->falseletmk_global~types~locfl=(* TODO: check only builtins *)lets=Symbol.make_builtinfinletf_ty=TypingEnv.(resolve_symbolstypes).ty|>(funx->TypeAssignment.applyxl)|>TypeAssignment.createin{scope=Scope.mkResolvedGlobaltypess;name=f;ty=f_ty;loc}letpif_w_name_ty~types({ty;loc}:'aw_ty_loc):const=mk_global~types~locF.pif[TypeAssignment.derefty]letpif_ty~types(ty:binder)=(pif_w_name_ty~typesty).tyletpif_arg_ty~typesty=matchTypeAssignment.deref@@pif_ty~typestywith|TypeAssignment.Arr(_,_,x,_)->TypeAssignment.createx|_->assertfalseletmk_loc~loc~tyit={ty;it;loc}(* TODO store the types in Main *)letadd_spilled~types(l:spilllist)t=ifl=[]thentelseList.fold_right(fun{expr;vars_names}t->vars_names(* Format.eprintf "fold %a\n" ScopedTerm.pretty t; *)|>List.fold_left(funt(v:binder)->mk_loc~loc:t.loc~ty:t.ty@@App(mk_global~loc:v.loc~typesF.sigmaf[TypeAssignment.derefv.ty],[mk_loc~loc:t.loc~ty:TypeAssignment.(create(Arr(MRef(MutableOnce.makeF.dummyname),NotVariadic,derefv.ty,dereft.ty)))@@Lam(Somev,None,t)]))(mk_loc~loc:t.loc~ty:TypeAssignment.(create(PropElpi_parser.Ast.Structured.Function))@@App(mk_global~types~loc:t.locF.andf[],[expr;t])))ltletmkAppnl=App(n,l)letis_symbol~typesb=function|Scope.Global{resolved_to=x}->beginmatchSymbolResolver.resolved_totypesxwith|Somes->TypingEnv.same_symboltypessb|_->anomaly"unresolved global symbol"end|_->falseletapp~type_abbrevs~typestargs=ifargs=[]thentelseletrecaux{loc;it;ty}:t=letit,ty=matchitwith|App(({scope=s}asn),xs)whenis_symbol~typesElpi_runtime.Data.Global_symbols.and_s->mkAppn(aux_lastxs),eat~type_abbrevsargsty|Impl(b,l,s,t)->Impl(b,l,s,auxt),ty|App(n,xs)->mkAppn(xs@args),eat~type_abbrevsargsty|UVar(c,l)->UVar(c,l@args),eat~type_abbrevsargsty|Discard_|Lam(_,_,_)|CData_|Spill(_,_)|Cast(_,_)->assertfalseinmk_loc~loc~tyitandaux_last=function[]->assertfalse|[x]->[auxx]|x::xs->x::aux_lastxsinauxtletmk_spilled~loc~tyargsn:(binder*t)list=(* builds the type of the spilled variables, all variables has same type *)(* let builf_head_ty tgt_ty =
let rec aux = function
| [] -> tgt_ty
| ScopedTerm.{ ty } :: tl ->
TypeAssignment.(Arr (MRef (MutableOnce.make F.dummyname), NotVariadic, deref ty, aux tl))
in
TypeAssignment.create (aux ctx)
in *)letrecauxnty=ifn=0then[]elseletf=incrargs;F.from_string(Printf.sprintf"%%spill%d"!args)inletbuilt_tmty=lethd_ty=TypeAssignment.createtyinmk_loc~loc~ty:hd_ty@@App(mk_bound_const~lang:elpi_languagef~loc~ty:hd_ty,[])inmatchtywith|TypeAssignment.Arr(_,_,l,r)->(mk_binder~lang:elpi_languagef~loc~ty:(TypeAssignment.createl),built_tml)::aux(n-1)r|UVarrwhenMutableOnce.is_setr->auxn(TypeAssignment.derefr)|_->anomaly"type abbreviations and spilling, not implemented"inauxnty(* barendregt_convention (naive implementation) *)letrecbcctxt=matchtwith|Lam(None,o,t)->Lam(None,o,bc_locctxt)|Lam(Some{scope=l;name=c;loc;ty=tya},o,t)whenList.mem(c,l)ctx->letd=fresh()inbcctx(Lam(Some{scope=l;name=d;loc;ty=tya},o,rename_loclcdt))|Lam((Some{scope=l;name=c}asabs),o,t)->Lam(abs,o,bc_loc((c,l)::ctx)t)|Impl(b,bl,t1,t2)->Impl(b,bl,bc_locctxt1,bc_locctxt2)|Cast(t,ty)->Cast(bc_locctxt,ty)|Spill(t,i)->Spill(bc_locctxt,i)|App(hd,xs)->App(hd,List.map(bc_locctx)xs)|Discard_|UVar_|CData_->tandbc_locctx{loc;ty;it}={loc;ty;it=bcctxit}(* let not_from_pi (_,b) = b = false *)(* let from_pi (_,b) = b = true *)letrecapplywhatv=function|App({scope=Boundl;name=f;ty=hd_ty}asn,xs)whenl=elpi_language&&List.exists(funf'->F.equalff'.name)what->App({nwithty=TypeAssignment.(create@@Arr(MRef(MutableOnce.makeF.dummyname),NotVariadic,derefv.ty,derefhd_ty))},v::xs)|App(f,xs)->App(f,smart_map(apply_locwhatv)xs)|Lam(n,o,t)->Lam(n,o,apply_locwhatvt)|Impl(d,l,t1,t2)->Impl(d,l,apply_locwhatvt1,apply_locwhatvt2)|Cast(t,e)->Cast(apply_locwhatvt,e)|Spill_->assertfalse|CData_|Discard_|UVar_asx->xandapply_locwhatv{loc;ty;it}={loc;ty;it=applywhatvit}letapply_locwhatvt=(* Format.eprintf "apply %a to %a in %a\n" (pplist (fun fmt (s,_,_) -> Format.fprintf fmt "%s" s) " ") what ScopedTerm.pretty v ScopedTerm.pretty t; *)lett=apply_locwhatvtin(* Format.eprintf "apply=%a\n" ScopedTerm.pretty t; *)tletrecspill~type_abbrevs~types?(extra=0)args({loc;ty;it}ast):spills*tlist=(* Format.eprintf "@[<hov 2>spill %a :@ %a@]\n" pretty t TypeAssignment.pretty (TypeAssignment.deref ty); *)matchitwith|CData_|Discard_->([],[t])|Cast(t,_)->spill~types~type_abbrevsargst|Spill(t,{contents=NoInfo})->assertfalse(* no type checking *)|Spill(t,{contents=Phantom_})->assertfalse(* escapes type checker *)|Spill(t,{contents=Mainn})->letty=t.tyin(* Format.eprintf "Spilling of %a with ty %a requires %d slots@." ScopedTerm.pretty_ it TypeAssignment.pretty_mut_once (UVar ty) n; *)letvars_names,vars=List.split@@mk_spilled~loc~ty:(TypeAssignment.derefty)argsninlett=app~type_abbrevs~typestvarsinletspills,t=spill1~types~type_abbrevs~extra:(List.lengthvars_names)argstin(* Format.eprintf "Spilled %a@." ScopedTerm.pretty t; *)(spills@[{vars_names;expr=t}],vars)(* globals and builtins *)|App(({scope=s}ashd),[{it=Lam(Somev,o,t);loc=tloc;ty=tty}])whenis_symbol~typesElpi_runtime.Data.Global_symbols.pis->letspilled,t=spill1~types~type_abbrevsargstin([],[{loc;ty;it=App(hd,[{it=Lam(Somev,o,add_spilled~typesspilledt);loc=tloc;ty=tty}])}])|App(({scope=s}ashd),[{it=Lam(Somev,o,t);loc=tloc;ty=tty}])whenis_symbol~typesElpi_runtime.Data.Global_symbols.sigmas->(* not to be put in scope of spills *)letspilled,t=spill1~types~type_abbrevsargstin([],[{loc;ty;it=App(hd,[{it=Lam(Somev,o,add_spilled~typesspilledt);loc=tloc;ty=tty}])}])|App(({scope=s;ty=hty}ashd),xs)->letmk_eta_var()=incrargs;F.from_string@@Format.asprintf"%%eta%d"!argsinletlast=ifis_symbol~typesElpi_runtime.Data.Global_symbols.and_sthenList.lengthxselse-1inletspills,args=List.split@@List.mapi(funi->spill~types~type_abbrevs~extra:(ifi=lastthenextraelse0)args)xsinletargs=List.flattenargsinletspilled=List.flattenspillsinletit=App(hd,args)inletty=eat~type_abbrevsargshtyinifspilled=[]then(spilled,[{it;loc;ty}])elsebeginmatchargs_missing_to_prop~type_abbrevstywith|None->(spilled,[{it;loc;ty}])|Somemissing->letrecmk_lamlt=matchlwith|[]->t|(v,ty)::vs->{loc;ty;it=Lam(Somev,None,mk_lamvst)}inletmissing_vars=List.map(fun(ty,arrow)->letv=mk_eta_var()in(mk_binder~lang:elpi_languagev~loc~ty,arrow))missinginletmissing_args=List.map(fun(v,_)->{ty;loc;it=App(bind_constv,[])})missing_varsinlett={it;loc;ty}inlett=mk_lammissing_vars@@add_spilled~typesspilled(app~type_abbrevs~typestmissing_args)in([],[t])end(* TODO: positive/negative postion, for now we assume :- and => are used in the obvious way *)|Impl(R2L,l,head,premise)->(* head :- premise *)letspills_head,head=spill1~types~type_abbrevsargsheadinifspills_head<>[]thenerror~loc"Spilling in the head of a clause is not supported";letspilled,premise=spill1~types~type_abbrevsargspremiseinletit=Impl(R2L,l,head,premise)in([],[add_spilled~typesspilled{it;loc;ty}])|Impl((L2R|L2RBang)askind,l,premise,conclusion)->(* premise => conclusion *)letspills_premise,premise=spill1~types~type_abbrevsargspremiseinifspills_premise<>[]thenerror~loc"Spilling in the premise of an implication is not supported";letspilled,conclusion=spill1~types~type_abbrevs~extraargsconclusioninletit=Impl(kind,l,premise,conclusion)in([],[add_spilled~typesspilled{it;loc;ty}])(* lambda terms *)|Lam(None,o,t)->letspills,t=spill1~types~type_abbrevsargstin(spills,[{it=Lam(None,o,t);loc;ty}])|Lam((Somecasabs),o,t)->letspills,t=spill1~types~type_abbrevsargstinlett,spills=let{scope=s;name=f;ty}=cinmap_acc(funt{vars_names;expr}->letbc=mk_loc~loc~ty(App(bind_constc,[]))in(apply_locvars_namesbct,{vars_names=List.map(fun(v:binder)->{vwithty=TypeAssignment.(create@@Arr(MRef(MutableOnce.makeF.dummyname),NotVariadic,derefty,derefv.ty))})vars_names;expr=mk_loc~loc~ty:(pif_ty~typesc)@@App(pif_w_name_ty~typesc,[mk_loc~loc~ty:(pif_arg_ty~typesc)@@Lam(abs,o,apply_locvars_namesbcexpr)]);}))tspillsin(spills,[{it=Lam(abs,o,t);loc;ty}])(* holes *)|UVar({ty=cty}asc,xs)->letspills,args=List.split@@List.map(spill~types~type_abbrevsargs)xsinletargs=List.flattenargsinletspilled=List.flattenspillsinletit=UVar(c,args)inletty=eat~type_abbrevsargsctyinifis_prop~type_abbrevstythen([],[add_spilled~typesspilled{it;loc;ty}])else(spilled,[{it;loc;ty}])andspill1~type_abbrevs~types?extraargs({loc}ast)=letspills,t=spill~types~type_abbrevs?extraargstinlett=ifList.lengtht<>1thenerror~loc"bad spilling"elseList.hdtin(spills,t)letfresh=ref0letrecremove_top_sigmas~typest=matcht.itwith|App({scope=s},[_])whenis_symbol~typesElpi_runtime.Data.Global_symbols.pis->t|App({scope=s}asn,xs)whenis_symbol~typesElpi_runtime.Data.Global_symbols.and_s->{twithit=App(n,smart_map(remove_top_sigmas~types)xs)}|Impl(x,l,t1,t2)->{twithit=Impl(x,l,t1,remove_top_sigmas~typest2)}|App({scope=s},[{it=Lam(Some{name=vn;ty=vty;loc=vloc},_,{loc;ty});}asb])whenis_symbol~typesElpi_runtime.Data.Global_symbols.sigmas->letvn_fresh=F.from_string@@Printf.sprintf"%s_%d"(F.showvn)!freshinincrfresh;remove_top_sigmas~types{loc;ty;it=ScopedTerm.betab[{ty=vty;loc;it=UVar(mk_uvarvn_fresh~loc:vloc~ty:vty,[])}]}|_->tletspill~type_abbrevs~typest=letargs=ref0in(* Format.eprintf "before spill: %a\n" pretty t; *)lets,t=spill~type_abbrevs~typesargstin(* Format.eprintf "after spill: %a\n" pp (List.hd t); *)lett=List.map(remove_top_sigmas~types)tin(* Format.eprintf "after sigma removal: %a\n" pretty (List.hd t); *)(s,t)letmain~type_abbrevs~typest=(* if needs_spilling then Format.eprintf "before %a\n" pretty t; *)letspills,ts=spill~type_abbrevs~types(bc_loc[]t)inlett=match(spills,ts)with|[],[t]->t|[],_->assertfalse|_::_,_->error~loc:t.loc"Cannot place spilled expression"int