12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538(* elpi: embedded lambda prolog interpreter *)(* license: GNU Lesser General Public License Version 2.1 or later *)(* ------------------------------------------------------------------------- *)openElpi_utilopenElpi_parsermoduleFmt=FormatmoduleF=Ast.FuncopenUtilopenData(* Internal notion of constraint *)typeconstraint_def={cdepth:int;prog:prolog_prog[@equalfun__->true][@printer(funfmt_->Fmt.fprintffmt"<prolog_prog>")];context:clause_srclist;conclusion:term;cgid:UUID.t[@trace];}type'unification_defstuck_goal_kind+=|Constraintofconstraint_defletget_suspended_goalblockers=function|Constraint{cdepth;conclusion;context;_}->Some{context;goal=(cdepth,conclusion);blockers}|_->None(* Constants *)moduleC:sigtypet=Constants.tmoduleMap=Constants.MapmoduleSet=Constants.Setvalshow:?table:symbol_table->t->stringvalpp:?table:symbol_table->Fmt.formatter->t->unitvalmkConst:constant->termvalmkAppL:constant->termlist->termvalfresh_global_constant:unit->constant*term(* mkinterval d n 0 = [d; ...; d+n-1] *)valmkinterval:int->int->int->termlistvaldummy:termvaltable:symbol_tableFork.local_refend=structtypet=Constants.tletdummy=Data.dummylettable=Fork.new_local{c2s=Constants.Map.empty;c2t=Hashtbl.create37;frozen_constants=0;}(* let () = at_exit (fun () -> let open Hashtbl in let s = stats !table.c2t in
Array.iter (fun i -> Printf.eprintf "%d\n" i) s.bucket_histogram) *)letshow?(table=!table)n=try(Constants.Map.findnGlobal_symbols.table.c2s)|>Symbol.get_strwithNot_found->tryConstants.Map.findntable.c2s|>Symbol.get_strwithNot_found->ifn>=0then"c"^string_of_intnelse"SYMBOL"^string_of_intnletpp?tablefmtn=Format.fprintffmt"%s"(show?tablen)letmkConstx=tryHashtbl.find!table.c2txwithNot_found->letxx=ConstxinHashtbl.add!table.c2txxx;xx[@@inline]letfresh_global_constant()=!table.frozen_constants<-!table.frozen_constants-1;letn=!table.frozen_constantsinletxx=Constnin!table.c2s<-Constants.Map.addn(Symbol.make(File(Loc.initial"(chr)"))(F.from_string@@"frozen-"^string_of_intn))!table.c2s;Hashtbl.add!table.c2tnxx;n,xxmoduleMap=Constants.MapmoduleSet=Constants.Set(* - negative constants are global names
- constants are hashconsed (terms)
- we use special constants to represent !, pi, sigma *)(* mkinterval d n 0 = [d; ...; d+n-1] *)letrecmkintervaldepthargsnon=ifn=argsnothen[]elsemkConst(n+depth)::mkintervaldepthargsno(n+1);;letmkAppLc=function|[]->mkConstc|x::xs->mkAppcxxs[@@inline]endletmkConst=C.mkConst(* Dereferencing an UVar(r,args) when !!r != dummy requires a function
of this kind. The pretty printer needs one but will only be defined
later, since we need, for example, beta reduction to implement it *)type'argsderef_uv_fun=?oc:occur_check->to_:int->uvar->'args->termtype'argsderef_arg_fun=?oc:occur_check->from:int->to_:int->term->'args->termmodulePp:sig(* Low level printing *)valppterm:?pp_ctx:pp_ctx->?min_prec:int->(*depth:*)int->(*names:*)stringlist->argsdepth:int->env->Fmt.formatter->term->unit(* For user consumption *)valuppterm:?pp_ctx:pp_ctx->?min_prec:int->(*depth:*)int->(*names:*)stringlist->argsdepth:int->env->Fmt.formatter->term->unit(* To be assigned later, used to dereference an UVar/AppUVar *)valdo_uv_deref:intderef_uv_funrefvaldo_appuv_deref:termlistderef_uv_funrefvaldo_arg_deref:intderef_arg_funrefvaldo_apparg_deref:termlistderef_arg_funref(* To put it in the solution *)valuv_names:(stringIntMap.t*int)Fork.local_refvalpp_oref:?pp_ctx:pp_ctx->Format.formatter->(Util.UUID.t*Obj.t)->unitvalpp_constant:?pp_ctx:pp_ctx->Format.formatter->constant->unitend=struct(* {{{ *)letdo_uv_deref=ref(fun?oc~to___->assertfalse);;letdo_appuv_deref=ref(fun?oc~to___->assertfalse);;letdo_arg_deref=ref(fun?oc~from~to___->assertfalse);;letdo_apparg_deref=ref(fun?oc~from~to___->assertfalse);;letuv_names=Fork.new_local(IntMap.empty,0)letmin_prec=Elpi_parser.Parser_config.min_precedenceletappl_prec=Elpi_parser.Parser_config.appl_precedenceletlam_prec=Elpi_parser.Parser_config.lam_precedenceletinf_prec=Elpi_parser.Parser_config.inf_precedenceletxppterm~nice?(pp_ctx={Data.uv_names;table=!C.table})?(min_prec=min_prec)depth0names~argsdepthenvft=letpp_appfpphdpparg?pplastarg(hd,args)=ifargs=[]thenpphdfhdelseFmt.fprintff"@[<hov 1>%a@ %a@]"pphdhd(pplistpparg?pplastelem:pplastarg" ")argsinletppconstantfc=Fmt.fprintff"%s"(C.show~table:pp_ctx.tablec)in(* let ppconstant f c = Fmt.fprintf f "%s/%d" (C.show ~table:pp_ctx.table c) c in *)letppbuiltinfb=Fmt.fprintff"%s"@@show_builtin_predicate~table:pp_ctx.tableC.showbinletstring_of_uvar_bodyr=(* Use this to have stable names: "X" ^ string_of_int (uvar_id r) in *)tryIntMap.find(uvar_idr)(fst!(pp_ctx.uv_names))withNot_found->letm,n=!(pp_ctx.uv_names)inlets="X"^string_of_intninletn=n+1inletm=IntMap.add(uvar_idr)sminpp_ctx.uv_names:=(m,n);sinletrecpp_uvarprecdepthvardepthargsfr=(* for printing purposes it could be that vardepth != r.vardepth *)if!!r==C.dummythenbeginlets=string_of_uvar_bodyrinFmt.fprintff"%s%s%s"s(ifvardepth=0then""else"^"^string_of_intvardepth)(ifargs=0then""else"+"^string_of_intargs)endelseifnicethenbeginauxprecdepthf(!do_uv_deref~to_:depthrargs)endelseFmt.fprintff"<%s|%a>_%d"(string_of_uvar_bodyr)(auxmin_precvardepth)!!rvardepthandpp_argprecdepthfn=letname=tryList.nthnamesnwithFailure_->"A"^string_of_intniniftryenv.(n)==C.dummywithInvalid_argument_->truethenFmt.fprintff"%s"nameelseifnicethenbeginifargsdepth<=depththenletdereffed=!do_arg_deref~from:argsdepth~to_:depthenv.(n)0inauxprecdepthfdereffedelse(* The instantiated Args live at an higher depth, and that's ok.
But if we try to deref we make an imperative mess *)Fmt.fprintff"≪%a≫_%d"(auxmin_precargsdepth)env.(n)argsdepthendelseFmt.fprintff"≪%a≫_%d"(auxmin_precargsdepth)env.(n)argsdepthandwith_parensprec?(test=true)myprech=iftest&&myprec<precthen(Fmt.fprintff"(";h();Fmt.fprintff")")elseh()andpp_mixfix:typea.int->int->_option->int->a->(Format.formatter->a->unit)->_=fundepthcprecprechdlvlppp_pxxs->with_parenscprechdlvl(fun_->letopenElpi_lexer_config.Lexer_configinmatchprecwith|SomeInfix(*when List.length xs = 1*)->letsep=Fmt.asprintf" %a "pp_ppinFmt.fprintff"@[<hov 1>%a@]"(pplist(aux(hdlvl+1)depth)sep)(x::xs)|SomeInfixlwhenList.lengthxs=1->Fmt.fprintff"@[<hov 1>%a@ %a@ %a@]"(auxhdlvldepth)xpp_pp(aux(hdlvl+1)depth)(List.hdxs)|SomeInfixrwhenList.lengthxs=1->Fmt.fprintff"@[<hov 1>%a@ %a@ %a@]"(aux(hdlvl+1)depth)xpp_pp(auxhdlvldepth)(List.hdxs)|SomePrefixwhenxs=[]->Fmt.fprintff"@[<hov 1>%a@ %a@]"pp_pp(auxhdlvldepth)x|SomePostfixwhenxs=[]->Fmt.fprintff"@[<hov 1>%a@ %a@]"(auxhdlvldepth)xpp_pp|_->pp_appfpp_p(auxinf_precdepth)~pplastarg:(aux_lastinf_precdepth)(p,x::xs))(* ::(a, ::(b, nil)) --> [a,b] *)andflat_cons_to_listdepthacct=matchtwithUVar(r,terms)when!!r!=C.dummy->flat_cons_to_listdepthacc(!do_uv_deref~to_:depthrterms)|AppUVar(r,terms)when!!r!=C.dummy->flat_cons_to_listdepthacc(!do_appuv_deref~to_:depthrterms)|Cons(x,y)->flat_cons_to_listdepth(x::acc)y|_->List.revacc,tandis_lambdadepth=functionLam_->true|UVar(r,terms)when!!r!=C.dummy->is_lambdadepth(!do_uv_deref~to_:depthrterms)|AppUVar(r,terms)when!!r!=C.dummy->is_lambdadepth(!do_appuv_deref~to_:depthrterms)|_->falseandaux_lastprecdepthft=ifnicethenbeginmatchtwithLam_->auxmin_precdepthft|UVar(r,terms)when!!r!=C.dummy->aux_lastprecdepthf(!do_uv_deref~to_:depthrterms)|AppUVar(r,terms)when!!r!=C.dummy->aux_lastprecdepthf(!do_appuv_deref~to_:depthrterms)|_->auxprecdepthftendelseauxinf_precdepthftandauxprecdepthft=matchtwith|(Cons_|Nil)->letprefix,last=flat_cons_to_listdepth[]tinFmt.fprintff"[";pplist~boxed:true(auxElpi_parser.Parser_config.comma_precedencedepth)", "fprefix;iflast!=NilthenbeginFmt.fprintff" | ";auxprec1flastend;Fmt.fprintff"]"|Consts->ppconstantfs|App(hd,x,xs)->(tryletpprec,hdlvl=Elpi_parser.Parser_config.precedence_of(C.show~table:pp_ctx.tablehd)inpp_mixfixdepthprecpprechdlvlhdppconstantxxswithNot_found->letlastarg=List.nth(x::xs)(List.lengthxs)inlethdlvl=ifis_lambdadepthlastargthenlam_precelseappl_precinwith_parensprechdlvl(fun_->pp_appfppconstant(auxinf_precdepth)~pplastarg:(aux_lastinf_precdepth)(hd,x::xs)))|Builtin(Eq,[a;b])->let_,hdlvl=Elpi_parser.Parser_config.precedence_of(F.showF.eqf)inwith_parensprechdlvl(fun_->Fmt.fprintff"@[<hov 1>%a@ %a@ %a@]"(aux(hdlvl+1)depth)aF.ppF.eqf(aux(hdlvl+1)depth)b)|Builtin(Pi,[body])->let_,hdlvl=Elpi_parser.Parser_config.precedence_of(F.showF.pif)inwith_parensprechdlvl(fun_->Fmt.fprintff"@[<hov 1>%a"F.ppF.pif;letrecpp_pisdeptht=Fmt.fprintff"@ %a"(auxinf_precdepth)(mkConstdepth);matchtwith|Lam(Builtin(Pi,[body]))->pp_pis(depth+1)body|Lamt->Fmt.fprintff"@ \\@ %a@]"(auxmin_prec(depth+1))t|_->assertfalseinpp_pisdepthbody)|Builtin(b,[])->Fmt.fprintff"%a"ppbuiltinb|Builtin(b,x::xs)->(tryletpprec,hdlvl=ifb==AndthenSomeElpi_lexer_config.Lexer_config.Infix,Elpi_parser.Parser_config.comma_precedenceelselethd=func_of_builtin_predicate(funx->C.show~table:pp_ctx.tablex|>F.from_string)binElpi_parser.Parser_config.precedence_of(F.showhd)inpp_mixfixdepthprecpprechdlvlbppbuiltinxxswithNot_found->letlastarg=List.nth(x::xs)(List.lengthxs)inlethdlvl=ifis_lambdadepthlastargthenlam_precelseappl_precinwith_parensprechdlvl(fun_->pp_appfppbuiltin(auxinf_precdepth)~pplastarg:(aux_lastinf_precdepth)(b,x::xs)))|UVar(r,argsno)whennotnice->letargs=List.mapdestConst(C.mkintervalr.vardepthargsno0)inwith_parensprec~test:(args<>[])appl_prec(fun_->Fmt.fprintff".";pp_appf(pp_uvarinf_precdepthr.vardepth0)ppconstant(r,args))|UVar(r,argsno)when!!r==C.dummy->letdiff=r.vardepth-depth0inletdiff=ifdiff>=0thendiffelse0inletvardepth=r.vardepth-diffinletargsno=argsno+diffinletargs=List.mapdestConst(C.mkintervalvardepthargsno0)inwith_parensprec~test:(args<>[])appl_prec(fun_->pp_appf(pp_uvarinf_precdepthvardepth0)ppconstant(r,args))|UVar(r,argsno)->pp_uvarprecdepthr.vardepthargsnofr|AppUVar(r,terms)when!!r!=C.dummy&&nice->auxprecdepthf(!do_appuv_deref~to_:depthrterms)|AppUVar(r,terms)->with_parensprecappl_prec(fun_->pp_appf(pp_uvarinf_precdepthr.vardepth0)(auxinf_precdepth)~pplastarg:(aux_lastinf_precdepth)(r,terms))|Arg(n,argsno)->letargs=List.mapdestConst(C.mkintervalargsdepthargsno0)inwith_parensprec~test:(args<>[])appl_prec(fun_->pp_appf(pp_argprecdepth)ppconstant(n,args))|AppArg(v,terms)->with_parensprecappl_prec(fun_->pp_appf(pp_arginf_precdepth)(auxinf_precdepth)~pplastarg:(aux_lastinf_precdepth)(v,terms))|Lamt->with_parenspreclam_prec(fun_->letc=mkConstdepthinFmt.fprintff"%a \\@ %a"(auxinf_precdepth)c(auxmin_prec(depth+1))t)|CDatad->CData.ppfd|Discard->Fmt.fprintff"_"intryauxmin_precdepth0ftwithe->Fmt.fprintff"EXN PRINTING: %s"(Printexc.to_stringe);;letppterm=xppterm~nice:falseletuppterm=xppterm~nice:trueletpp_oref?pp_ctxfmt(id,t)=ifnot(UUID.equalidid_term)thenanomaly"pp_oref"elselett:term=Obj.objtinift==C.dummythenFmt.fprintffmt"_"elseuppterm?pp_ctx0[]~argsdepth:0empty_envfmttletpp_constant?pp_ctxfmtc=lettable=matchpp_ctxwith|None->None|Some{table}->SometableinC.pp?tablefmtcend(* }}} *)openPpletrid,max_runtime_id=Fork.new_local0,ref0(******************************************************************************
Stores for:
- backtracking (trail)
- constraints (delayed goals)
- constraint handling rules (propagation rules)
Note: propagation code for CHR rules is later
******************************************************************************)(* Together to hide low level APIs of ConstraintStore needed by Trail *)moduleConstraintStoreAndTrail:sigtypepropagation_item={cstr:constraint_def;cstr_blockers:uvarlist;}valnew_delayed:propagation_itemlistFork.local_refvalto_resume:stuck_goallistFork.local_refvalblockers_map:stuck_goallistIntMap.tFork.local_refvalblocked_by:uvar->stuck_goallistvaldeclare_new:stuck_goal->unitvalremove_old:stuck_goal->unitvalremove_old_constraint:constraint_def->unitvalcontents:?overlapping:uvarlist->unit->(constraint_def*blockers)list(* val print : ?pp_ctx:pp_ctx -> Fmt.formatter -> (constraint_def * blockers) list -> unit *)valprint1:?pp_ctx:pp_ctx->Fmt.formatter->constraint_def*blockers->unit[@@warning"-32"]valprint_gid:Fmt.formatter->constraint_def*blockers->unit[@@warning"-32"]valpp_stuck_goal:?pp_ctx:pp_ctx->Fmt.formatter->stuck_goal->unitvalstate:State.tFork.local_refvalinitial_state:State.tFork.local_ref(* ---------------------------------------------------- *)typetrailvalempty:trailvalinitial_trail:trailFork.local_refvaltrail:trailFork.local_refvalcut_trail:unit->unit(* If true, no need to trail an imperative action. Not part of trial_this
* because you can save allocations and a function call by testing locally *)vallast_call:boolref(* add an item to the trail *)valtrail_assignment:uvar->unit(* backtrack *)valundo:old_trail:trail->?old_state:State.t->unit->unitvalprint_trail:Fmt.formatter->unit[@@warning"-32"](* ---------------------------------------------------- *)(* This is only used to know if the program execution is really over,
I.e. to implement the last component of the runtime data type *)moduleUgly:sigvaldelayed:stuck_goallistrefendend=struct(* {{{ *)typepropagation_item={cstr:constraint_def;cstr_blockers:uvarlist;}letstate=Fork.new_localState.dummyletinitial_state=Fork.new_localState.dummytypetrail_item=|Assignementofuvar|StuckGoalAdditionofstuck_goal|StuckGoalRemovalofstuck_goal[@@derivingshow]typetrail=trail_itemlist[@@derivingshow]letempty=[]lettrail=Fork.new_local[]letinitial_trail=Fork.new_local[]letlast_call=Fork.new_localfalse;;letcut_trail()=trail:=!initial_trail[@@inline];;letblockers_map=Fork.new_local(IntMap.empty:stuck_goallistIntMap.t)letblocked_byr=IntMap.find(uvar_idr)!blockers_mapmoduleUgly=structletdelayed:stuck_goallistref=Fork.new_local[]endopenUglyletcontents?overlapping()=letoverlap:uvarlist->bool=matchoverlappingwith|None->fun_->true|Somel->funb->List.exists(funx->List.memqxl)binmap_filter(function|{kind=Constraintc;blockers}whenoverlapblockers->Some(c,blockers)|_->None)!delayedlettrail_assignmentx=[%spy"dev:trail:assign"~ridFmt.pp_print_bool!last_callpp_trail_item(Assignementx)];ifnot!last_callthentrail:=Assignementx::!trail[@@inline];;lettrail_stuck_goal_additionx=[%spy"dev:trail:add-constraint"~ridFmt.pp_print_bool!last_callpp_trail_item(StuckGoalAdditionx)];ifnot!last_callthentrail:=StuckGoalAdditionx::!trail[@@inline];;lettrail_stuck_goal_removalx=[%spy"dev:trail:remove-constraint"~ridFmt.pp_print_bool!last_callpp_trail_item(StuckGoalRemovalx)];ifnot!last_callthentrail:=StuckGoalRemovalx::!trail[@@inline];;letappend_blockedblockedmapr=letblocker=uvar_idrintryletold=IntMap.findblockermapin(*assert(b.uid <= 0);*)IntMap.addblocker(blocked::old)mapwithNot_found->uvar_set_blockerr;IntMap.addblocker(blocked::[])mapletremove_blockedblockedmapr=letblocker=uvar_idrin(*try*)letold=IntMap.findblockermapin(*assert(b.uid <= 0);*)letl=remove_from_listblockedoldinifl=[]thenbeginuvar_unset_blockerr;IntMap.removeblockermapendelseIntMap.addblockerlmap(*with Not_found ->
assert(b.uid >= 0);
map*)letremove({blockers}assg:stuck_goal)=[%spy"dev:constraint:remove"~ridpp_stuck_goalsg];delayed:=remove_from_listsg!delayed;blockers_map:=List.fold_left(remove_blockedsg)!blockers_mapblockersletadd({blockers}assg:stuck_goal)=[%spy"dev:constraint:add"~ridpp_stuck_goalsg];delayed:=sg::!delayed;blockers_map:=List.fold_left(append_blockedsg)!blockers_mapblockersletnew_delayed=Fork.new_local[]letto_resume=Fork.new_local[]letprint_trailfmt=pp_trailfmt!trail;Fmt.fprintffmt"to_resume:%d new_delayed:%d\n%!"(List.length!to_resume)(List.length!new_delayed)letdeclare_new(sg:stuck_goal)=letblockers=uniqqsg.blockersinletsg={sgwithblockers}inaddsg;beginmatchsg.kindwith|Unification_->()|Constraintcstr->new_delayed:={cstr;cstr_blockers=sg.blockers}::!new_delayed|_->assertfalseend;(trail_stuck_goal_addition[@inlined])sgletremove_cstr_if_existsxl=letrecauxacc=function|[]->l|{cstr=y}::tlwhenx==y->List.revacc@tl|y::tl->aux(y::acc)tlinaux[]lletremove_oldcstr=removecstr;beginmatchcstr.kindwith|Unification_->()|Constraintc->new_delayed:=remove_cstr_if_existsc!new_delayed|_->assertfalseend;(trail_stuck_goal_removal[@inlined])cstr;;letremove_old_constraintcd=letc=List.find(function{kind=Constraintx}->x==cd|_->false)!delayedinremove_oldcletundo~old_trail?old_state()=(* Invariant: to_resume and new_delayed are always empty when a choice
point is created. This invariant is likely to break in the future,
when we allow more interesting constraints and constraint propagation
rules. *)to_resume:=[];new_delayed:=[];[%spy"dev:trail:undo"~ridpp_trail!trailpp_string"->"pp_trailold_trail];while!trail!=old_traildomatch!trailwith|Assignementr::rest->r.contents<-C.dummy;trail:=rest|StuckGoalAdditionsg::rest->removesg;trail:=rest|StuckGoalRemovalsg::rest->addsg;trail:=rest|[]->anomaly"undo to unknown trail"done;matchold_statewith|Someold_state->state:=old_state|None->();;letprint1?pp_ctxfmtx=letpp_depthfmtd=ifd>0thenFmt.fprintffmt"{%a} :@ "(pplist(uppterm?pp_ctxd[]~argsdepth:0empty_env)" ")(C.mkinterval0d0)inletpp_hypsfmtctx=ifctx<>[]thenFmt.fprintffmt"@[<hov 2>%a@]@ ?- "(pplist(funfmt{hdepth=d;hsrc=t}->uppterm?pp_ctxd[]~argsdepth:0empty_envfmtt)", ")ctxinletpp_goaldepth=uppterm?pp_ctxdepth[]~argsdepth:0empty_envinlet{cdepth=depth;context=pdiff;conclusion=g},blockers=xinFmt.fprintffmt" @[<h>@[<hov 2>%a%a%a@]@ /* suspended on %a */@]"pp_depthdepthpp_hypspdiff(pp_goaldepth)g(pplist(uppterm?pp_ctx0[]~argsdepth:0empty_env)", ")(List.map(funr->UVar(r,0))blockers)letprint_gidfmtx=let{cgid=gid[@trace];cdepth=_},_=xinlet()[@trace]=Fmt.fprintffmt"%a"UUID.ppgidin()letprint?pp_ctxfmtx=pplist(print1?pp_ctx)" "fmtxletpp_stuck_goal?pp_ctxfmt{kind;blockers}=matchkindwith|Unification{adepth=ad;env=e;bdepth=bd;a;b}->Fmt.fprintffmt" @[<h>@[<hov 2>^%d:%a@ == ^%d:%a@]@ /* suspended on %a */@]"ad(uppterm?pp_ctxad[]~argsdepth:0empty_env)abd(uppterm?pp_ctxad[]~argsdepth:ade)b(pplist~boxed:false(uppterm?pp_ctx0[]~argsdepth:0empty_env)", ")(List.map(funr->UVar(r,0))blockers)|Constraintc->print?pp_ctxfmt[c,blockers]|_->assertfalseend(* }}} *)moduleT=ConstraintStoreAndTrailmoduleCS=ConstraintStoreAndTrail(* Assigning an UVar wakes up suspended goals/constraints *)let(@:=)rv=(T.trail_assignment[@inlined])r;ifuvar_is_a_blockerrthenbeginletblocked=CS.blocked_byrin[%spy"user:assign:resume"~rid(funfmtl->letl=map_filter(function|{kind=Constraint{cgid;_};_}->Somecgid|_->None)linFmt.fprintffmt"%a"(pplist~boxed:trueUUID.pp" ")l)blocked];CS.to_resume:=List.fold_right(funxacc->ifList.memqxaccthenaccelsex::acc)blocked!CS.to_resumeend;r.contents<-v;;(* Low level, trail but no wakeup, used in freeze *)let(@::==)rv=(T.trail_assignment[@inlined])r;r.contents<-v(******************************************************************************
Unification (dereferencing and lift, to_heap)
******************************************************************************)moduleHO:sigvalunif:oc:bool->argsdepth:int->matching:bool->(UUID.t[@trace])->int->env->int->term->term->bool(* lift/restriction/heapification with occur_check *)valmove:argsdepth:int->env->?oc:occur_check->from:int->to_:int->term->term(* like move but for heap terms (no heapification) *)valhmove:?oc:occur_check->from:int->to_:int->term->term(* simultaneous substitution *)valsubst:int->termlist->term->termvalderef_uv:intderef_uv_funvalderef_appuv:termlistderef_uv_funvalderef_arg:intderef_arg_funvalderef_apparg:termlistderef_arg_funvalmkAppUVar:uvar->termlist->termvalmkAppArg:int->int->termlist->termvalis_flex:depth:int->term->uvaroptionvallist_to_lp_list:termlist->termvalfull_deref:adepth:int->env->depth:int->term->term(* freshens all uvars (unless keep_if_outside), discards blocker status *)valcopy_heap_drop_csts:depth:int->?keep_if_outside:uvarIntMap.t->term->term*uvarIntMap.t(* Head of an heap term *)valderef_head:depth:int->term->termvaleta_contract_flex:depth:int->term->termoption(* Put a flexible term in canonical expanded form: X^0 args.
* It returns the canonical term and an assignment if needed.
* (The first term is the result of dereferencing after the assignment) *)typeassignment=uvar*termvalexpand_uv:depth:int->uvar->ano:int->term*assignmentoptionvalexpand_appuv:depth:int->uvar->args:termlist->term*assignmentoptionvalshift_bound_vars:depth:int->to_:int->term->termvalmap_free_vars:map:constantC.Map.t->depth:int->to_:int->term->termvaldelay_hard_unif_problems:boolFork.local_refend=struct(* {{{ *)(* {{{ ************** move/hmove/deref_* ******************** *)exceptionNotInTheFragment(* in_fragment n [n;...;n+m-1] = m
it must be called either on heap terms or on stack terms whose Args are
non instantiated *)letrecin_fragmentexpected=function[]->0|Constc::tlwhenc=expected->1+in_fragment(expected+1)tl|UVar({contents=t},_)::tl->(* XXX *)in_fragmentexpected(t::tl)(* Invariant not true anymore, since we may not deref aggressively
to avoid occur-check
| UVar (r,_,_)::_
| AppUVar (r,_,_)::_ when !!r != C.dummy ->
anomaly "non dereferenced terms in in_fragment"
*)|_->raiseNotInTheFragmentexceptionNonMetaClosedletdeterministic_restrictione~args_safet=letrecaux=functionLamf->auxf|App(_,t,l)->auxt;List.iterauxl|Cons(x,xs)->auxx;auxxs|Builtin(_,l)->List.iterauxl|UVar(r,_)|AppUVar(r,_)when!!r==C.dummy->raiseNonMetaClosed|UVar(r,_)->aux!!r|AppUVar(r,l)->aux!!r;List.iterauxl|Arg(i,_)whene.(i)==C.dummy&¬args_safe->raiseNonMetaClosed|AppArg(i,_)whene.(i)==C.dummy->raiseNonMetaClosed|Arg(i,_)->ife.(i)!=C.dummythenauxe.(i)|AppArg(i,l)->auxe.(i);List.iterauxl|Const_|Nil|Discard|CData_->()intryauxt;truewithNonMetaClosed->falseexceptionRestrictionFailureletoccurr_checkr1r2=matchr1with|No|Skip->()|Checkr1->(* It may be the case that in `X = Y` where `Y = f X` the term Y has to be
moved/derefd in two steps, eg:
else maux empty_env depth (deref_uv ~from:vardepth ~to_:(from+depth) args t)
here maux carries the r1 = X (the ?oc), while deref_uv does not, to avoid
occur checking things twice. But deref_uv, if Y contains X, may assign
X' to X (or x..\ X' x.. t oX). If this happens, then r1 is no more a dummy
(unassigned variable) *)if!!r1!=C.dummy||r1==r2thenraiseRestrictionFailureletrecmake_lambdasdestdepthargs=ifargs<=0thenUVar(oref~depth:destdepthC.dummy,0)elseLam(make_lambdas(destdepth+1)(args-1))letrecmknLamnx=ifn=0thenxelseLam(mknLam(n-1)x)letmkAppUVarrl=tryUVar(r,in_fragmentr.vardepthl)withNotInTheFragment->AppUVar(r,l)letmkAppArgifromdepthxxs'=tryArg(i,in_fragmentfromdepthxxs')withNotInTheFragment->AppArg(i,xxs')letexpand_uv(r:uvar)~ano=letlvl=r.vardepthinletargs=C.mkinterval0(lvl+ano)0iniflvl=0thenAppUVar(r,args),Noneelseletr1=oref~depth:0C.dummyinlett=AppUVar(r1,args)inletassignment=mknLamanotint,Some(r,assignment)letexpand_uv~depth(r:uvar)~ano=[%spy"dev:expand_uv:in"~rid(upptermdepth[]~argsdepth:0empty_env)(UVar(r,ano))];lett,assasrc=expand_uvr~anoin[%spy"dev:expand_uv:out"~rid(upptermdepth[]~argsdepth:0empty_env)t(funfmt->function|None->Fmt.fprintffmt"no assignment"|Some(_,t)->Fmt.fprintffmt"%a := %a"(upptermdepth[]~argsdepth:0empty_env)(UVar(r,ano))(upptermr.vardepth[]~argsdepth:0empty_env)t)ass];rcletexpand_appuv(r:uvar)~args=letlvl=r.vardepthiniflvl=0thenAppUVar(r,args),Noneelseletargs_lvl=C.mkinterval0lvl0inletr1=oref~depth:0C.dummyinlett=AppUVar(r1,args_lvl@args)inletnargs=List.lengthargsinletassignment=mknLamnargs(AppUVar(r1,args_lvl@C.mkintervallvlnargs0))int,Some(r,assignment)letexpand_appuv~depth(r:uvar)~args=[%spy"dev:expand_appuv:in"~rid(upptermdepth[]~argsdepth:0empty_env)(AppUVar(r,args))];lett,assasrc=expand_appuvr~argsin[%spy"dev:expand_appuv:out"~rid(upptermdepth[]~argsdepth:0empty_env)t(funfmt->function|None->Fmt.fprintffmt"no assignment"|Some(_,t)->Fmt.fprintffmt"%a := %a"(upptermdepth[]~argsdepth:0empty_env)(AppUVar(r,args))(upptermr.vardepth[]~argsdepth:0empty_env)t)ass];rcletdeoptimize_uv_w_args=function|UVar(r,args)whenargs>0->AppUVar(r,C.mkintervalr.vardepthargs0)|x->x(* move performs at once:
1) refreshing of the arguments into variables (heapifycation)
2) restriction/occur-check
hmove is the variant that only does 2
when from = to, i.e. delta = 0:
(-infty,+infty) -> (-infty,+infty)
when from < to, i.e. delta < 0:
(-infty,from) -> (-infty,from) free variables
[from,+infty) -> [to,+infty) bound variables
when from > to, i.e. delta > 0:
(-infty,to) -> (-infty,to) free variables
[to,from) -> error free restricted variables
[from,+infty) -> [to,+infty) bound variables
Invariant:
when from=to, to_heap is to be called only for terms that are not in the
heap
Notes:
- remember that the depth of a stack term is the depth when the clause
entered the program, whereas the argsdepth of the variables is the depth
when the clause is used. Therefore it is normal to have arguments,
possibly instantiated, whose depth is greater than the surrounding term.
Calling to_heap on them with the wrong depth (e.g. the depth of the
surrounding term) can therefore trigger restrictions that are meaningless.
- it is possible for delta to be >0 (restriction) and the second term
be a stack term. Therefore sometimes restrictions of heap terms are
meaningful. Example:
p A.
|- pi x \ p X
The unification problem becomes X^0 1^=^0 A^1 that triggers the
assignment X^0 := to_heap ~from:1 ~to_:0 A^1
- On the other hand *I think* that it is not possible to have
argsdepth < to_ in to_heap.
It would mean that I am doing an assignment
X^to_ := ... A^argsdepth....
that is triggered by an unification problem
.... X^to_ .... == .... A^argsdepth ....
that is triggered by calling a clause at depth argsdepth with a formal
parameter containing an UVar whose depth is higher than the current depth
of the program. How could such a variable enters the formal parameters
without being restricted earlier?
Therefore, in the case of heap terms, the invariant is
from <= depthargs <= to_
the first inequality because a clause always enter a program at a depth
(from) smaller than when it is used (depthargs).
*)(* [move ~from ~to ?oc t] relocates a term t by amount (= to - from).
In the diagrams below, c is a constant, l is locally bound variable
(i.e. bound after from). The resulting term lives in the heap and avoid,
if passed, is occur checked.
- If amount is > 0 then Const nodes >= from are lifted by amount
c1 ---> c1
c2 from ---> c2
l3 - to
l4 -`-> l4
`-> l5
- If amount is < 0 then Const nodes between to and from are ensured not
to occur in the result, otherwise RestrictionFailure is raised.
Const nodes >= from are de-lifted by amount
c1 ---> c1 to c1 ---> c1 to
c2 from ---> Error from ,-> l2
l3 l3 -,-> l3
l4 l4 -
* Property: move ~to ~from (move ~from ~to t) = t
- if from <= to
- if to > from and no Const >= to and < from occurs in t
where occurs also means in the scope of an Uv
* Args:
- when defined in e the corresponding term lives in adepth
- when undefined they are turned into Uv (heapification)
* Uv occur check is performed only if avoid is passed
* Deref under binders:
from:2 to_:4
G |- 3\ X^1 3 X := 2\f 1 2
phase 1
G |- 3\ (4\f 1 4) 3
G |- 3\ f 1 3
phase 2 (the lambda is anonymous, so 3\ is like 5\)
G |- 5\ f 1 5
*)(* let rec no_discard = function
| Discard -> false
| Const _ -> true
| Nil -> true
| Lam x -> no_discard x
| App(_,x,xs) -> no_discard x && List.for_all no_discard xs
| Cons(x,y) -> no_discard x && no_discard y
| Arg _ | AppArg _ -> false
| UVar _ | AppUVar _ -> true
| CData _ -> true
| Builtin(_,xs) -> List.for_all no_discard xs *)letrecmove~argsdepth(e:env)?(oc=No)~from~to_t=(* TODO: to disable occur_check add something like: let avoid = None in *)letdelta=from-to_inletrc=ifdelta=0&&e==empty_env&&(oc==No||(oc==Skip))thenbegin(* statically checked: *)(* assert(no_discard t); *)t(* Nothing to do! *)endelsebegin(*if delta = 0 && e == empty_env && avoid <> None then prerr_endline "# EXPENSIVE OCCUR CHECK";*)letrecmauxedepthx=[%trace"move"~rid("adepth:%d depth:%d from:%d to:%d x:%a"argsdepthdepthfromto_(ppterm(from+depth)[]~argsdepthe)x)beginmatchxwith|Constc->ifdelta==0thenxelse(* optimization *)ifc>=fromthenmkConst(c-delta)else(* locally bound *)ifc<to_thenxelse(* constant *)raiseRestrictionFailure|Lamf->letf'=mauxe(depth+1)finiff==f'thenxelseLamf'|App(c,t,l)whendelta==0||c<from&&c<to_->lett'=mauxedepthtinletl'=smart_map3mauxedepthlinift==t'&&l==l'thenxelseApp(c,t',l')|App(c,t,l)whenc>=from->App(c-delta,mauxedeptht,smart_map3mauxedepthl)|App_->raiseRestrictionFailure|Builtin(c,l)->letl'=smart_map3mauxedepthlinifl==l'thenxelseBuiltin(c,l')|CData_->x|Cons(hd,tl)->lethd'=mauxedepthhdinlettl'=mauxedepthtlinifhd==hd'&&tl==tl'thenxelseCons(hd',tl')|Nil->x|Discardwhenoc==No->x|Discard->letr=oref~depth:to_C.dummyinUVar(r,0)(* fast path with no deref... *)|UVar_whendelta==0&&(oc==No||oc==Skip)->x(* deref *)|UVar({contents=t}asr,args)whent!=C.dummy->ifdepth==0thenderef_uv~oc~to_rargselsemauxempty_envdepth(deref_uv~to_:(from+depth)rargs)|AppUVar({contents=t}asr,args)whent!=C.dummy->(* wrong, args escape occur check: if depth == 0 then deref_appuv ?oc ~from:vardepth ~to_ args t
else *)mauxempty_envdepth(deref_appuv~to_:(from+depth)rargs)|Arg(i,argsno)whene.(i)!=C.dummy->ifto_=argsdepththenderef_arg~oc~from:argsdepth~to_:(to_+depth)e.(i)argsnoelseletargs=C.mkintervalfromargsno0inletargs=trysmart_map3mauxedepthargswithRestrictionFailure->anomaly"move: could check if unrestrictable args are unused"inderef_apparg~oc~from:argsdepth~to_:(to_+depth)e.(i)args|AppArg(i,args)whene.(i)!=C.dummy->letargs=trysmart_map3mauxedepthargswithRestrictionFailure->anomaly"move: could check if unrestrictable args are unused"inderef_apparg~oc~from:argsdepth~to_:(to_+depth)e.(i)args(* heapification/restriction of Arg and AppArg *)|Arg(i,args)->letto_=minargsdepthto_inletr=oref~depth:to_C.dummyinletv=UVar(r,0)ine.(i)<-v;ifargs==0thenvelseUVar(r,args)|AppArg(i,args)whenList.for_all(deterministic_restrictione~args_safe:(argsdepth=to_))args->letto_=minargsdepthto_inletargs=trysmart_map(mauxedepth)argswithRestrictionFailure->anomaly"TODO: implement deterministic restriction"inletr=oref~depth:to_C.dummyinletv=UVar(r,0)ine.(i)<-v;mkAppUVarrargs|AppArg_->Fmt.fprintfFmt.str_formatter"Non deterministic pruning, delay to be implemented: t=%a, delta=%d%!"(pptermdepth[]~argsdepthe)xdelta;anomaly(Fmt.flush_str_formatter())(* restriction/lifting of UVar *)|UVar(r,argsno)->letvardepth=r.vardepthinoccurr_checkocr;ifdelta<=0then(* to_ >= from *)ifvardepth+argsno<=fromthenxelseletr,vardepth,argsno=decrease_depthr~from:vardepth~to_:fromargsnoinletargs=C.mkintervalvardepthargsno0inletargs=smart_map(mauxempty_envdepth)argsinmkAppUVarrargselseifvardepth+argsno<=to_thenxelselett,assignment=expand_uv~depth:(from+depth)r~ano:argsnoinoption_iter(fun(r,assignment)->[%spy"user:assign:expand"~rid(funfmt()->Fmt.fprintffmt"%a := %a"(uppterm(from+depth)[]~argsdepthe)x(upptermvardepth[]~argsdepthe)assignment)()];r@:=assignment)assignment;mauxedeptht|AppUVar(r,args)->letvardepth=r.vardepthinoccurr_checkocr;ifdelta<0thenletr,vardepth,argsno=decrease_depthr~from:vardepth~to_:from0inletargs0=C.mkintervalvardepthargsno0inletargs=trysmart_map(mauxedepth)(args0@args)withRestrictionFailure->anomaly"impossible, delta < 0"inmkAppUVarrargselseifdelta==0thenAppUVar(r,smart_map(mauxedepth)args)elseifList.for_all(deterministic_restrictione~args_safe:(argsdepth=to_))argsthen(* Code for deterministic restriction *)letpruned=ref(vardepth>to_)inletorig_argsno=List.lengthargsinletfilteredargs_vardepth=ref[]inletfilteredargs_to=letrecfilteriacc=function|[]->filteredargs_vardepth:=List.revacc;[]|arg::args->tryletarg=mauxedeptharginarg::filter(succi)(mkConst(vardepth+i)::acc)argswithRestrictionFailure->pruned:=true;filter(succi)accargsinfilter0[]argsinif!prunedthenbeginletvardepth'=minvardepthto_inletr'=oref~depth:vardepth'C.dummyinletnewvar=mkAppUVarr'!filteredargs_vardepthinletassignment=mknLamorig_argsnonewvarin[%spy"user:assign:restrict"~rid(funfmt()->Fmt.fprintffmt"%d %a := %a"vardepth(ppterm(from+depth)[]~argsdepthe)x(ppterm(vardepth)[]~argsdepthe)assignment)()];r@:=assignment;mkAppUVarr'filteredargs_toendelsemkAppUVarrfilteredargs_toelsebeginFmt.fprintfFmt.str_formatter"Non deterministic pruning, delay to be implemented: t=%a, delta=%d%!"(pptermdepth[]~argsdepthe)xdelta;anomaly(Fmt.flush_str_formatter())endend]inmauxe0tendin[%spy"dev:move:out"~rid(pptermto_[]~argsdepthe)rc];rc(* Hmove is like move for heap terms. By setting env to empty_env, it triggers
fast paths in move (no need to heapify, the term already lives in the heap)*)andhmove?oc~from~to_t=[%trace"hmove"~rid("@[<hov 1>from:%d@ to:%d@ %a@]"fromto_(upptermfrom[]~argsdepth:0empty_env)t)beginmove?oc~argsdepth:0~from~to_empty_envtend](* UVar(_,from,argsno) -> Uvar(_,to_,argsno+from-to_) *)anddecrease_depthr~from~to_argsno=iffrom<=to_thenr,from,argsnoelseletnewr=oref~depth:to_C.dummyinletnewargsno=argsno+from-to_inletnewvar=UVar(newr,from-to_)inr@:=newvar;newr,to_,newargsno(* simultaneous substitution of ts for [depth,depth+|ts|)
the substituted term must be in the heap
the term is delifted by |ts|
every t in ts must be either an heap term or an Arg(i,0)
the ts are lifted as usual *)andsubstfromdepthtst=[%trace"subst"~rid("@[<hov 2>fromdepth:%d t: %a@ ts: %a@]"fromdepth(uppterm(fromdepth)[]~argsdepth:0empty_env)t(pplist(upptermfromdepth[]~argsdepth:0empty_env)", ")ts)beginifts==[]thentelseletlen=List.lengthtsinletfromdepthlen=fromdepth+leninletrecauxdepthtt=[%trace"subst-aux"~rid("@[<hov 2>t: %a@]"(uppterm(fromdepth+1)[]~argsdepth:0empty_env)tt)beginmatchttwith|Constcasx->ifc>=fromdepth&&c<fromdepthlenthenmatchList.nthts(len-1-(c-fromdepth))with|Arg(i,0)ast->t|t->hmove~from:fromdepth~to_:(depth-len)telseifc<fromdepththenxelsemkConst(c-len)(* NOT LIFTED *)|Arg_|AppArg_->anomaly"subst takes a heap term"|App(c,x,xs)asorig->letx'=auxdepthxinletxs'=smart_map(auxdepth)xsinletxxs'=x'::xs'inifc>=fromdepth&&c<fromdepthlenthenmatchList.nthts(len-1-(c-fromdepth))with|Arg(i,0)->mkAppArgifromdepthxxs'|t->lett=hmove~from:fromdepth~to_:(depth-len)tinbeta(depth-len)[]txxs'elseifc<fromdepththenifx==x'&&xs==xs'thenorigelseApp(c,x',xs')elseApp(c-len,x',xs')|Builtin(c,xs)asorig->letxs'=smart_map(auxdepth)xsinifxs==xs'thenorigelseBuiltin(c,xs')|Cons(hd,tl)asorig->lethd'=auxdepthhdinlettl'=auxdepthtlinifhd==hd'&&tl==tl'thenorigelseCons(hd',tl')|Nil->tt|Discard->tt|UVar({contents=g}asr,argsno)wheng!=C.dummy->[%tcallauxdepth(deref_uv~to_:depthrargsno)]|UVar(r,argsno)asorig->letvardepth=r.vardepthinifvardepth+argsno<=fromdepththenorigelseletr,vardepth,argsno=decrease_depthr~from:vardepth~to_:fromdepthargsnoinletargs=C.mkintervalvardepthargsno0inletargs=smart_map(auxdepth)argsinmkAppUVarrargs|AppUVar({contents=t}asr,args)whent!=C.dummy->[%tcallauxdepth(deref_appuv~to_:depthrargs)]|AppUVar(r,args)->letvardepth=r.vardepthinletr,vardepth,argsno=decrease_depthr~from:vardepth~to_:fromdepth0inletargs0=C.mkintervalvardepthargsno0inletargs=smart_map(auxdepth)(args0@args)inmkAppUVarrargs|Lamt->Lam(aux(depth+1)t)|CData_asx->xend]inauxfromdepthlentend]andbetadepthsubtargs=[%trace"beta"~rid("@[<hov 2>subst@ t: %a@ args: %a@]"(uppterm(depth+List.lengthsub)[]~argsdepth:0empty_env)t(pplist(upptermdepth[]~argsdepth:0empty_env)", ")args)beginmatcht,argswith|UVar({contents=g}asr,argsno),_wheng!=C.dummy->[%tcallbetadepthsub(deref_uv~to_:(depth+List.lengthsub)rargsno)args]|AppUVar({contents=g}asr,uargs),_wheng!=C.dummy->[%tcallbetadepthsub(deref_appuv~to_:(depth+List.lengthsub)ruargs)args]|Lamt',hd::tl->[%tcallbetadepth(hd::sub)t'tl]|_->lett'=substdepthsubtin[%spy"dev:subst:out"~rid(pptermdepth[]~argsdepth:0empty_env)t'];matchargswith|[]->t'|ahd::atl->matcht'with|Constc->App(c,ahd,atl)|Arg_|AppArg_->anomaly"beta takes only heap terms"|App(c,arg,args1)->App(c,arg,args1@args)|Builtin(c,args1)->Builtin(c,args1@args)|UVar(r,m)->beginletn=r.vardepthintryUVar(r,m+in_fragment(n+m)args)withNotInTheFragment->letargs1=C.mkintervalnm0inAppUVar(r,args1@args)end|AppUVar(r,args1)->AppUVar(r,args1@args)|Lam_->anomaly"beta: some args and some lambdas"|CDatax->type_error(Printf.sprintf"beta: '%s'"(CData.showx))|Nil->type_error"beta: Nil"|Cons_->type_error"beta: Cons"|Discard->type_error"beta: Discard"end](* eat_args n [n ; ... ; n+k] (Lam_0 ... (Lam_k t)...) = n+k+1,[],t
eat_args n [n ; ... ; n+k]@l (Lam_0 ... (Lam_k t)...) =
n+k+1,l,t if t != Lam or List.hd l != n+k+1 *)andeat_argsdepthlt=matchtwith|Lamt'whenl>0->eat_args(depth+1)(l-1)t'|UVar({contents=t}asr,args)whent!=C.dummy->eat_argsdepthl(deref_uv~to_:depthrargs)|AppUVar({contents=t}asr,args)whent!=C.dummy->eat_argsdepthl(deref_appuv~to_:depthrargs)|_->depth,l,t(* CSC: The following set of comments are to be revised. I found them scattered
around and they refer to old names. They are also somehow duplicated *)(* Deref is to be called only on heap terms and with from <= to *)(* Deref is to be called only on heap terms and with from <= to
* The args must live in to_.
*)(* deref_uv performs lifting only and with from <= to
if called on non-heap terms, it does not turn them to heap terms
(if from=to_)
Note:
when deref_uv is called inside restrict, it may be from > to_
t lives in from; args already live in to_
*)andderef_uv?oc~to_(r:uvar)(args:int):term=letfrom=r.vardepthinlett=!!rinderef_arg?oc~from~to_targs[@@inline]andderef_appuv?oc~to_rargs=letfrom=r.vardepthinlett=!!rinbetato_[](deref_arg?oc~from~to_t0)args[@@inline]andderef_apparg?oc~from~to_targs=betato_[](deref_arg?oc~from~to_t0)args[@@inline]andderef_arg?oc~from~to_targs=[%trace"deref_uv"~rid("from:%d to:%d %a @@ %d"fromto_(pptermfrom[]~argsdepth:0empty_env)targs)beginifargs==0thenhmove?oc~from~to_telse(* O(1) reduction fragment tested here *)letfrom,args',t=eat_argsfromargstinlett=deref_arg?oc~from~to_t0inifargs'==0thentelsematchtwith|Lam_->anomaly"eat_args went crazy"|Constc->letargs=C.mkinterval(from+1)(args'-1)0inApp(c,mkConstfrom,args)|App(c,arg,args2)->letargs=C.mkintervalfromargs'0inApp(c,arg,args2@args)|Builtin(c,args2)->letargs=C.mkintervalfromargs'0inBuiltin(c,args2@args)(* TODO: when the UVar/Arg is not C.dummy, we call deref_uv that
will call move that will call_deref_uv again. Optimize the
path *)|UVar(r,0)whenfrom=r.vardepth->UVar(r,args')|AppUVar(r,args2)->letargs=C.mkintervalfromargs'0inAppUVar(r,args2@args)|UVar(r,argsno)->letvardepth=r.vardepthinletargs1=C.mkintervalvardepthargsno0inletargs2=C.mkintervalfromargs'0inletargs=args1@args2inmkAppUVarrargs|Cons_|Nil->type_error"deref_uv: applied list"|Discard->type_error"deref_uv: applied Discard"|CData_->t|Arg_|AppArg_->assertfalse(* Uv gets assigned only heap term *)end];;letcopy_heap_drop_csts~depth?keep_if_outsidex=letm:uvarIntMap.tref=matchkeep_if_outsidewith|None->refIntMap.empty|Somem->refminletalloc_copyr=tryIntMap.find(uvar_idr)!mwithNot_found->ifkeep_if_outside<>Nonethenrelseletr'=oref~depth:r.vardepthC.dummyinm:=IntMap.add(uvar_idr)r'!m;r'inletalloc_copyr=letr'=alloc_copyrin(* Format.eprintf " copy uv %a -> %a\n%!" (uppterm depth [] ~argsdepth:0 empty_env) (UVar(r,0,0)) (uppterm depth [] ~argsdepth:0 empty_env) (UVar(r',0,0)); *)r'inletrecmauxdepthx=matchxwith|Const_->x|Lamf->letf'=maux(depth+1)finiff==f'thenxelseLamf'|App(c,t,l)->lett'=mauxdepthtinletl'=smart_map2mauxdepthlinift==t'&&l==l'thenxelseApp(c,t',l')|Builtin(c,l)->letl'=smart_map2mauxdepthlinifl==l'thenxelseBuiltin(c,l')|CData_->x|Cons(hd,tl)->lethd'=mauxdepthhdinlettl'=mauxdepthtlinifhd==hd'&&tl==tl'thenxelseCons(hd',tl')|Nil->x|Discard->letr=oref~depthC.dummyinUVar(r,0)(* deref *)|UVar({contents=t}asr,args)whent!=C.dummy->mauxdepth(deref_uv~to_:depthrargs)|AppUVar({contents=t}asr,args)whent!=C.dummy->mauxdepth(deref_appuv~to_:depthrargs)|Arg_|AppArg_->anomaly"not a heap term"|UVar(r,argsno)->letr'=alloc_copyrinUVar(r',argsno)|AppUVar(r,args)->letr'=alloc_copyrinAppUVar(r',smart_map2mauxdepthargs)inletx'=mauxdepthxin(* Format.eprintf "copy %a -> %a\n%!" (uppterm depth [] ~argsdepth:0 empty_env) x (uppterm depth [] ~argsdepth:0 empty_env) x'; *)x',!m(* }}} *)(* {{{ ************** unification ******************************* *)(* is_flex is to be called only on heap terms *)letrecis_flex~depth=function|Arg_|AppArg_->anomaly"is_flex called on Args"|UVar({contents=t}asr,args)whent!=C.dummy->is_flex~depth(deref_uv~to_:depthrargs)|AppUVar({contents=t}asr,args)whent!=C.dummy->is_flex~depth(deref_appuv~to_:depthrargs)|UVar(r,_)|AppUVar(r,_)->Somer|Const_|Lam_|App_|Builtin_|CData_|Cons_|Nil|Discard->None(* Invariants: |
adepth: depth of a (query, heap term) - bdepth b
bdepth: depth of b (clause hd, stack term in env e) | b-only .
adepth >= bdepth - adepth a = .
| local x\ x\
- a' = b'
Spec:
(-infy,bdepth) = (-infty,bdepth) common free variables
[bdepth,adepth) free variable only visible by one:fail
[adepth,+infty) = [bdepth,+infy) bound variables
Names:
delta = adepth - bdepth i.e. size of forbidden region
heap = ?
Note about dereferencing UVar(r,origdepth,args):
- args live *here* (a/bdepth + depth)
- !!r lives in origdepth
+ we deref_uv to move everything to a/bdepth + depth
Note about dereferencing Arg(i,args):
- args live *here* (bdepth + depth)
- e.(i) lives in bdepth
+ we deref_uv to move everything to adepth + depth
*)(* Tests is args are in the L_\lambda fragment and produces a map from
* constants to int. The idea being that an UVar of level lvl also sees
* all the constants in the map, and the associated int is their position
* in the list of arguments starting from 0 *)letis_llamlvlargsadepthbdepthdepthlefte=letto_=ifleftthenadepth+depthelsebdepth+depthinletget_con=functionConstx->x|_->raiseRestrictionFailureinletderef_to_const=function|UVar({contents=t}asr,args)whent!=C.dummy->get_con(deref_uv~to_rargs)|AppUVar({contents=t}asr,args)whent!=C.dummy->get_con(deref_appuv~to_rargs)|Arg(i,args)whene.(i)!=C.dummy->get_con(deref_arg~from:adepth~to_e.(i)args)|AppArg(i,args)whene.(i)!=C.dummy->get_con(deref_apparg~from:adepth~to_e.(i)args)|Constx->ifnotleft&&x>=bdepththenx+(adepth-bdepth)elsex|_->raiseRestrictionFailureinletrecauxn=function|[]->[]|x::xs->ifx>=lvl&¬(List.memxxs)then(x,n)::aux(n+1)xselseraiseRestrictionFailureintrytrue,aux0(List.mapderef_to_constargs)withRestrictionFailure->false,[]letis_llamlvlargsadepthbdepthdepthlefte=letres=is_llamlvlargsadepthbdepthdepthleftein[%spy"dev:is_llam"~rid(funfmt()->let(b,map)=resinFmt.fprintffmt"%d + %a = %b, %a"lvl(pplist(pptermadepth[]~argsdepth:bdepthe)" ")argsb(pplist(funfmt(x,n)->Fmt.fprintffmt"%d |-> %d"xn)" ")map)()];resletrecmknLamnt=ifn=0thentelsemknLam(n-1)(Lamt)(* [bind r args ... t] generates a term \args.t' to be assigned to r.
* r is the variable being assigned
* gamma is the level of the variable we assigning
* l is its extended domain as a map (see is_llam)
* a is adepth
* b is bdepth
* d is depth (local lamdas traversed during unif
* w is the same but during bind, hence current depth is (d+w)
* delta is (a-b)
* left is true when the variable being assigned is on the left (goal)
* t is the term we are assigning to r
* e is the env for args *)letbind~argsdepthrladdeltableftte=letgamma=r.vardepthinletnew_lams=List.lengthlinletposx=tryList.assocxlwithNot_found->raiseRestrictionFailurein(* hmove = false makes the code insensitive to left/right, i.e. no hmove from b
* to a is performed *)letcst?(hmove=true)cbdelta=(* The complex thing (DBL) *)ifleftthenbeginifc<gamma&&c<bthencelseletc=ifhmove&&c>=bthenc+deltaelsecinifc<gammathencelseifc>=a+dthenc+new_lams-(a+d-gamma)elseposc+gammaendelsebeginifc<gammathencelseifc>=a+dthenc+new_lams-(a+d-gamma)elseposc+gammaendinletcst?hmovecbdelta=letn=cst?hmovecbdeltain[%spy"dev:bind:constant-mapping"~rid(funfmt()->let(n,m)=c,ninFmt.fprintffmt"%d -> %d (c:%d b:%d gamma:%d delta:%d d:%d)"nmcbgammadeltad)()];ninletrecbindbdeltawt=[%trace"bind"~rid("%b gamma:%d + %a = t:%a a:%d delta:%d d:%d w:%d b:%d"leftgamma(pplist(funfmt(x,n)->Fmt.fprintffmt"%a |-> %d"(ppterma[]~argsdepthe)(mkConstx)n)" ")l(ppterma[]~argsdepthempty_env)tadeltadwb)beginmatchtwith|UVar(r1,_)|AppUVar(r1,_)whenr==r1->raiseRestrictionFailure|Constc->letn=cstcbdeltainifn<0thenmkConstnelseConstn|Lamt->Lam(bindbdelta(w+1)t)|App(c,t,ts)->App(cstcbdelta,bindbdeltawt,smart_map(bindbdeltaw)ts)|Cons(hd,tl)->Cons(bindbdeltawhd,bindbdeltawtl)|Nil->t|Builtin(c,tl)->Builtin(c,smart_map(bindbdeltaw)tl)|CData_->t(* deref_uv *)|Arg(i,args)whene.(i)!=C.dummy->binda0w(deref_arg~from:argsdepth~to_:(a+d+w)e.(i)args)|AppArg(i,args)whene.(i)!=C.dummy->binda0w(deref_apparg~from:argsdepth~to_:(a+d+w)e.(i)args)|UVar({contents=t}asr,args)whent!=C.dummy->bindbdeltaw(deref_uv~to_:((ifleftthenbelsea)+d+w)rargs)|AppUVar({contents=t}asr,args)whent!=C.dummy->bindbdeltaw(deref_appuv~to_:((ifleftthenbelsea)+d+w)rargs)(* pruning *)|(UVar_|AppUVar_|Arg_|AppArg_|Discard)asorig->(* We deal with all flexible terms in a uniform way *)letr,(is_llam,args),orig_args=matchorigwith|UVar(r,0)->r,(true,[]),[]|UVar(r,args)->letr'=oref~depth:(r.vardepth+args)C.dummyinletv=UVar(r',0)inr@:=mknLamargsv;r',(true,[]),[]|AppUVar(r,orig_args)->r,is_llamr.vardepthorig_argsab(d+w)lefte,orig_args|Discard->letr=oref~depth:(a+d+w)C.dummyinr,(true,[]),[]|Arg(i,0)->letr=oref~depth:aC.dummyinletv=UVar(r,0)ine.(i)<-v;r,(true,[]),[]|Arg(i,args)->letr=oref~depth:aC.dummyinletv=UVar(r,0)ine.(i)<-v;letr'=oref~depth:(a+args)C.dummyinletv'=UVar(r',0)inr@:=mknLamargsv';r',(true,[]),[]|AppArg(i,orig_args)->letis_llam,args=is_llamaorig_argsab(d+w)falseeinletr=oref~depth:aC.dummyinletv=UVar(r,0)ine.(i)<-v;r,(is_llam,args),orig_args|_->assertfalseinletlvl=r.vardepthin[%spy"dev:bind:maybe-prune"~rid(funfmt()->Fmt.fprintffmt"lvl:%d is_llam:%b args:%a orig_args:%a orig:%a"lvlis_llam(pplist(funfmt(x,n)->Fmt.fprintffmt"%a->%d"(ppterma[]~argsdepth:be)(mkConstx)n)" ")args(pplist(ppterma[]~argsdepthe)" ")orig_args(ppterma[]~argsdepthe)orig)()];ifis_llamthenbeginletn_args=List.lengthargsiniflvl>gammathen(* All orig args go away, but some between gamma and lvl can stay
* if they are in l or locally bound [d,w] *)letargs_gamma_lvl_abs,args_gamma_lvl_here=letmk_argi=mkConsti,mkConst(cst~hmove:falseibdelta)inletrecmk_intervaldargsnon=ifn=argsnothen[]elseifn+d>=lvlthenleti=n+din(* cut&paste from below *)(tryletnn=List.associargsin(mkConst(lvl+nn),mkConst(gamma+List.lengthl+n))::mk_intervaldargsno(n+1)withNot_found->mk_intervaldargsno(n+1))elsemk_arg(n+d)::mk_intervaldargsno(n+1)inletreckeep_cst_for_lvl=function|[]->mk_interval(d+ifleftthenaelseb)w0|(i,mm)::rest->ifi<lvlthen(mk_argi::keep_cst_for_lvlrest)else(tryletnn=List.associargsin(mkConst(lvl+nn),mkConstmm)::keep_cst_for_lvlrestwithNot_found->keep_cst_for_lvlrest)inList.split(keep_cst_for_lvl(List.sortStdlib.comparel))inletr'=oref~depth:gammaC.dummyinr@:=mknLamn_args(mkAppUVarr'args_gamma_lvl_abs);mkAppUVarr'args_gamma_lvl_hereelse(* given that we need to make lambdas to prune some args,
* we also permute to make the restricted meta eventually
* fall inside the small fragment (sort the args) *)letargs=List.sortStdlib.compareargsinletargs_lvl,args_here=List.fold_right(fun(c,c_p)(a_lvl,a_hereasacc)->tryleti=ifc<gammathencelseifc>=(ifleftthenbelsea)+dthenc+new_lams-(a+d-gamma)elseposc+gammainmkConst(c_p+lvl)::a_lvl,mkConsti::a_herewithRestrictionFailure->acc)args([],[])inifn_args=List.lengthargs_herethen(* no pruning, just binding the args as a normal App *)mkAppUVarr(smart_map(bindbdeltaw)orig_args)else(* we need to project away some of the args *)letr'=oref~depth:lvlC.dummyinletv=mkAppUVarr'args_lvlinr@:=mknLamn_argsv;(* This should be the beta reduct. One could also
* return the non reduced but bound as in the other if branch *)mkAppUVarr'args_hereendelsebeginmkAppUVarr(smart_map(bindbdeltaw)orig_args)endend]inletv=mknLamnew_lams(bindbdelta0t)in[%spy"user:assign:HO"~rid(funfmt()->Fmt.fprintffmt"%a := %a"(upptermgamma[]~argsdepthe)(UVar(r,0))(upptermgamma[]~argsdepthe)v)()];r@:=v;true;;(* exception Non_linear *)letreclist_to_lp_list=function|[]->Nil|x::xs->Cons(x,list_to_lp_listxs);;letdelay_hard_unif_problems=Fork.new_localfalseleterror_msg_hard_unifab="Unification problem outside the pattern fragment. ("^show_terma^" == "^show_termb^") Pass -delay-problems-outside-pattern-fragment (elpi command line utility) "^"or set delay_outside_fragment to true (Elpi_API) in order to delay "^"(deprecated, for Teyjus compatibility)."letrecderef_head~depth=function|UVar({contents=t}asr,ano)whent!=C.dummy->deref_head~depth(deref_uv~to_:depthrano)|AppUVar({contents=t}asr,args)whent!=C.dummy->deref_head~depth(deref_appuv~to_:depthrargs)|x->x(* constant x occurs in term t with level d? *)letoccursxdadepthet=letrecauxdt=matchderef_head~depth:dtwith|Constc->c=x|Lamt->aux(d+1)t|App(c,v,vs)->c=x||auxdv||auxsdvs|UVar(r,ano)->lett,assignment=expand_uv~depth:dr~anoinoption_iter(fun(r,assignment)->r@:=assignment)assignment;auxdt|AppUVar(_,args)->auxsdargs|Builtin(_,vs)->auxsdvs|Cons(v1,v2)->auxdv1||auxdv2|Arg(i,args)whene.(i)!=C.dummy->auxd(deref_arg~from:adepth~to_:de.(i)args)|AppArg(i,args)whene.(i)!=C.dummy->auxd(deref_apparg~from:adepth~to_:de.(i)args)|Nil|CData_|Discard|Arg_|AppArg_->falseandauxsd=function|[]->false|t::ts->auxdt||auxsdtsinx<d&&auxdtletreceta_contract_args~orig_depth~depthrargseat~argsdepthe=matchargs,eatwith|_,[]->[%spy"eta_contract_flex"~rid(funfmt()->Fmt.fprintffmt"all eaten")()];begintrySome(AppUVar(r,smart_map(move~argsdepth~from:depth~to_:orig_depthe)(List.revargs)))withRestrictionFailure->Noneend|Constx::xs,y::yswhenx==y&¬(List.exists(occursydepthargsdepthe)xs)->[%spy"eta_contract_flex"~rid(funfmt->Fmt.fprintffmt"eat %d")y];eta_contract_args~orig_depth~depthrxsys~argsdepthe|_,y::_->[%spy"eta_contract_flex"~rid(funfmt->Fmt.fprintffmt"cannot eat %d")y];None;;letreceta_contract_flexorig_depthdepthxdepth~argsdeptheteat=[%trace"eta_contract_flex"~rid("@[<hov 2>eta_contract_flex %d+%d:%a <- [%a]%!"xdepthdepth(ppterm(xdepth+depth)[]~argsdepthe)t(pplist(funfmti->Fmt.fprintffmt"%d"i)" ")eat)beginmatchderef_head~depth:(xdepth+depth)twith|AppUVar(r,args)whenr.vardepth==0->eta_contract_args~orig_depth:(xdepth+orig_depth)~depth:(xdepth+depth)r(List.revargs)eat~argsdepthe|Lamt->eta_contract_flexorig_depth(depth+1)xdepth~argsdepthet(depth+xdepth::eat)|UVar(r,ano)->lett,assignment=expand_uv~depthr~anoinoption_iter(fun(r,assignment)->r@:=assignment)assignment;eta_contract_flexorig_depthdepthxdepth~argsdeptheteat|AppUVar(r,args)->lett,assignment=expand_appuv~depthr~argsinoption_iter(fun(r,assignment)->r@:=assignment)assignment;eta_contract_flexorig_depthdepthxdepth~argsdeptheteat|Arg(i,args)whene.(i)!=C.dummy->eta_contract_flexorig_depthdepthxdepth~argsdepthe(deref_arg~from:argsdepth~to_:(xdepth+depth)e.(i)args)eat|AppArg(i,args)whene.(i)!=C.dummy->eta_contract_flexorig_depthdepthxdepth~argsdepthe(deref_apparg~from:argsdepth~to_:(xdepth+depth)e.(i)args)eat|Arg(i,args)->letto_=argsdepthinletr=oref~depth:to_C.dummyinletv=UVar(r,0)ine.(i)<-v;eta_contract_flexorig_depthdepthxdepth~argsdepthe(ifargs==0thenvelseUVar(r,args))eat|AppArg(i,args)->letto_=argsdepthinletr=oref~depth:to_C.dummyinletv=UVar(r,0)ine.(i)<-v;eta_contract_flexorig_depthdepthxdepth~argsdepthe(mkAppUVarrargs)eat|_->Noneend];;leteta_contract_flexdepthxdepth~argsdepthet=eta_contract_flexdepthdepthxdepth~argsdepthet[][@@inline]letuvar_uvar_assignment_orderr1r2=uvar_idr1>uvar_idr2letisLam=functionLam_->true|_->falseletrecunif~ocargsdepthmatchingdepthadepthabdepthbe=[%trace"unif"~rid("@[<hov 2>^%d:%a@ =%d%s= ^%d:%a@]%!"adepth(ppterm(adepth+depth)[]~argsdepthempty_env)adepth(ifmatchingthen"m"else"")bdepth(ppterm(bdepth+depth)[]~argsdepth:bdepthe)b)beginletdelta=adepth-bdepthin(delta=0&&a==b)||matcha,bwith|(Discard,_|_,Discard)->true(* _ as X binding *)|_,App(c,arg,[as_this])whenc==Global_symbols.asc->unif~ocargsdepthmatchingdepthadepthabdeptharge&&unif~ocargsdepthmatchingdepthadepthabdepthas_thise|_,App(c,arg,_)whenc==Global_symbols.asc->error"syntax error in as"|App(c,arg,_),_whenc==Global_symbols.asc->unif~ocargsdepthmatchingdepthadepthargbdepthbe(* TODO: test if it is better to deref_uv first or not, i.e. the relative order
of the clauses below *)|UVar(r1,args1),UVar(r2,args2)whenr1==r2&&!!r1==C.dummy->args1==args2(* XXX this would be a type error *)|UVar(r1,xs),AppUVar(r2,ys)whenr1==r2&&!!r1==C.dummy->unif~ocargsdepthmatchingdepthadepth(AppUVar(r1,C.mkintervalr1.vardepthxs0))bdepthbe|AppUVar(r1,xs),UVar(r2,ys)whenr1==r2&&!!r1==C.dummy->unif~ocargsdepthmatchingdepthadepthabdepth(AppUVar(r1,C.mkintervalr1.vardepthys0))e|AppUVar(r1,xs),AppUVar(r2,ys)whenr1==r2&&!!r1==C.dummy->letpruned=reffalseinletfiltered_args_rev=fold_left2i(funiargsxy->letb=unif~ocargsdepthmatchingdepthadepthxbdepthyeinifnotbthen(pruned:=true;args)elsex::args)[]xsysinif!prunedthenbeginletlen=List.lengthxsinletr=oref~depth:r1.vardepthC.dummyinr1@:=mknLamlen(mkAppUVarr(List.revfiltered_args_rev));end;true(* deref_uv *)|UVar({contents=t}asr,args),_whent!=C.dummy->unif~ocargsdepthmatchingdepthadepth(deref_uv~to_:(adepth+depth)rargs)bdepthbe|AppUVar({contents=t}asr,args),_whent!=C.dummy->unif~ocargsdepthmatchingdepthadepth(deref_appuv~to_:(adepth+depth)rargs)bdepthbe|_,UVar({contents=t}asr,args)whent!=C.dummy->unif~ocargsdepthmatchingdepthadepthabdepth(deref_uv~to_:(bdepth+depth)rargs)empty_env|_,AppUVar({contents=t}asr,args)whent!=C.dummy->unif~ocargsdepthmatchingdepthadepthabdepth(deref_appuv~to_:(bdepth+depth)rargs)empty_env|_,Arg(i,args)whene.(i)!=C.dummy->(* e.(i) is a heap term living at argsdepth wich can be > bdepth (e.g.
the clause is at 0 and we are under a pi x\. As a result we do the
deref to and the rec call at adepth *)unif~ocargsdepthmatchingdepthadepthaadepth(deref_arg~from:argsdepth~to_:(adepth+depth)e.(i)args)empty_env|_,AppArg(i,args)whene.(i)!=C.dummy->(* e.(i) is a heap term living at argsdepth wich can be > bdepth (e.g.
the clause is at 0 and we are under a pi x\. As a result we do the
deref to and the rec call at adepth *)letargs=smart_map(move~argsdepth~from:bdepth~to_:adepthe)argsinunif~ocargsdepthmatchingdepthadepthaadepth(deref_apparg~from:argsdepth~to_:(adepth+depth)e.(i)args)empty_env(* UVar introspection (matching) *)|(UVar_|AppUVar_),Constcwhenc==Global_symbols.uvarc&&matching->true|UVar(r,ano),App(c,hd,[])whenc==Global_symbols.uvarc&&matching->unif~ocargsdepthmatchingdepthadepth(UVar(r,ano))bdepthhde|AppUVar(r,_),App(c,hd,[])whenc==Global_symbols.uvarc&&matching->unif~ocargsdepthmatchingdepthadepth(UVar(r,0))bdepthhde|UVar(r,ano),App(c,hd,[arg])whenc==Global_symbols.uvarc&&matching->letvd=r.vardepthinletr_exp=oref~depth:0C.dummyinletexp=UVar(r_exp,0)inr@:=UVar(r_exp,vd);unif~ocargsdepthmatchingdepthadepthexpbdepthhde&&letargs=list_to_lp_list(C.mkinterval0(vd+ano)0)inunif~ocargsdepthmatchingdepthadepthargsbdeptharge|AppUVar(r,args),App(c,hd,[arg])whenc==Global_symbols.uvarc&&matching->letvd=r.vardepthinletr_exp=oref~depth:0C.dummyinletexp=UVar(r_exp,0)inr@:=UVar(r_exp,vd);unif~ocargsdepthmatchingdepthadepthexpbdepthhde&&letargs=list_to_lp_list(C.mkinterval0vd0@args)inunif~ocargsdepthmatchingdepthadepthargsbdeptharge|Lam_,(Constc|App(c,_,_))whenc==Global_symbols.uvarc&&matching->beginmatcheta_contract_flexdepthadepth~argsdepth:adeptheawith|None->false|Somea->unif~ocargsdepthmatchingdepthadepthabdepthbeend|(App_|Const_|Builtin_|Nil|Cons_|CData_),(Constc|App(c,_,[]))whenc==Global_symbols.uvarc&&matching->false(* On purpose we let the fully applied uvarc pass, so that at the
* meta level one can unify fronzen constants. One can use the var builtin
* to discriminate the two cases, as in "p (uvar F L as X) :- var X, .." *)(* assign *)|_,Arg(i,0)->begintryletv=hmove~from:(adepth+depth)~to_:argsdepthain[%spy"user:assign"~rid(funfmt()->Fmt.fprintffmt"%a := %a"(upptermadepth[]~argsdepthe)b(upptermadepth[]~argsdepthe)v)()];e.(i)<-v;truewithRestrictionFailure->falseend|UVar(r1,0),UVar(r2,0)whenuvar_uvar_assignment_orderr1r2->unif~ocargsdepthmatchingdepthbdepthbadepthae|AppUVar(r1,_),UVar(r2,0)whenuvar_uvar_assignment_orderr1r2->unif~ocargsdepthmatchingdepthbdepthbadepthae|_,UVar(r,0)->letorigdepth=r.vardepthinbegintrylett=ifdepth=0thenhmove~oc:(ifocthenCheckrelseSkip)~from:adepth~to_:origdepthaelse(* First step: we lift the l.h.s. to the r.h.s. level *)leta=hmove~oc:(ifocthenCheckrelseSkip)~from:(adepth+depth)~to_:(bdepth+depth)ain(* Second step: we restrict the l.h.s. *)hmove~from:(bdepth+depth)~to_:origdepthain[%spy"user:assign"~rid(funfmt()->Fmt.fprintffmt"%a := %a"(upptermdepth[]~argsdepthe)b(upptermdepth[]~argsdepthe)t)()];r@:=t;truewithRestrictionFailurewhenisLama->(* avoid fail occur-check on: x\A x = A | x\y\A y x = A
we eta expand and see how it is under the lambdas *)letb=(mkLam@@mkAppUVarr[mkConst@@depth+bdepth])inleta=hmove~from:(adepth+depth)~to_:(bdepth+depth)ainunif~ocargsdepthmatchingdepthbdepthabdepthbe|RestrictionFailure->falseend|UVar(r,0),_whennotmatching->letorigdepth=r.vardepthinbegintrylett=ifdepth=0thenmove~oc:(ifocthenCheckrelseSkip)~argsdepth~from:bdepth~to_:origdepthebelse(* First step: we lift the r.h.s. to the l.h.s. level *)letb=move~oc:(ifocthenCheckrelseSkip)~argsdepth~from:(bdepth+depth)~to_:(adepth+depth)ebin(* Second step: we restrict the r.h.s. *)hmove~from:(adepth+depth)~to_:origdepthbin[%spy"user:assign"~rid(funfmt()->Fmt.fprintffmt"%a := %a"(upptermorigdepth[]~argsdepth:0empty_env)a(upptermorigdepth[]~argsdepth:0empty_env)t)()];r@:=t;truewithRestrictionFailurewhenisLamb->(* avoid fail occur-check on: x\A x = A | x\y\A y x = A
we eta expand and see how it is under the lambdas *)leta=(mkLam@@mkAppUVarr[mkConst@@depth+adepth])inletb=move~argsdepth~from:(bdepth+depth)~to_:(adepth+depth)ebinunif~ocargsdepthmatchingdepthadepthaadepthbe|RestrictionFailure->falseend(* XXX simplify either generated UVar(_,_,0) or AppUVar XXX *)|_,Arg(i,args)->letv=make_lambdasadepth(args-depth)in[%spy"user:assign:simplify:stack:arg"~rid(funfmt()->Fmt.fprintffmt"%a := %a"(upptermdepth[]~argsdepthe)(Arg(i,0))(upptermdepth[]~argsdepthe)v)()];e.(i)<-v;letbdepth=adepthin(* like in deref for arg *)letb=deoptimize_uv_w_args@@deref_arg~from:argsdepth~to_:(bdepth+depth)vargsinunif~ocargsdepthmatchingdepthadepthabdepthbe|UVar(r1,a1),UVar(r2,a2)whenuvar_uvar_assignment_orderr1r2->unif~ocargsdepthmatchingdepthbdepthbadepthae(* TODO argsdepth *)|AppUVar(r1,_),UVar(r2,a2)whenuvar_uvar_assignment_orderr1r2->unif~ocargsdepthmatchingdepthbdepthbadepthae|_,UVar(r,args)whenargs>0&&matchawithUVar(r1,_)|AppUVar(r1,_)->r!=r1|_->true->letorigdepth=r.vardepthinletv=make_lambdasorigdepth(args-depth)in[%spy"user:assign:simplify:stack:uvar"~rid(funfmt()->Fmt.fprintffmt"%a := %a"(upptermdepth[]~argsdepthe)(UVar(r,0))(upptermdepth[]~argsdepthe)v)()];r@:=v;letb=deoptimize_uv_w_args@@deref_arg~from:origdepth~to_:(bdepth+depth)vargsinunif~ocargsdepthmatchingdepthadepthabdepthbe|UVar(r,args),_whenargs>0&&matchbwithUVar(r1,_)|AppUVar(r1,_)->r!=r1|_->true->letorigdepth=r.vardepthinletv=make_lambdasorigdepth(args-depth)in[%spy"user:assign:simplify:heap"~rid(funfmt()->Fmt.fprintffmt"%a := %a"(upptermdepth[]~argsdepthe)(UVar(r,0))(upptermdepth[]~argsdepthe)v)()];r@:=v;leta=deoptimize_uv_w_args@@deref_arg~from:origdepth~to_:(adepth+depth)vargsinunif~ocargsdepthmatchingdepthadepthabdepthbe(* HO *)|other,AppArg(i,args)->letis_llam,args=is_llamadepthargsadepthbdepthdepthfalseeinifis_llamthenletr=oref~depth:adepthC.dummyine.(i)<-UVar(r,0);trybind~argsdepthrargsadepthdepthdeltabdepthfalseotherewithRestrictionFailure->falseelseif!delay_hard_unif_problemsthenbeginFmt.fprintfFmt.std_formatter"HO unification delayed: %a = %a\n%!"(upptermdepth[]~argsdepthempty_env)a(upptermdepth[]~argsdepthe)b;letr=oref~depth:adepthC.dummyine.(i)<-UVar(r,0);letkind=Unification{adepth=adepth+depth;env=e;bdepth=bdepth+depth;a;b;matching;oc}inletblockers=matchis_flex~depth:(adepth+depth)otherwith|None->[r]|Somer'->ifr==r'then[r]else[r;r']inCS.declare_new{kind;blockers};trueendelseerror(error_msg_hard_unifab)|AppUVar(r2,_),(AppUVar(r1,_)|UVar(r1,_))whenuvar_uvar_assignment_orderr1r2->unif~ocargsdepthmatchingdepthbdepthbadepthae|AppUVar(r,(argsasoargs)),otherwhennotmatching->letlvl=r.vardepthinletis_llam,args=is_llamlvlargsadepthbdepthdepthtrueeinifis_llamthentrybind~argsdepthrargsadepthdepthdeltabdepthtrueotherewithRestrictionFailurewhenisLamother->leta=mkLam@@mkAppUVarr(smart_map(move~argsdepthe~from:(depth+adepth)~to_:(depth+adepth+1))oargs@[mkConst@@depth+adepth])inletb=move~from:(depth+bdepth)~to_:(depth+adepth)~argsdepthebinunif~ocargsdepthmatchingdepthadepthaadepthbe|RestrictionFailure->falseelseif!delay_hard_unif_problemsthenbeginFmt.fprintfFmt.std_formatter"HO unification delayed: %a = %a\n%!"(upptermdepth[]~argsdepthempty_env)a(upptermdepth[]~argsdepthempty_env)b;letkind=Unification{adepth=adepth+depth;env=e;bdepth=bdepth+depth;a;b;matching;oc}inletblockers=matchis_flex~depth:(bdepth+depth)otherwith|None->[r]|Somer'->[r;r']inCS.declare_new{kind;blockers};trueendelseerror(error_msg_hard_unifab)|other,AppUVar(r,(argsasoargs))->letlvl=r.vardepthinletis_llam,args=is_llamlvlargsadepthbdepthdepthfalseeinifis_llamthentrybind~argsdepthrargsadepthdepthdeltabdepthfalseotherewithRestrictionFailurewhenisLamother->letb=mkLam@@mkAppUVarr(smart_map(move~argsdepthe~from:(depth+bdepth)~to_:(depth+bdepth+1))oargs@[mkConst@@depth+bdepth])inleta=hmove~from:(depth+adepth)~to_:(depth+bdepth)ainunif~ocargsdepthmatchingdepthbdepthabdepthbe|RestrictionFailure->falseelseif!delay_hard_unif_problemsthenbeginFmt.fprintfFmt.std_formatter"HO unification delayed: %a = %a\n%!"(upptermdepth[]~argsdepthempty_env)a(upptermdepth[]~argsdepthe)b;letkind=Unification{adepth=adepth+depth;env=e;bdepth=bdepth+depth;a;b;matching;oc}inletblockers=matchis_flex~depth:(adepth+depth)otherwith|None->[r]|Somer'->ifr==r'then[r]else[r;r']inCS.declare_new{kind;blockers};trueendelseerror(error_msg_hard_unifab)(* recursion *)|App(c1,x2,xs),App(c2,y2,ys)->(* Compressed cut&past from Const vs Const case below +
delta=0 optimization for <c1,c2> and <x2,y2> *)((delta=0||c1<bdepth)&&c1=c2||c1>=adepth&&c1=c2+delta)&&(delta=0&&x2==y2||unif~ocargsdepthmatchingdepthadepthx2bdepthy2e)&&for_all2(funxy->unif~ocargsdepthmatchingdepthadepthxbdepthye)xsys|Builtin(c1,xs),Builtin(c2,ys)->(* Inefficient comparison *)c1=c2&&for_all2(funxy->unif~ocargsdepthmatchingdepthadepthxbdepthye)xsys|Lamt1,Lamt2->unif~ocargsdepthmatching(depth+1)adeptht1bdeptht2e|Constc1,Constc2->ifc1<bdepththenc1=c2elsec1>=adepth&&c1=c2+delta(*| Const c1, Const c2 when c1 < bdepth -> c1=c2
| Const c, Const _ when c >= bdepth && c < adepth -> false
| Const c1, Const c2 when c1 = c2 + delta -> true*)|CDatad1,CDatad2->CData.equald1d2|Cons(hd1,tl1),Cons(hd2,tl2)->unif~ocargsdepthmatchingdepthadepthhd1bdepthhd2e&&unif~ocargsdepthmatchingdepthadepthtl1bdepthtl2e|Nil,Nil->true(* eta *)|Lamt,Constc->eta_expand_stack~ocargsdepthmatchingdepthadepthtbdepthbc[]e|Constc,Lamt->eta_expand_heap~ocargsdepthmatchingdepthadepthc[]bdepthbte|Lamt,App(c,x,xs)->eta_expand_stack~ocargsdepthmatchingdepthadepthtbdepthbc(x::xs)e|App(c,x,xs),Lamt->eta_expand_heap~ocargsdepthmatchingdepthadepthc(x::xs)bdepthbte|_->falseend]andeta_expand_stack~ocargsdepthmatchingdepthadepthxbdepthbcargse=letextra=mkConst(bdepth+depth)inletmotion=move~argsdepth~from:(bdepth+depth)~to_:(bdepth+depth+1)einletargs=smart_mapmotionargsinleteta=C.mkAppLc(args@[extra])inunif~ocargsdepthmatching(depth+1)adepthxbdepthetaeandeta_expand_heap~ocargsdepthmatchingdepthadepthcargsbdepthbxe=letextra=mkConst(adepth+depth)inletmotion=hmove~from:(adepth+depth)~to_:(adepth+depth+1)inletargs=smart_mapmotionargsinleteta=C.mkAppLc(args@[extra])inunif~ocargsdepthmatching(depth+1)adepthetabdepthxe;;(* FISSA PRECEDENZA PER AS e FISSA INDEXING per AS e fai coso generale in unif *)letunif~oc~argsdepth~matching(gid[@trace])adepthebdepthab=letres=unif~ocargsdepthmatching0adepthabdepthbein[%spy"dev:unif:out"~ridFmt.pp_print_boolres];[%spy"user:backchain:fail-to"~rid~gid~cond:(notres)(funfmt()->letop=ifmatchingthen"match"else"unify"inFmt.fprintffmt"@[<hov 2>%s@ %a@ with@ %a@]"op(uppterm(adepth)[]~argsdepth:bdepthempty_env)a(uppterm(bdepth)[]~argsdepth:bdepthe)b)()];res;;(* Look in Git for Enrico's partially tail recursive but slow unification.
The tail recursive version is even slower. *)(* }}} *)letfull_deref~adepthenv~deptht=letrecderefd=function|Const_asx->x|Lamrasorig->letr'=deref(d+1)rinifr==r'thenorigelseLamr'|App(n,x,xs)asorig->letx'=derefdxinletxs'=smart_map(derefd)xsinifx==x'&&xs==xs'thenorigelseApp(n,x',xs')|Cons(hd,tl)asorig->lethd'=derefdhdinlettl'=derefdtlinifhd==hd'&&tl==tl'thenorigelseCons(hd',tl')|Nilasx->x|Discardasx->x|Arg(i,ano)whenenv.(i)!=C.dummy->derefd(deref_arg~from:adepth~to_:denv.(i)ano)|Arg_asx->x|AppArg(i,args)whenenv.(i)!=C.dummy->derefd(deref_apparg~from:adepth~to_:denv.(i)args)|AppArg(i,args)asorig->letargs'=smart_map(derefd)argsinifargs==args'thenorigelseAppArg(i,args')|UVar(r,ano)when!!r!=C.dummy->derefd(deref_uv~to_:drano)|UVar_asx->x|AppUVar(r,args)when!!r!=C.dummy->derefd(deref_appuv~to_:drargs)|AppUVar(r,args)asorig->letargs'=smart_map(derefd)argsinifargs==args'thenorigelseAppUVar(r,args')|Builtin(c,xs)asorig->letxs'=smart_map(derefd)xsinifxs==xs'thenorigelseBuiltin(c,xs')|CData_asx->xinderefdepthttypeassignment=uvar*termletshift_bound_vars~depth~to_t=letshift_dbdn=ifn<depththennelsen+to_-depthinletrecshiftd=function|Constnasx->letm=shift_dbdninifm=nthenxelsemkConstm|Lamrasorig->letr'=shift(d+1)rinifr==r'thenorigelseLamr'|App(n,x,xs)asorig->letx'=shiftdxinletxs'=smart_map(shiftd)xsinifx==x'&&xs==xs'thenorigelseApp(shift_dbdn,x',xs')|Cons(hd,tl)asorig->lethd'=shiftdhdinlettl'=shiftdtlinifhd==hd'&&tl==tl'thenorigelseCons(hd',tl')|Nilasx->x|Discardasx->x|Arg_asx->x|AppArg(i,args)asorig->letargs'=smart_map(shiftd)argsinifargs==args'thenorigelseAppArg(i,args')|(UVar(r,_)|AppUVar(r,_))when!!r!=C.dummy->anomaly"shift_bound_vars: non-derefd term"|UVar_asx->x|AppUVar(r,args)asorig->letargs'=smart_map(shiftd)argsinifargs==args'thenorigelseAppUVar(r,args')|Builtin(c,xs)asorig->letxs'=smart_map(shiftd)xsinifxs==xs'thenorigelseBuiltin(c,xs')|CData_asx->xinifdepth=to_thentelseshiftdepthtletmap_free_vars~map~depth~to_t=letshift_bound=depth-to_inletshift_dbdn=ifn<0thennelseifn<depththentryC.Map.findnmapwithNot_found->error(Printf.sprintf"The term cannot be put in the desired context since it contains name: %s"@@C.shown)elseifn>=depth&&n-depth<=dthenn-shift_boundelseerror(Printf.sprintf"The term cannot be put in the desired context since it contains name: %s"@@C.shown)inletrecshiftd=function|Constnasx->letm=shift_dbdninifm=nthenxelsemkConstm|Lamrasorig->letr'=shift(d+1)rinifr==r'thenorigelseLamr'|App(n,x,xs)asorig->letx'=shiftdxinletxs'=smart_map(shiftd)xsinifx==x'&&xs==xs'thenorigelseApp(shift_dbdn,x',xs')|Cons(hd,tl)asorig->lethd'=shiftdhdinlettl'=shiftdtlinifhd==hd'&&tl==tl'thenorigelseCons(hd',tl')|Nilasx->x|Discardasx->x|Arg_asx->x|AppArg(i,args)asorig->letargs'=smart_map(shiftd)argsinifargs==args'thenorigelseAppArg(i,args')|(UVar(r,_)|AppUVar(r,_))when!!r!=C.dummy->anomaly"map_free_vars: non-derefd term"|UVar(r,ano)asorig->assert(r.vardepth=minr.vardepthto_);orig|AppUVar(r,args)->assert(r.vardepth=minr.vardepthto_);AppUVar(r,smart_map(shiftd)args)|Builtin(c,xs)asorig->letxs'=smart_map(shiftd)xsinifxs==xs'thenorigelseBuiltin(c,xs')|CData_asx->xinifdepth=to_&&C.Map.is_emptymapthentelseshift0tleteta_contract_flex~deptht=eta_contract_flexdepth0~argsdepth:0empty_envt[@@inline]end(* }}} *)openHOlet()=do_uv_deref:=deref_uvlet()=do_appuv_deref:=deref_appuvlet()=do_arg_deref:=deref_arglet()=do_apparg_deref:=deref_apparg(* Built-in predicates and their FFI *************************************** *)moduleFFI=structletbuiltins:Data.BuiltInPredicate.builtin_tableref=Fork.new_local(Hashtbl.create17)letlookupc=Hashtbl.find!builtinsclettype_err~depthbnamentyt=type_errorbegin"builtin "^bname^": "^(ifn=0then""elsestring_of_intn^"th argument: ")^"expected: "^ty^" got"^matchtwith|None->"_"|Somet->matchtwith|CDatac->Format.asprintf" %s: %a"(CData.namec)(Pp.upptermdepth[]~argsdepth:0empty_env)t|_->Format.asprintf": %a"(Pp.upptermdepth[]~argsdepth:0empty_env)tendletwrap_type_errbnamenfx=tryfxwithConversion.TypeErr(ty,depth,t)->type_err~depthbnamen(Conversion.show_ty_astty)(Somet)letarity_err~depthbnament=type_error("builtin "^bname^": "^matchtwith|None->string_of_intn^"th argument is missing"|Somet->"too many arguments at: "^Format.asprintf"%a"(Pp.upptermdepth[]~argsdepth:0empty_env)t)letout_of_term~depthreadbacknbnamestatet=matchderef_head~depthtwith|Discard->Data.BuiltInPredicate.Discard|_->Data.BuiltInPredicate.Keepletin_of_term~depthreadbacknbnamestatet=wrap_type_errbnamen(readback~depthstate)tletinout_of_term~depthreadbacknbnamestatet=wrap_type_errbnamen(readback~depthstate)tletmk_out_assign~depthembedbnamestateinputvoutput=matchoutput,inputwith|None,Data.BuiltInPredicate.Discard->state,[]|Some_,Data.BuiltInPredicate.Discard->state,[](* We could warn that such output was generated without being required *)|Somet,Data.BuiltInPredicate.Keep->letstate,t,extra=embed~depthstatetinstate,extra@[Conversion.Unify(v,t)]|None,Data.BuiltInPredicate.Keep->state,[]letmk_inout_assign~depthembedbnamestateinputvoutput=matchoutputwith|None->state,[]|Somet->letstate,t,extra=embed~depthstate(Data.BuiltInPredicate.Datat)instate,extra@[Conversion.Unify(v,t)]letin_of_termC~depthreadbacknbnamehypsconstraintsstatet=wrap_type_errbnamen(readback~depthhypsconstraintsstate)tletinout_of_termC=in_of_termCletmk_out_assignC~depthembedbnamehypsconstraintsstateinputvoutput=matchoutput,inputwith|None,Data.BuiltInPredicate.Discard->state,[]|Some_,Data.BuiltInPredicate.Discard->state,[](* We could warn that such output was generated without being required *)|Somet,Data.BuiltInPredicate.Keep->letstate,t,extra=embed~depthhypsconstraintsstatetinstate,extra@[Conversion.Unify(v,t)]|None,Data.BuiltInPredicate.Keep->state,[]letmk_inout_assignC~depthembedbnamehypsconstraintsstateinputvoutput=matchoutputwith|Somet->letstate,t,extra=embed~depthhypsconstraintsstate(Data.BuiltInPredicate.Datat)instate,extra@[Conversion.Unify(v,t)]|None->state,[]letmap_accfsl=letrecauxaccextras=function|[]->s,List.revacc,List.(concat(revextra))|x::xs->lets,x,gls=fsxinaux(x::acc)(gls::extra)sxsinaux[][]slletcall(Data.BuiltInPredicate.Pred(bname,ffi,compute))~once~depthhypsconstraintsstatedata=letrecaux:typeiohc.(i,o,h,c)Data.BuiltInPredicate.ffi->h->c->compute:i->reduce:(State.t->o->State.t*Conversion.extra_goals)->termlist->int->State.t->Conversion.extra_goalslist->State.t*Conversion.extra_goals=funffictxconstraints~compute~reducedatanstateextra->matchffi,datawith|Data.BuiltInPredicate.Easy_,[]->letresult=wrap_type_errbname0(fun()->compute~depth)()inletstate,l=reducestateresultinstate,List.(concat(revextra)@revl)|Data.BuiltInPredicate.Read_,[]->letresult=wrap_type_errbname0(compute~depthctxconstraints)stateinletstate,l=reducestateresultinstate,List.(concat(revextra)@revl)|Data.BuiltInPredicate.Full_,[]->letstate,result,gls=wrap_type_errbname0(compute~depthctxconstraints)stateinletstate,l=reducestateresultinstate,List.(concat(revextra))@gls@List.revl|Data.BuiltInPredicate.FullHO_,[]->letstate,result,gls=wrap_type_errbname0(compute~once~depthctxconstraints)stateinletstate,l=reducestateresultinstate,List.(concat(revextra))@gls@List.revl|Data.BuiltInPredicate.VariadicIn(_,{ContextualConversion.readback},_),data->letstate,i,gls=map_acc(in_of_termC~depthreadbacknbnamectxconstraints)statedatainletstate,rest=wrap_type_errbname0(computei~depthctxconstraints)stateinletstate,l=reducestaterestinstate,List.(gls@concat(revextra)@revl)|Data.BuiltInPredicate.VariadicOut(_,{ContextualConversion.embed;readback},_),data->leti=List.map(out_of_term~depthreadbacknbnamestate)datainletstate,(rest,out)=wrap_type_errbname0(computei~depthctxconstraints)stateinletstate,l=reducestaterestinbeginmatchoutwith|Someout->letstate,ass=map_acc3(mk_out_assignC~depthembedbnamectxconstraints)stateidataoutinstate,List.(concat(revextra)@rev(concatass)@l)|None->state,List.(concat(revextra)@revl)end|Data.BuiltInPredicate.VariadicInOut(_,{ContextualConversion.embed;readback},_),data->letstate,i,gls=map_acc(inout_of_termC~depthreadbacknbnamectxconstraints)statedatainletstate,(rest,out)=wrap_type_errbname0(computei~depthctxconstraints)stateinletstate,l=reducestaterestinbeginmatchoutwith|Someout->letstate,ass=map_acc3(mk_inout_assignC~depthembedbnamectxconstraints)stateidataoutinstate,List.(gls@concat(revextra)@rev(concatass)@l)|None->state,List.(gls@concat(revextra)@revl)end|Data.BuiltInPredicate.CIn({ContextualConversion.readback},_,ffi),t::rest->letstate,i,gls=in_of_termC~depthreadbacknbnamectxconstraintsstatetinauxffictxconstraints~compute:(computei)~reducerest(n+1)state(gls::extra)|Data.BuiltInPredicate.COut({ContextualConversion.embed;readback},_,ffi),t::rest->leti=out_of_term~depthreadbacknbnamestatetinletreducestate(rest,out)=letstate,l=reducestaterestinletstate,ass=mk_out_assignC~depthembedbnamectxconstraintsstateitoutinstate,ass@linauxffictxconstraints~compute:(computei)~reducerest(n+1)stateextra|Data.BuiltInPredicate.CInOut({ContextualConversion.embed;readback},_,ffi),t::rest->letstate,i,gls=inout_of_termC~depthreadbacknbnamectxconstraintsstatetinletreducestate(rest,out)=letstate,l=reducestaterestinletstate,ass=mk_inout_assignC~depthembedbnamectxconstraintsstateitoutinstate,ass@linauxffictxconstraints~compute:(computei)~reducerest(n+1)state(gls::extra)|Data.BuiltInPredicate.In({Conversion.readback},_,ffi),t::rest->letstate,i,gls=in_of_term~depthreadbacknbnamestatetinauxffictxconstraints~compute:(computei)~reducerest(n+1)state(gls::extra)|Data.BuiltInPredicate.Out({Conversion.embed;readback},_,ffi),t::rest->leti=out_of_term~depthreadbacknbnamestatetinletreducestate(rest,out)=letstate,l=reducestaterestinletstate,ass=mk_out_assign~depthembedbnamestateitoutinstate,ass@linauxffictxconstraints~compute:(computei)~reducerest(n+1)stateextra|Data.BuiltInPredicate.InOut({Conversion.embed;readback},_,ffi),t::rest->letstate,i,gls=inout_of_term~depthreadbacknbnamestatetinletreducestate(rest,out)=letstate,l=reducestaterestinletstate,ass=mk_inout_assign~depthembedbnamestateitoutinstate,ass@linauxffictxconstraints~compute:(computei)~reducerest(n+1)state(gls::extra)|_,t::_->arity_err~depthbnamen(Somet)|_,[]->arity_err~depthbnamenNoneinletrecaux_ctx:typeiohc.(i,o,h,c)Data.BuiltInPredicate.ffi->(h,c)ContextualConversion.ctx_readback=function|Data.BuiltInPredicate.FullHO(f,_)->f|Data.BuiltInPredicate.Full(f,_)->f|Data.BuiltInPredicate.Read(f,_)->f|Data.BuiltInPredicate.VariadicIn(f,_,_)->f|Data.BuiltInPredicate.VariadicOut(f,_,_)->f|Data.BuiltInPredicate.VariadicInOut(f,_,_)->f|Data.BuiltInPredicate.Easy_->ContextualConversion.unit_ctx|Data.BuiltInPredicate.In(_,_,rest)->aux_ctxrest|Data.BuiltInPredicate.Out(_,_,rest)->aux_ctxrest|Data.BuiltInPredicate.InOut(_,_,rest)->aux_ctxrest|Data.BuiltInPredicate.CIn(_,_,rest)->aux_ctxrest|Data.BuiltInPredicate.COut(_,_,rest)->aux_ctxrest|Data.BuiltInPredicate.CInOut(_,_,rest)->aux_ctxrestinletreducestate_=state,[]inletstate,ctx,csts,gls_ctx=aux_ctxffi~depthhypsconstraintsstateinletstate,gls=auxffictxcsts~compute~reducedata1state[]instate,gls_ctx@gls;;end(******************************************************************************
Indexing
******************************************************************************)moduleIndexing=struct(* {{{ *)(* These are sorted wrt lex_insertion
-2
-1
0
1.-1
1.-2
1
1.+2
1.+1
2
The idea being that clause "a" to be inserted w.r.t. "b" takes
as timestamp the one of "b" followerd by the timestamp. If "a"
has to be before, the timestamp is made negative.
*)letlex_insertionl1l2=letreclex_insertionfstl1l2=matchl1,l2with|[],[]->0|x::l1,y::l2whennotfst->letr=ifx<0&&y<0||x>0&&y>0theny-xelsex-yinifr=0thenlex_insertionfalsel1l2elser|x1::l1,x2::l2->letx=x1-x2inifx=0thenlex_insertionfalsel1l2elsex|[],ys->lex_insertionfalse[0]ys|xs,[]->lex_insertionfalsexs[0]inlex_insertiontruel1l2letmustbevariablec=min_int(* uvar or uvar t or uvar l t *)letppclausef~hd{depth;args=args;hyps=hyps}=Fmt.fprintff"@[<hov 1>%a :- %a.@]"(uppterm~min_prec:(Elpi_parser.Parser_config.appl_precedence+1)depth[]~argsdepth:0empty_env)(C.mkAppLhdargs)(pplist(uppterm~min_prec:(Elpi_parser.Parser_config.appl_precedence+1)depth[]~argsdepth:0empty_env)", ")hyps(** [tail_opt L] returns: [match L with [] -> [] | x :: xs -> xs] *)lettail_opt=function|[]->[]|_::xs->xslethd_opt=function|x::_->Mode.get_headx|_->Outputtypeclause_arg_classification=|Variable|MustBeVariable|Rigidofconstant*Mode.tletrecclassify_clause_arg~depthmatchingt=(* Format.eprintf "index %a\n%!" (ppterm depth [] ~argsdepth:depth empty_env) t; *)matchderef_head~depthtwith|Constkwhenk==Global_symbols.uvarc->MustBeVariable|Constk->Rigid(k,matching)|Nil->Rigid(Global_symbols.nilc,matching)|Cons_->Rigid(Global_symbols.consc,matching)|App(k,_,_)whenk==Global_symbols.uvarc->MustBeVariable|App(k,a,_)whenk==Global_symbols.asc->classify_clause_arg~depthmatchinga|App(k,_,_)->Rigid(k,matching)|Builtin(k,_)->Rigid(const_of_builtin_predicatek,matching)|Lam_->Variable(* loose indexing to enable eta *)|Arg_|UVar_|AppArg_|AppUVar_|Discard->Variable|CDatad->lethash=-(CData.hashd)inifhash>mustbevariablecthenRigid(hash,matching)elseRigid(hash+1,matching)(**
[classify_clause_argno ~depth N mode L] where L is the arguments of the
clause. Returns the classification of the Nth element of L wrt to the Nth mode
for the TwoLevelIndex
*)letrecclassify_clause_argno~depthargnomode=function|[]->Variable|x::_whenargno==0->classify_clause_arg~depth(hd_optmode)x|_::xs->classify_clause_argno~depth(argno-1)(tail_optmode)xsletdec_to_bin2num=letrecauxx=ifx==1then["1"]elseifx==0then["0"]elseifxmod2==1then"1"::aux(x/2)else"0"::aux(x/2)inString.concat""(List.rev(auxnum))[@@warning"-32"]lethash_bits=Sys.int_size-1(* the sign *)(**
Hashing function for clause and queries depending on the boolean [is_goal].
This is done by hashing the parameters wrt to Sys.int_size - 1 (see [hash_bits])
*)lethash_arg_listis_goalhd~depthargsmodespec=letnargs=List.(length(filter(funx->x>0)spec))in(* we partition equally, that may not be smart, but is simple ;-) *)letarg_size=hash_bits/nargsinlethashsizek=letmodulus=1lslsizeinletkabs=Hashtbl.hashkinleth=kabsmodmodulusin[%spy"dev:index:subhash-const"~ridC.ppkpp_string(dec_to_bin2h)];hinletall_1size=max_intlsr(hash_bits-size)inletall_0size=0inletshiftslot_sizepositionx=xlsl(slot_size*position)inletrecauxoffaccargsmodespec=matchargs,specwith|_,[]->acc|[],_->acc|x::xs,n::spec->leth=aux_argarg_size(hd_optmode)nxinaux(off+arg_size)(acclor(hlsloff))xs(tail_optmode)specandaux_argsizemodedeeparg=leth=matchderef_head~depthargwith|App(k,a,_)whenk==Global_symbols.asc->aux_argsizemodedeepa|Constkwhenk==Global_symbols.uvarc->hashsizemustbevariablec|App(k,_,_)whenk==Global_symbols.uvarc&&deep=1->hashsizemustbevariablec|Constk->hashsizek|App(k,_,_)whendeep=1->hashsizek|App(k,x,xs)->letsize=size/(List.lengthxs+2)inletself=aux_argsizemode(deep-1)inletshift=shiftsizein(hashsizek)lor(shift1(selfx))lorList.(fold_left(lor)0(mapi(funix->shift(i+2)(selfx))xs))|(UVar_|AppUVar_)whenmode==Input&&is_goal->hashsizemustbevariablec|(UVar_|AppUVar_)whenmode==Input->all_1size|(UVar_|AppUVar_)->ifis_goalthenall_0sizeelseall_1size|(Arg_|AppArg_)->all_1size|Nil->hashsizeGlobal_symbols.nilc|Cons(x,xs)->letsize=size/2inletself=aux_argsizemode(deep-1)inletshift=shiftsizein(hashsizeGlobal_symbols.consc)lor(shift1(selfx))|CDatas->hashsize(CData.hashs)|Lam_->all_1size|Discard->all_1size|Builtin(k,xs)->letsize=size/(List.lengthxs+1)inletself=aux_argsizemode(deep-1)inletshift=shiftsizein(hashsize(const_of_builtin_predicatek))lorList.(fold_left(lor)0(mapi(funix->shift(i+1)(selfx))xs))in[%spy"dev:index:subhash"~rid(funfmt()->Fmt.fprintffmt"%s: %d: %s: %a"(ifis_goalthen"goal"else"clause")size(dec_to_bin2h)(upptermdepth[]~argsdepth:0empty_env)arg)()];hinleth=aux00argsmodespecin[%spy"dev:index:hash"~rid(funfmt()->Fmt.fprintffmt"%s: %s: %a"(ifis_goalthen"goal"else"clause")(dec_to_bin2h)(pplist~boxed:true(upptermdepth[]~argsdepth:0empty_env)" ")(Consthd::args))()];hlethash_clause_arg_list=hash_arg_listfalselethash_goal_arg_list=hash_arg_listtrue(* returns the maximal length of any sub_list
this operation is done at compile time per each clause being index
for example the term (app['a','b',app['c','d','e'], 'f', app['a','b','c','d','e','f']])
has three lists L1 = ['a','b',app['c','d','e'], 'f', app['a','b','c','d','e','f']
L2 = ['c','d','e']
L3 = app['a','b','c','d','e','f']
and the longest one has length 6
*)letrecmax_list_lengthacc=function|Nil->acc|Cons(a,(UVar(_,_)|AppUVar(_,_)|Arg(_,_)|AppArg(_,_)|Discard))->letalen=max_list_length0ainmax(acc+2)alen|Cons(a,b)->letalen=max_list_length0ainletblen=max_list_length(acc+1)binmaxblenalen|App(_,x,xs)->List.fold_left(funaccx->maxacc(max_list_length0x))acc(x::xs)|Builtin(_,xs)->List.fold_left(funaccx->maxacc(max_list_length0x))accxs|Lamt->max_list_lengthacct|Discard|Const_|CData_|UVar(_,_)|AppUVar(_,_)|Arg(_,_)|AppArg(_,_)->accletmax_lists_length=List.fold_left(funacce->max(max_list_length0e)acc)0(**
[arg_to_trie_path ~safe ~depth ~is_goal args arg_depths arg_modes mp max_list_length]
returns the path represetation of a term to be used in indexing with trie.
args, args_depths and arg_modes are the lists of respectively the arguments, the
depths and the modes of the current term to be indexed.
~is_goal is used to know if we are encoding the path for instance retriaval or
for clause insertion in the trie.
In the former case, each argument we add a special mkInputMode/mkOutputMode
node before each argument to be indexed. This special node is used during
instance retrival to know the mode of the current argument
- mp is the max_path size of any path in the index used to truncate the goal
- max_list_length is the length of the longest sublist in each term of args
*)typecheck_mut_excl=|OffofMode.hos|On[@@derivingshow]letarg_to_trie_path~check_mut_excl~safe~depth~is_goalargsarg_depthsargs_depths_armp(max_list_length':int):Discrimination_tree.Path.t=letopenDiscrimination_treeinletpath_length=mp+Array.lengthargs_depths_ar+1inletpath=Path.makepath_lengthmkPathEndinletcurrent_ar_pos=ref0inletcurrent_user_depth=ref0inletcurrent_min_depth=refmax_intinletupdate_current_min_depthd=ifnotis_goalthencurrent_min_depth:=min!current_min_depthdin(* Invariant: !current_ar_pos < Array.length args_depths_ar *)letupdate_ardepth=ifnotis_goalthenbeginletold_max=Array.unsafe_getargs_depths_ar!current_ar_posinletcurrent_max=!current_user_depth-depthinifold_max<current_maxthenArray.unsafe_setargs_depths_ar!current_ar_poscurrent_maxendinletreclist_to_trie_path~safe~depth~hpath_depth(len:int)(t:term):unit=matchderef_head~depthtwith|Nil->Path.emitpathmkListEnd;update_current_min_depthpath_depth|Cons(a,b)->(* heuristic: we limit the size of the list to at most 30 *)(* this aims to control the width of the path, *)(* or equivalently the number of children of *)(* a specific node. *)(* for example, the term `app[1,...,100]` with depth 2, *)(* has the node `app` with arity `1` as first*)(* cell, then come the elment of the list *)(* up to the 30^th elemebt *)ifis_goal&&h>=max_list_length'then(Path.emitpathmkListTailVariableUnif;update_current_min_depthpath_depth)else(main~safe~depthapath_depth;list_to_trie_path~depth~safe~h:(h+1)path_depth(len+1)b)(* These cases can come from terms like `[_ | _]`, `[_ | A]` ... *)|UVar_|AppUVar_|Arg_|AppArg_|Discard->Path.emitpathmkListTailVariable;update_current_min_depthpath_depth(* One could write the following:
type f list int.
p [1,2,3,4 | f]. *)|App_|Const_->Path.emitpathmkListTailVariable;update_current_min_depthpath_depth|Builtin_|CData_|Lam_->type_error(Format.asprintf"[DT]: not a list: %a"(Pp.pptermdepth[]~argsdepth:0Data.empty_env)(deref_head~deptht))andemit_modeis_goalmode=ifis_goalthenPath.emitpathmode(** gives the path representation of a list of sub-terms *)andarg_to_trie_path_aux~safe~deptht_listpath_depth:unit=ifpath_depth=0thenupdate_current_min_depthpath_depthelsematcht_listwith|[]->update_current_min_depthpath_depth|hd::tl->main~safe~depthhdpath_depth;arg_to_trie_path_aux~safe~depthtlpath_depth(** gives the path representation of a term *)andmain~safe~depthtpath_depth:unit=ifpath_depth=0thenupdate_current_min_depthpath_depthelseifis_goal&&Path.get_builder_pospath>=path_lengththen(Path.emitpathmkAny;update_current_min_depthpath_depth)elseletpath_depth=path_depth-1inmatchderef_head~depthtwith|(Constk|App(k,_,_))whenk==Global_symbols.uvarc->Path.emitpathmkUvarConstant;update_current_min_depthpath_depth|Constkwhensafe->Path.emitpath@@mkConstant~safe~data:k~arity:0;update_current_min_depthpath_depth|Constk->Path.emitpath@@mkConstant~safe~data:k~arity:0;update_current_min_depthpath_depth|CDatad->Path.emitpath@@mkPrimitived;update_current_min_depthpath_depth|App(k,a,_)whenk==Global_symbols.asc->main~safe~depthapath_depth|Lam_->Path.emitpathmkAny;update_current_min_depthpath_depth(* loose indexing to enable eta *)|Arg_|UVar_|AppArg_|AppUVar_|Discard->Path.emitpath@@mkVariable;update_current_min_depthpath_depth|Builtin(k,tl)->Path.emitpath@@mkConstant~safe~data:(const_of_builtin_predicatek)~arity:(ifpath_depth=0then0elseList.lengthtl);arg_to_trie_path_aux~safe~depthtlpath_depth|App(k,x,xs)->letarg_length=ifpath_depth=0then0elseList.lengthxs+1inPath.emitpath@@mkConstant~safe~data:k~arity:arg_length;main~safe~depthxpath_depth;arg_to_trie_path_aux~safe~depthxspath_depth|Nil->Path.emitpathmkListNil;update_current_min_depthpath_depth|Cons(x,xs)->Path.emitpathmkListHead;main~safe~depthx(path_depth+1);list_to_trie_path~safe~depth~h:1(path_depth+1)0xs(** builds the sub-path of a sublist of arguments of the current clause *)andmake_sub_patharg_hdarg_tlarg_depth_hdarg_depth_tl(mode_hd:Mode.t)mode_tl=emit_modeis_goal(matchmode_hdwithInput->mkInputMode|_->mkOutputMode);beginifnotis_goalthenbegincurrent_user_depth:=arg_depth_hd;current_min_depth:=max_int;main~safe~deptharg_hdarg_depth_hd;update_ar!current_min_depth;endelsemain~safe~deptharg_hd(Array.unsafe_getargs_depths_ar!current_ar_pos)end;incrcurrent_ar_pos;aux~safe~depthis_goalarg_tlarg_depth_tlmode_tl(** main function: build the path of the arguments received in entry *)andaux~safe~depthis_goalargsarg_depthsmode=matchargs,arg_depths,modewith|_,[],_->()|arg_hd::arg_tl,arg_depth_hd::arg_depth_tl,(On|Off[])->(* overlap check:
func p int -> .
p 1.
p X.
we query the DT in output mode so that query p X finds p 1 *)make_sub_patharg_hdarg_tlarg_depth_hdarg_depth_tlOutputOn|arg_hd::arg_tl,arg_depth_hd::arg_depth_tl,Off(mode_hd::mode_tl)->make_sub_patharg_hdarg_tlarg_depth_hdarg_depth_tl(Mode.get_headmode_hd)(Offmode_tl)|_,_::_,_->anomaly"Invalid Index length"inbeginifargs==[]thenemit_modeis_goalmkOutputModeelseaux~safe~depthis_goalargs(ifis_goalthenArray.to_listargs_depths_arelsearg_depths)check_mut_exclend;Path.stoppathletmake_new_Map_snd_level_indexargnomode=TwoLevelIndex{argno;mode;all_clauses=Bl.empty();flex_arg_clauses=Bl.empty();arg_idx=Ptmap.empty;}letpath_for_dtree~depth~check_mut_exclargs_idxargs=letmax_depths=Discrimination_tree.max_depthsargs_idxinletmax_path=Discrimination_tree.max_pathargs_idxinletmax_list_length=max_lists_lengthargsinletarg_depths=Discrimination_tree.user_upper_bound_depthargs_idxin(* Format.printf "[%d] Going to index [%a]\n%!" max_list_length (pplist pp_int ",") arg_depths; *)letpath=arg_to_trie_path~depth~safe:true~is_goal:falseargsarg_depthsmax_depths~check_mut_exclmax_pathmax_list_lengthin(* Format.eprintf "Path is %a@." Discrimination_tree.Path.pp path; *)path,max_list_length,max_depthsletadd_clause_to_snd_lvl_idx~depth~insertpredicateclause=function|TwoLevelIndex{all_clauses;argno;mode;flex_arg_clauses;arg_idx;}->beginmatchclassify_clause_argno~depthargnomodeclause.argswith|Variable->(* X: matches both rigid and flexible terms *)TwoLevelIndex{argno;mode;all_clauses=insertclauseall_clauses;flex_arg_clauses=insertclauseflex_arg_clauses;arg_idx=Ptmap.map(funl_rev->insertclausel_rev)arg_idx;}|MustBeVariable->(* uvar: matches only flexible terms (or itself at the meta level) *)letclauses=tryPtmap.findmustbevariablecarg_idxwithNot_found->Bl.empty()inTwoLevelIndex{argno;mode;all_clauses=insertclauseall_clauses;flex_arg_clauses;arg_idx=Ptmap.addmustbevariablec(insertclauseclauses)arg_idx;}|Rigid(arg_hd,arg_mode)->(* t: a rigid term matches flexible terms only in unification mode *)letclauses=tryPtmap.findarg_hdarg_idxwithNot_found->flex_arg_clausesinletall_clauses=ifarg_mode=Inputthenall_clauseselseinsertclauseall_clausesinTwoLevelIndex{argno;mode;all_clauses;flex_arg_clauses;arg_idx=Ptmap.addarg_hd(insertclauseclauses)arg_idx;}end|BitHash{mode;args;args_idx}->lethash=hash_clause_arg_listpredicate~depthclause.argsmodeargsinletclauses=tryPtmap.findhashargs_idxwithNot_found->Bl.empty()inBitHash{mode;args;args_idx=Ptmap.addhash(insertclauseclauses)args_idx}|IndexWithDiscriminationTree{mode;arg_depths;args_idx;}->letpath,max_list_length,max_depths=path_for_dtree~depth~check_mut_excl:(Offmode)args_idxclause.argsin[%spy"dev:disc-tree:depth-path"~ridpp_string"Inst: MaxDepths "(pplistpp_int"")(Array.to_listmax_depths)];IndexWithDiscriminationTree{mode;arg_depths;args_idx=Discrimination_tree.indexargs_idxpathclause~max_list_length}letcompile_time_tickx=x+1letrun_time_tickx=x-1letrecadd1clause_runtime~depth{idx;time;times}predicateclause=tryletsnd_lvl_idx=Ptmap.findpredicateidxinlettime=run_time_ticktimeinclause.timestamp<-[time];letsnd_lvl_idx=add_clause_to_snd_lvl_idx~depth~insert:Bl.conspredicateclausesnd_lvl_idxin{times;time;idx=Ptmap.addpredicatesnd_lvl_idxidx}with|Not_found->(* Unknown predicate, we could detect this statically and forbid it *)letidx=Ptmap.addpredicate(make_new_Map_snd_level_index0[])idxinadd1clause_runtime~depth{idx;time;times}predicateclauseletadd_clauses~depthclausesidx=(* pplist (fun fmt (hd, b) -> ppclause fmt hd b) ";" Fmt.std_formatter clauses; *)(* let t1 = Unix.gettimeofday () in *)letidx=List.fold_left(funm(p,c)->add1clause_runtime~depthmpc)idxclausesin(* let t2 = Unix.gettimeofday () in *)(* pp_string Fmt.std_formatter (Printf.sprintf "\nTime taken by add_clauses is %f\n" (t2-.t1)); *)idxletadd_clauses~depthclausesclauses_src{index;src}={index=add_clauses~depthclausesindex;src=List.revclauses_src@src}letadd_to_timeslocnametimepredicatetimes=matchnamewith|None->times|Someid->ifStrMap.memidtimesthenerror?loc("duplicate clause name "^id)elseStrMap.addid(time,predicate)timeslettime_oflocxtimes=tryStrMap.findxtimeswithNot_found->error?loc("cannot graft, clause "^x^" not found")letremove_from_timesidtimes=StrMap.removeidtimesletremove_clause_in_snd_lvl_idxp=function|TwoLevelIndex{argno;mode;all_clauses;flex_arg_clauses;arg_idx;}->TwoLevelIndex{argno;mode;all_clauses=Bl.removepall_clauses;flex_arg_clauses=Bl.removepflex_arg_clauses;arg_idx=Ptmap.map(Bl.removep)arg_idx;}|BitHash{mode;args;args_idx}->BitHash{mode;args;args_idx=Ptmap.map(Bl.removep)args_idx}|IndexWithDiscriminationTree{mode;arg_depths;args_idx;}->IndexWithDiscriminationTree{mode;arg_depths;args_idx=Discrimination_tree.removepargs_idx;}lethas_bang(t:termlist):bool=letrecauxt=matchtwith|[]->false|Builtin(Cut,[])::_->true|Builtin(Pi,[Lamb])::xs|Builtin(Sigma,[Lamb])::xs->aux[b]||auxxs|Builtin(Impl,[h;l])::xs->aux[l]||auxxs|Builtin(And,l)::xs->auxl||auxxs|_::xs->auxxsinauxtletadd1clause_overlap_runtime~depth(idx:pred_infoC.Map.t)predicate~time(clause:clause)=matchC.Map.findpredicateidxwith|{overlap=Allowed}->None,idx|{overlap=Forbiddendt}aspred_info->clause.timestamp<-[time];letpath,max_list_length,max_depths=path_for_dtree~depth~check_mut_excl:(Offpred_info.mode)dtclause.argsinletcl_overlap={overlap_loc=clause.loc;has_cut=has_bangclause.hyps;timestamp=clause.timestamp;arg_nb=List.lengthclause.args}inletdt=Discrimination_tree.indexdt~max_list_lengthpathcl_overlapinSomecl_overlap,C.Map.addpredicate({pred_infowithoverlap=Forbiddendt})idx|exceptionNot_found->None,idxletupdate_overlap~det_checkoverlap~depthindexclause=matchdet_checkwith|None->None,overlap|Sometime->lett0=Unix.gettimeofday()inletrc=matchoverlap.overlapwith|Allowed->None,overlap|Forbiddendt->letarg_depths,mode=matchindexwith|TwoLevelIndex{mode;argno}->List.init(argno+1)(funj->ifj=argno-1then1else0),mode|BitHash{mode;args=arg_depths}->arg_depths,mode|IndexWithDiscriminationTree{mode;arg_depths}->arg_depths,modeinletpath,max_list_length,max_depths=path_for_dtree~depth~check_mut_excl:(Offmode)dtclause.argsinlethas_cut=has_bangclause.hypsinletarg_nb=List.lengthclause.argsinletoverlap_clause={overlap_loc=clause.loc;has_cut;timestamp=clause.timestamp;arg_nb}inletdt=Discrimination_tree.indexdtpathoverlap_clause~max_list_lengthinSomeoverlap_clause,{overlapwithoverlap=Forbiddendt}inlett1=Unix.gettimeofday()intime:=!time+.(t1-.t0);rcletrecadd1clause_compile_time~det_check~depth{idx;time;times}overlap~graftpredicateclausename=tryletsnd_lvl_idx=Ptmap.findpredicateidxinlettime=compile_time_ticktimeinmatchgraftwith|None->lettimestamp=[time]inlettimes=add_to_timesclause.locnametimestamppredicatetimesinclause.timestamp<-timestamp;letsnd_lvl_idx=add_clause_to_snd_lvl_idx~depth~insert:Bl.rconspredicateclausesnd_lvl_idxin{times;time;idx=Ptmap.addpredicatesnd_lvl_idxidx},update_overlap~det_checkoverlap~depthsnd_lvl_idxclause|Some(Ast.Structured.Removex)->letreference,predicate1=time_ofclause.locxtimesinifpredicate1<>predicatethenerror?loc:clause.loc("cannot remove a clause for another predicate");lettimes=remove_from_timesxtimesinclause.timestamp<-reference;letsnd_lvl_idx=remove_clause_in_snd_lvl_idx(funx->x.timestamp=reference)snd_lvl_idxin{times;time;idx=Ptmap.addpredicatesnd_lvl_idxidx},(None,overlap)|Some(Ast.Structured.Replacex)->letreference,predicate1=time_ofclause.locxtimesinifpredicate1<>predicatethenerror?loc:clause.loc("cannot replace a clause for another predicate");lettimes=remove_from_timesxtimesinclause.timestamp<-reference;letsnd_lvl_idx=remove_clause_in_snd_lvl_idx(funx->x.timestamp=reference)snd_lvl_idxinletsnd_lvl_idx=add_clause_to_snd_lvl_idx~depth~insert:Bl.(insert(funx->lex_insertionx.timestampreference))predicateclausesnd_lvl_idxin{times;time;idx=Ptmap.addpredicatesnd_lvl_idxidx},update_overlap~det_checkoverlap~depthsnd_lvl_idxclause|Some(Ast.Structured.Insertgr)->lettimestamp=matchgrwith|Ast.Structured.Beforex->(fst@@time_ofclause.locxtimes)@[-time]|Ast.Structured.Afterx->(fst@@time_ofclause.locxtimes)@[+time]inlettimes=add_to_timesclause.locnametimestamppredicatetimesinclause.timestamp<-timestamp;letsnd_lvl_idx=add_clause_to_snd_lvl_idx~depth~insert:Bl.(insert(funx->lex_insertionx.timestamptimestamp))predicateclausesnd_lvl_idxin{times;time;idx=Ptmap.addpredicatesnd_lvl_idxidx},update_overlap~det_checkoverlap~depthsnd_lvl_idxclausewithNot_found->letidx=Ptmap.addpredicate(make_new_Map_snd_level_index0[])idxinadd1clause_compile_time~det_check~depth{idx;time;times}overlap~graftpredicateclausenameletupdate_indexing(indexing:pred_infoConstants.Map.t)(index:index):index=letidx=C.Map.fold(funpredicate({mode;indexing})m->Ptmap.addpredicatebeginmatchindexingwith|Hashargs->BitHash{args;mode;args_idx=Ptmap.empty;}|MapOnargno->make_new_Map_snd_level_indexargnomode|DiscriminationTreearg_depths->IndexWithDiscriminationTree{arg_depths;mode;args_idx=Discrimination_tree.empty_dtarg_depths;}endm)indexingindex.idxin{indexwithidx}letadd_to_index_compile_time~det_check~depth~predicate~graftclausenameindexoverlap_index=add1clause_compile_time~det_check~depth~graftindexoverlap_indexpredicateclausenameletmake_empty_index~depth~indexing=letindex=update_indexingindexing{idx=Ptmap.empty;time=0;times=StrMap.empty}inletindex=close_indexindexin{index;src=[]}typegoal_arg_classification=|Variable|Rigidofconstantletrecclassify_goal_arg~deptht=(* Format.eprintf "goal %a\n%!" (ppterm depth [] ~argsdepth:depth empty_env) t; *)matchderef_head~depthtwith|Constkwhenk==Global_symbols.uvarc->Rigidmustbevariablec|Constk->Rigid(k)|Nil->Rigid(Global_symbols.nilc)|Cons_->Rigid(Global_symbols.consc)|App(k,_,_)whenk==Global_symbols.uvarc->Rigidmustbevariablec|App(k,a,_)whenk==Global_symbols.asc->classify_goal_arg~deptha|App(k,_,_)->Rigid(k)|Builtin(k,_)->Rigid(const_of_builtin_predicatek)|Lamt->classify_goal_arg~depth:(depth+1)t(* eta *)|Arg_|UVar_|AppArg_|AppUVar_|Discard->Variable|CDatad->lethash=-(CData.hashd)inifhash>mustbevariablecthenRigid(hash)elseRigid(hash+1)letclassify_goal_argno~depthargno=function|Const_->Variable|App(_,x,_)whenargno==0->classify_goal_arg~depthx|App(_,_,xs)->letx=tryList.nthxs(argno-1)withInvalid_argument_->type_error("The goal is not applied enough")inclassify_goal_arg~depthx|_->assertfalselethash_goal_args~depthmodeargsgoal=matchgoalwith|Const_->0|App(k,x,xs)->hash_goal_arg_listk~depth(x::xs)modeargs|_->assertfalselettrie_goal_argsgoal:termlist=matchgoalwith|Const_->[]|App(_,x,xs)->x::xs|_->assertfalseletcmp_timestamp{timestamp=tx}{timestamp=ty}=lex_insertiontxtyletget_clauses_dt~(check_mut_excl:check_mut_excl)~depthgoal~cmp_clause~pp_clauseargs_idx=letmax_depths=Discrimination_tree.max_depthsargs_idxinletmax_path=Discrimination_tree.max_pathargs_idxinletmax_list_length=Discrimination_tree.max_list_lengthargs_idxinletarg_depths=Discrimination_tree.user_upper_bound_depthargs_idxin(* Format.eprintf "Args depths is [%a]@." (pplist pp_int "-- ") arg_depths; *)letpath=arg_to_trie_path~check_mut_excl~safe:false~depth~is_goal:true(trie_goal_argsgoal)arg_depthsmax_depthsmax_pathmax_list_lengthin[%spy"dev:disc-tree:depth-path"~ridpp_string"Goal: MaxDepths "(pplistpp_int";")(Array.to_listmax_depths)];[%spy"dev:disc-tree:list-size-path"~ridpp_string"Goal: MaxListSize "pp_intmax_list_length];(* Format.(printf "Goal: MaxDepth is %a\n" (pp_print_list ~pp_sep:(fun fmt _ -> pp_print_string fmt " ") pp_print_int) (Discrimination_tree.max_depths args_idx |> Array.to_list)); *)[%spy"dev:disc-tree:path"~ridDiscrimination_tree.Path.pppath(pplistpp_int";")arg_depths(*Discrimination_tree.(pp (fun fmt x -> pp_string fmt "+")) args_idx*)];(* Format.eprintf "@[<hov 2>Path is@ @[%a@]]@." Discrimination_tree.Path.pp path;
Format.eprintf "@[<hov 2>Discrimination tree is@ @[%a@]@." (Discrimination_tree.pp pp_clause) args_idx; *)(* Format.eprintf "@[<hov 4>Going to retrieve with %a, path is@ %a -- goal is@ %a@]@." pp_check_mut_excl check_mut_excl Discrimination_tree.Path.pp path (uppterm 0 [] [||] ~argsdepth:0) goal; *)letcandidates=Discrimination_tree.retrievecmp_clausepathargs_idxin(* Format.eprintf "Candidates len is %d -->@ @[[%a]@]@." (Bl.length candidates) (pplist pp_clause ",@.") (Bl.to_list candidates); *)[%spy"dev:disc-tree:candidates"~ridpp_int(Bl.lengthcandidates)];candidatesletget_clauses~depthpredicategoal{idx=m}=letrc=trymatchPtmap.findpredicatemwith|TwoLevelIndex{all_clauses;argno;mode;flex_arg_clauses;arg_idx}->beginmatchclassify_goal_argno~depthargnogoalwith|Variable->all_clauses|Rigidarg_hd->tryPtmap.findarg_hdarg_idxwithNot_found->flex_arg_clausesend|>Bl.to_scan|BitHash{args;mode;args_idx}->lethash=hash_goal_args~depthmodeargsgoalinletcl=Ptmap.find_unifiableshashargs_idx|>List.mapBl.to_scan|>List.mapBl.to_list|>List.flatteninBl.of_list@@List.sortcmp_timestampcl|IndexWithDiscriminationTree{arg_depths;mode;args_idx}->get_clauses_dt~check_mut_excl:(Offmode)~cmp_clause:cmp_timestamp~pp_clause:pp_clause~depthgoalargs_idxwithNot_found->Bl.of_list[]in[%log"get_clauses"~rid(C.showpredicate)(Bl.lengthrc)];[%spy"dev:get_clauses"~ridC.pppredicatepp_int(Bl.lengthrc)];rcletlocal_prog{src}=srcend(* }}} *)openIndexing(* Used to pass the program to the CHR runtime *)letorig_prolog_program=Fork.new_local(make_empty_index~depth:0~indexing:C.Map.empty)(******************************************************************************
Dynamic Prolog program
******************************************************************************)moduleClausify:sigvalclausify:tail_cut:bool->loc:Loc.toption->prolog_prog->depth:int->term->(constant*clause)list*clause_srclist*intvalclausify1:tail_cut:bool->loc:Loc.t->modes:(constant->Mode.hos)->nargs:int->depth:int->term->(constant*clause)*clause_src*int(* Utilities that deref on the fly *)vallp_list_to_list:depth:int->term->termlistvalget_lambda_body:depth:int->term->termvalsplit_conj:depth:int->term->termlistend=struct(* {{{ *)letrecsplit_conj~depth=function|Builtin(And,hd::args)->split_conj~depthhd@List.(flatten(map(split_conj~depth)args))|Nil->[]|Cons(x,xs)->split_conj~depthx@split_conj~depthxs|UVar({contents=g}asr,args)wheng!=C.dummy->split_conj~depth(deref_uv~to_:depthrargs)|AppUVar({contents=g}asr,args)wheng!=C.dummy->split_conj~depth(deref_appuv~to_:depthrargs)|Discard->[]|_asf->[f];;letreclp_list_to_list~depth=function|Cons(hd,tl)->hd::lp_list_to_list~depthtl|Nil->[]|UVar({contents=g}asr,args)wheng!=C.dummy->lp_list_to_list~depth(deref_uv~to_:depthrargs)|AppUVar({contents=g}asr,args)wheng!=C.dummy->lp_list_to_list~depth(deref_appuv~to_:depthrargs)|x->error(Fmt.sprintf"%s is not a list"(show_termx));;letrecget_lambda_body~depth=function|UVar({contents=g}asr,args)wheng!=C.dummy->get_lambda_body~depth(deref_uv~to_:depthrargs)|AppUVar({contents=g}asr,args)wheng!=C.dummy->get_lambda_body~depth(deref_appuv~to_:depthrargs)|Lamb->b|_->error"pi/sigma applied to something that is not a Lam";;(* BUG: the following clause is rejected because (Z c d) is not
in the fragment. However, once X and Y becomes arguments, (Z c d)
enters the fragment.
r :- (pi X\ pi Y\ q X Y :- pi c\ pi d\ q (Z c d) (X c d) (Y c)) => ... *)(* Takes the source of an implication and produces the clauses to be added to
* the program and the number of existentially quantified constants turned
* into globals.
*
* Invariants:
* - lts is the number of lambdas crossed and it is always = List.length ts
* - lcs is the number of new constants to be generated because a sigma
* has been crossed
* - the argument lives in (depth+lts)
* - the clause will live in (depth+lcs)
*)letrecclaux1locget_modevarsdepthhypstsltslcst=[%trace"clausify"~rid("%a %d %d %d %d\n%!"(ppterm(depth+lts)[]~argsdepth:0empty_env)tdepthltslcs(List.lengthts))beginmatchtwith|Discard->error?loc"ill-formed hypothetical clause: discard in head position"|Builtin(RImpl,[g2;g1])->claux1locget_modevarsdepth((ts,g1)::hyps)tsltslcsg2|Builtin(RImpl,[])->error?loc"ill-formed hypothetical clause: :-"|Builtin(Impl,[g1;g2])->claux1locget_modevarsdepth((ts,g1)::hyps)tsltslcsg2|Builtin(Impl,[])->error?loc"ill-formed hypothetical clause: =>"|Builtin(Sigma,[arg])->letb=get_lambda_body~depth:(depth+lts)arginletargs=List.rev(List.filter(function(Arg_)->true|_->false)ts)inletcst=matchargswith[]->Const(depth+lcs)|hd::rest->App(depth+lcs,hd,rest)inclaux1locget_modevarsdepthhyps(cst::ts)(lts+1)(lcs+1)b|Builtin(Pi,[arg])->letb=get_lambda_body~depth:(depth+lts)arginclaux1locget_mode(vars+1)depthhyps(Arg(vars,0)::ts)(lts+1)lcsb|Builtin(And,_)->error?loc"Conjunction in the head of a clause is not supported"|Const_|App_asg->lethyps=List.(flatten(rev_map(fun(ts,g)->letg=hmove~from:(depth+lts)~to_:(depth+lts+lcs)ginletg=substdepthtsginsplit_conj~depth:(depth+lcs)g)hyps))inletg=hmove~from:(depth+lts)~to_:(depth+lts+lcs)ginletg=substdepthtsgin(* Fmt.eprintf "@[<hov 1>%a@ :-@ %a.@]\n%!"
(ppterm (depth+lcs) [] ~argsdepth:0 empty_env) g
(pplist (ppterm (depth+lcs) [] ~argsdepth:0 empty_env) " , ")
hyps ;*)lethd,args=matchgwithConsth->h,[]|App(h,x,xs)->h,x::xs|UVar_|AppUVar_|Arg_|AppArg_|Discard->raiseFlex_head|Lam_->type_error?loc"The head of a clause cannot be a lambda abstraction"|Builtin(c,_)->raise@@CannotDeclareClauseForBuiltin(loc,c)|CData_->type_error?loc"The head of a clause cannot be a builtin data type"|Cons_|Nil->assertfalseinletc={depth=depth+lcs;args;hyps;mode=get_modehd;vars;loc;timestamp=[];oc=true}in[%spy"dev:claudify:extra-clause"~rid(ppclause~hd)c];(hd,c),{hdepth=depth;hsrc=g},lcs|UVar({contents=g}asr,args)wheng!=C.dummy->claux1locget_modevarsdepthhypstsltslcs(deref_uv~to_:(depth+lts)rargs)|AppUVar({contents=g}asr,args)wheng!=C.dummy->claux1locget_modevarsdepthhypstsltslcs(deref_appuv~to_:(depth+lts)rargs)|Arg_|AppArg_->raiseFlex_head|Builtin(c,_)->raise@@CannotDeclareClauseForBuiltin(loc,c)|(Lam_|CData_)asx->type_error?loc("Assuming a string or int or float or function:"^show_termx)|UVar_|AppUVar_->raiseFlex_head|Nil|Cons_->error?loc"ill-formed hypothetical clause: [] / ::"end]letadd_tail_cut~tail_cut=iftail_cutthen[[],Builtin(Cut,[])]else[]letclausify~tail_cut~loc{index={idx=index}}~deptht=letget_modex=matchPtmap.findxindexwith|TwoLevelIndex{mode}->mode|BitHash{mode}->mode|IndexWithDiscriminationTree{mode}->mode|exceptionNot_found->[]inletl=split_conj~depthtinletclauses,program,lcs=List.fold_left(fun(clauses,programs,lcs)t->letclause,program,lcs=tryclaux1locget_mode0depth(add_tail_cut~tail_cut)[]0lcstwith|Flex_head->error?loc"The head of a clause cannot be flexible"|CannotDeclareClauseForBuiltin(loc,c)->error?loc("Declaring a clause for built in predicate "^show_builtin_predicateC.showc)inclause::clauses,program::programs,lcs)([],[],0)linclauses,program,lcs;;letclausify1~tail_cut~loc~modes~nargs~deptht=claux1(Someloc)modesnargsdepth(add_tail_cut~tail_cut)[]00tend(* }}} *)openClausify(******************************************************************************
Choice stack
******************************************************************************)typegoal={depth:int;program:prolog_prog;goal:term;gid:UUID.t[@trace]}letmake_subgoal_idogid((depth,goal)[@trace])=letgid=UUID.make()in[%spy"user:subgoal"~rid~gid:ogidUUID.ppgid];[%spy"user:newgoal"~rid~gid(upptermdepth[]~argsdepth:0empty_env)goal];gid[@@inline][@@warning"-32"]letmake_subgoal(gid[@trace])~depthprogramgoal=letgid[@trace]=make_subgoal_idgid((depth,goal)[@trace])in{depth;program;goal;gid=gid[@trace]}[@@inline]letrepack_goal(gid[@trace])~depthprogramgoal={depth;program;goal;gid=gid[@trace]}[@@inline](* The activation frames points to the choice point that
cut should backtrack to, i.e. the first one not to be
removed. We call it catto_alts in the code. *)typeframe=|FNil|FConsof(*lvl:*)alternative*goallist*frameandalternative={cutto_alts:alternative;program:prolog_prog;adepth:int;agoal_hd:constant;ogoal_arg:term;ogoal_args:termlist;agid:UUID.t;[@trace]goals:goallist;stack:frame;trail:T.trail;state:State.t;clauses:clauseBl.scan;next:alternative;}letnoalts:alternative=Obj.magic(Sys.opaque_identity0)(******************************************************************************
Constraint propagation
******************************************************************************)(* A runtime is a function to search for the first solution to the query
* plus a function to find the next one.
* The low level part of the runtime give access to the runtime memory.
* One can for example execute code before starting the runtime and such
* code may have effects "outside" the runtime that are trailed. The destroy
* function takes care of cleaning up the mess.
*
* The supported workflow is
* exec optional, many times
* search mandatory, 1 time
* next optional, repeat until No_clause is thrown
* destroy optional, 1 time, useful in nested runtimes
*)typeruntime={search:unit->alternative;next_solution:alternative->alternative;(* low level part *)destroy:unit->unit;exec:'a'b.('a->'b)->'a->'b;get:'a.'aFork.local_ref->'a;}letdo_make_runtime:(?max_steps:int->?delay_outside_fragment:bool->executable->runtime)ref=ref(fun?max_steps?delay_outside_fragment_->anomaly"do_make_runtime not initialized")moduleConstraints:sigtypenew_csts={new_goals:goallist;some_rule_was_tried:bool;[@trace]}valpropagation:unit->new_cstsvalresumption:constraint_deflist->goallistvalchrules:CHR.tFork.local_ref(* out of place *)valexect_builtin_predicate:once:(depth:int->term->State.t->State.t)->constant->depth:int->prolog_prog->(UUID.t[@trace])->termlist->termlistvaldeclare_constraint:depth:constant->prolog_prog->(UUID.t[@trace])->termlist->unitend=struct(* {{{ *)typenew_csts={new_goals:goallist;some_rule_was_tried:bool;[@trace]}exceptionNoMatchmoduleIce:sigtypefreezervalempty_freezer:freezer(* The input term lives in depth, the sequent lives in ground
* (the same as depth for the goal, while >= for ctx items)
*
* shift = relocate only bound variables
* relocate = increment all db indexes
*
* The input term is fully dereferenced, flexible terms are frozen,
* it is shifted to its ground, then relocated to new base, then
* shifted to the maxbase
*)valfreeze:depth:int->term->ground:int->newground:int->maxground:int->freezer->freezer*termvaldefrost:from:int->term->env->to_:int->map:constantC.Map.t->freezer->termvalassignments:freezer->assignmentlistend=struct(* {{{ *)typefreezer={c2uv:uvarC.Map.t;uv2c:(uvar*term)list;assignments:assignmentlist;(* assignment to lower the level to 0 *)}letempty_freezer={c2uv=C.Map.empty;uv2c=[];assignments=[]}letfreeze~deptht~ground~newground~maxgroundf=letf=reffinletlog_assignment=function|t,None->t|t,Some(r,ntass)->f:={!fwithassignments=s::!f.assignments};r@::==nt;tinletfreeze_uvr=assert(r.vardepth=0);tryList.assqr!f.uv2cwithNot_found->letn,c=C.fresh_global_constant()in[%spy"dev:freeze_uv:new"~rid(funfmt()->lettt=UVar(r,0)inFmt.fprintffmt"%s == %a"(C.shown)(ppterm0[]~argsdepth:0empty_env)tt)()];f:={!fwithc2uv=C.Map.addnr!f.c2uv;uv2c=(r,c)::!f.uv2c};cinletrecfauxd=function|(Const_|CData_|Nil|Discard)asx->x|Cons(hd,tl)asorig->lethd'=fauxdhdinlettl'=fauxdtlinifhd==hd'&&tl==tl'thenorigelseCons(hd',tl')|App(c,x,xs)asorig->letx'=fauxdxinletxs'=smart_map(fauxd)xsinifx==x'&&xs==xs'thenorigelseApp(c,x',xs')|Builtin(c,args)asorig->letargs'=smart_map(fauxd)argsinifargs==args'thenorigelseBuiltin(c,args')|(Arg_|AppArg_)->error"only heap terms can be frozen"|Lamtasorig->lett'=faux(d+1)tinift==t'thenorigelseLamt'(* deref *)|UVar(r,ano)when!!r!=C.dummy->fauxd(deref_uv~to_:drano)|AppUVar(r,args)when!!r!=C.dummy->fauxd(deref_appuv~to_:drargs)(* freeze *)|AppUVar(r,args)whenr.vardepth==0->letargs=smart_map(fauxd)argsinApp(Global_symbols.uvarc,freeze_uvr,[list_to_lp_listargs])(* expansion *)|UVar(r,ano)->fauxd(log_assignment(expand_uv~depth:dr~ano))|AppUVar(r,args)->fauxd(log_assignment(expand_appuv~depth:dr~args))in[%spy"dev:freeze:in"~rid(funfmt()->Fmt.fprintffmt"depth:%d ground:%d newground:%d maxground:%d %a"depthgroundnewgroundmaxground(upptermdepth[]~argsdepth:0empty_env)t)()];lett=fauxdepthtin[%spy"dev:freeze:after-faux"~rid(upptermdepth[]~argsdepth:0empty_env)t];lett=shift_bound_vars~depth~to_:groundtin[%spy"dev:freeze:after-shift->ground"~rid(upptermground[]~argsdepth:0empty_env)t];lett=shift_bound_vars~depth:0~to_:(newground-ground)tin[%spy"dev:freeze:after-reloc->newground"~rid(upptermnewground[]~argsdepth:0empty_env)t];lett=shift_bound_vars~depth:newground~to_:maxgroundtin[%spy"dev:freeze:out"~rid(upptermmaxground[]~argsdepth:0empty_env)t];!f,tletdefrost~fromtenv~to_~mapf=[%spy"dev:defrost:in"~rid(funfmt()->Fmt.fprintffmt"from:%d to:%d %a"fromto_(upptermfrom[]~argsdepth:fromenv)t)()];lett=full_deref~adepth:fromenv~depth:fromtin[%spy"dev:defrost:fully-derefd"~rid(funfmt()->Fmt.fprintffmt"from:%d to:%d %a"fromto_(upptermfrom[]~argsdepth:0empty_env)t)()];lett=map_free_vars~map~depth:from~to_tin[%spy"dev:defrost:shifted"~rid(funfmt()->Fmt.fprintffmt"from:%d to:%d %a"fromto_(upptermto_[]~argsdepth:0empty_env)t)()];letfresh_uv=refIntMap.emptyinletmk_fresh_uv_forr=letuid=uvar_idrintryIntMap.finduid!fresh_uvwithNot_found->letr'=oref~depth:0C.dummyinfresh_uv:=IntMap.adduidr'!fresh_uv;r'inletrecdauxd=function|ConstcwhenC.Map.memcf.c2uv->UVar(C.Map.findcf.c2uv,0)|(Const_|CData_|Nil|Discard)asx->x|Cons(hd,tl)asorig->lethd'=dauxdhdinlettl'=dauxdtlinifhd==hd'&&tl==tl'thenorigelseCons(hd',tl')|App(c,UVar(r,ano),a)when!!r!=C.dummy->dauxd(App(c,deref_uv~to_:drano,a))|App(c,AppUVar(r,args),a)when!!r!=C.dummy->dauxd(App(c,deref_appuv~to_:drargs,a))|App(c,Constx,[args])whenc==Global_symbols.uvarc->letr=C.Map.findxf.c2uvinletargs=lp_list_to_list~depth:dargsinmkAppUVarr(smart_map(dauxd)args)|App(c,UVar(r,0),[args])whenc==Global_symbols.uvarc->letargs=lp_list_to_list~depth:dargsinletr'=mk_fresh_uv_forrinmkAppUVarr'(smart_map(dauxd)args)|App(c,AppUVar(r,_),[args])whenc==Global_symbols.uvarc->letargs=lp_list_to_list~depth:dargsinletr'=mk_fresh_uv_forrinmkAppUVarr'(smart_map(dauxd)args)|App(c,x,xs)asorig->letx'=dauxdxinletxs'=smart_map(dauxd)xsinifx==x'&&xs==xs'thenorigelseApp(c,x',xs')|Builtin(c,args)asorig->letargs'=smart_map(dauxd)argsinifargs==args'thenorigelseBuiltin(c,args')|Arg(i,ano)whenenv.(i)!=C.dummy->dauxd(deref_arg~from:to_~to_:denv.(i)ano)|AppArg(i,args)whenenv.(i)!=C.dummy->dauxd(deref_apparg~from:to_~to_:denv.(i)args)|(Arg(i,_)|AppArg(i,_))asx->env.(i)<-UVar(oref~depth:to_C.dummy,0);dauxdx|Lamtasorig->lett'=daux(d+1)tinift==t'thenorigelseLamt'|UVar_asx->x|AppUVar(r,args)asorig->letargs'=smart_map(dauxd)argsinifargs==args'thenorigelseAppUVar(r,args')indauxto_tletassignments{assignments}=assignmentsend(* }}} *)letmatch_goal(gid[@trace])goalnomaxgroundenvfreezer(newground,depth,t)pattern=letfreezer,t=Ice.freeze~deptht~ground:depth~newground~maxgroundfreezerin[%trace"match_goal"~rid("@[<hov>%a ===@ %a@]"(upptermmaxground[]~argsdepth:maxgroundenv)t(uppterm0[]~argsdepth:maxgroundenv)pattern)beginifunif~oc:true~argsdepth:maxground~matching:false(gid[@trace])maxgroundenv0tpatternthenfreezerelseraiseNoMatchend]letmatch_context(gid[@trace])goalnomaxgroundenvfreezer(newground,ground,lt)pattern=ifpattern==Discardthenfreezerelseletfreezer,lt=map_acc(funfreezer{hdepth=depth;hsrc=t}->Ice.freeze~deptht~ground~newground~maxgroundfreezer)freezerltinlett=list_to_lp_listltin[%trace"match_context"~rid("@[<hov>%a ===@ %a@]"(upptermmaxground[]~argsdepth:maxgroundenv)t(uppterm0[]~argsdepth:maxgroundenv)pattern)beginifunif~oc:true~argsdepth:maxground~matching:false(gid[@trace])maxgroundenv0tpatternthenfreezerelseraiseNoMatchend](* To avoid matching the same propagation rule against the same ordered list
* of constraints *)typechrattempt={propagation_rule:CHR.rule;constraints:constraint_deflist}moduleHISTORY=Hashtbl.Make(structtypet=chrattemptlethash=Hashtbl.hashletequal{propagation_rule=p;constraints=lp}{propagation_rule=p';constraints=lp'}=p==p'&&for_all2(==)lplp'end)letchrules=Fork.new_localCHR.emptyletmake_constraint_def~rid~gid:(gid[@trace])depthprogpdiffconclusion={cdepth=depth;prog=prog;context=pdiff;cgid=gid[@trace];conclusion}letdelay_goal?(filter_ctx=fun_->true)~depthprog~goal:g(gid[@trace])~on:keys=letpdiff=local_progproginletpdiff=List.filterfilter_ctxpdiffinletgid[@trace]=make_subgoal_idgid(depth,g)inletkind=Constraint(make_constraint_def~rid~gid:(gid[@trace])depthprogpdiffg)inCS.declare_new{kind;blockers=keys};;letrechead_of=function|Constx->x|Builtin(Pi,[Lamf])->head_off|Builtin(RImpl,hd::_)->head_ofhd|Builtin(And,hd::_)->head_ofhd(* FIXME *)|App(x,_,_)->x|Builtin(x,_)->const_of_builtin_predicatex|AppUVar(r,_)|UVar(r,_)when!!r!=C.dummy->head_of!!r|CData_->type_error"A constraint cannot be a primitive data"|Cons(x,_)->head_ofx|Nil->type_error"A constraint cannot be a list"|(UVar_|AppUVar_)->type_error"A constraint cannot have flexible head"|(Arg_|AppArg_)->anomaly"head_of on non-heap term"|Discard->type_error"A constraint cannot be _"|Lam_->type_error"A constraint cannot be a function"letdeclare_constraint~depthprog(gid[@trace])args=letg,keys=matchargswith|t1::more->leterrt="The Key arguments of declare_constraint must be variables or list of variables. Got: "^show_termtinletreccollect_keyst=matchderef_head~depthtwith|UVar(r,_)|AppUVar(r,_)->[r]|Discard->[dummy_uvar_body]|Lam_->beginmatchHO.eta_contract_flex~depthtwith|None->type_error(errt)|Somet->collect_keystend|_->type_error(errt)andcollect_keys_listt=matchderef_head~depthtwith|Nil->[]|Cons(hd,tl)->collect_keyshd@collect_keys_listtl|x->collect_keysxint1,List.flatten(List.mapcollect_keys_listmore)|_->type_error"declare_constraint takes at least one argument"inmatchCHR.clique_of(head_ofg)!chruleswith|Some(clique,ctx_filter)->(* real constraint *)(* XXX head_of is weak because no clausify ? XXX *)delay_goal~filter_ctx:(fun{hsrc=x}->C.Set.mem(head_ofx)clique||C.Set.mem(head_ofx)ctx_filter)~depthprog~goal:g(gid[@trace])~on:keys|None->delay_goal~depthprog~goal:g(gid[@trace])~on:keysletexect_builtin_predicate~oncec~depthidx(gid[@trace])args=letb=tryFFI.lookupcwithNot_found->anomaly("no built-in predicated named "^C.showc)inletconstraints=!CS.Ugly.delayedinletstate=!CS.stateinletstate,gs=FFI.callb~once~depth(local_progidx)constraintsstateargsinletstate,gs=State.getData.Conversion.extra_goals_postprocessingstategsstateinCS.state:=state;List.mapData.Conversion.term_of_extra_goalgs;;letmatch_head{conclusion=x;cdepth}p=matchderef_head~depth:cdepthxwith|Constx->x==p|App(x,_,_)->x==p|_->false;;letpp_optstartffmt=function|None->()|Somex->Fmt.fprintffmt"%s%a"startfxletpp_optlstartffmt=function|[]->()|x->Fmt.fprintffmt"%s%a"start(pplistf" ")xletpp_opttermstopfmtx=matchderef_head~depth:0xwith|Discard->()|_->Fmt.fprintffmt"%a%s"(uppterm0[]~argsdepth:0empty_env)xstopletpp_sequentfmt{CHR.eigen;context;conclusion}=Fmt.fprintffmt"@[<hov 2>(%a%a%a)@]"(pp_optterm" : ")eigen(pp_optterm" ?- ")context(uppterm0[]~argsdepth:0empty_env)conclusionletpp_urulefmt{CHR.to_match;to_remove;new_goal;guard}=Fmt.fprintffmt"@[<hov 2>%a@ %a@ %a@ %a@]"(pplistpp_sequent" ")to_match(pp_optl"\\ "pp_sequent)to_remove(pp_opt"| "(uppterm~min_prec:Elpi_parser.Parser_config.inf_precedence0[]~argsdepth:0empty_env))guard(pp_opt"<=> "pp_sequent)new_goal[@@warning"-32"]lettry_fire_rule(gid[@trace])rule(constraintsasorig_constraints)=let{CHR.to_match=pats_to_match;to_remove=pats_to_remove;patsno;new_goal;guard;nargs;pattern=quick_filter;rule_name}=ruleinifpatsno<1thenerror"CHR propagation must mention at least one constraint";(* Quick filtering using just the head symbol *)ifnot(List.for_all2match_headconstraintsquick_filter)thenNoneelse(* max depth of rule and constraints involved in the matching *)letmax_depth,constraints=(* Goals are lifted at different depths to avoid collisions *)letmax_depth,constraints=List.fold_left(fun(md,res)c->letmd=md+c.cdepthinmd,(md,c)::res)(0,[])constraintsinmax_depth,List.revconstraintsinletconstraints_depts,constraints_contexts,constraints_goals=List.fold_right(fun(dto,{context=c;cdepth=d;conclusion=g})(ds,ctxs,gs)->(dto,d,d)::ds,(dto,d,c)::ctxs,(dto,d,g)::gs)constraints([],[],[])inletenv=Array.makenargsC.dummyinletpatterns_eigens,patterns_contexts,patterns_goals=List.fold_right(fun{CHR.eigen;context;conclusion}(es,cs,gs)->eigen::es,context::cs,conclusion::gs)(pats_to_match@pats_to_remove)([],[],[])inletmatch_eigenim(dto,d,eigen)pat=match_goal(gid[@trace])imax_depthenvm(dto,d,list_to_lp_list@@C.mkinterval0eigen0)patinletmatch_conclusionimgpat=match_goal(gid[@trace])imax_depthenvmgpatinletmatch_contextimctxpctx=match_context(gid[@trace])imax_depthenvmctxpctxinletguard=matchguardwith|Someg->g|None->mkBuiltinEq[mkNil;mkNil]inletinitial_program=!orig_prolog_programinletexecutable={(* same program *)compiled_program=initial_program;(* no meta meta level *)chr=CHR.empty;initial_goal=(* TODO: maybe we don't need to do this if we don't reach the guard *)move~argsdepth:max_depth~from:max_depth~to_:max_depthenv(shift_bound_vars~depth:0~to_:max_depthguard);assignments=StrMap.empty;initial_depth=max_depth;initial_runtime_state=!CS.initial_state;symbol_table=!C.table;builtins=!FFI.builtins;}inlet{search;get;exec;destroy}=!do_make_runtimeexecutableinletcheck_guard()=trylet_=search()inifgetCS.Ugly.delayed<>[]thenerror"propagation rules must not declare constraint(s)"withNo_clause->raiseNoMatchin(* Inefficient but sound:
deref_uv/appuv and freeze cannot be easily interleaved, since
deref>hmove>move may restrict and generate an assignment.
eg
1. X -> frozen-1 (freeze)
2. X c0 := Y (deref a term containing X c0)
3. Y -> frozen-2 (freeze)
4. X derefs to Y -> frozen-2 (freeze)
It is unclear when deref restricts, but it happens. Looks like an optimization
no to restrict ahead-of-time, but I couldn't find where we do it.
*)letconstraints_goals=List.map(fun(n,d,t)->n,d,full_deref~adepth:0empty_env~depth:dt)constraints_goalsinletconstraints_contexts=List.map(fun(n,m,l)->n,m,l|>List.map(fun{hdepth=depth;hsrc=t}->{hdepth=depth;hsrc=full_deref~adepth:0empty_env~deptht}))constraints_contextsinletresult=try(* matching *)letm=exec(funm->[%spy"dev:CHR:candidate"~rid(pplist(funfx->letdto,dt,t=xinFormat.fprintff"(lives-at:%d, to-be-lifted-to:%d) %a"dtdto(upptermdt[]~argsdepth:0empty_env)t)";")constraints_goals];letm=fold_left2imatch_conclusionmconstraints_goalspatterns_goalsinletm=fold_left2imatch_contextmconstraints_contextspatterns_contextsinletm=fold_left2imatch_eigenmconstraints_deptspatterns_eigensin[%spy"dev:CHR:matching-assignments"~rid(pplist(upptermmax_depth[]~argsdepth:0empty_env)~boxed:false",")(Array.to_listenv)];T.to_resume:=[];assert(!T.new_delayed=[]);m)Ice.empty_freezerin[%spy"dev:CHR:maxdepth"~ridFmt.pp_print_intmax_depth];check_guard();(* result *)let_,constraints_to_remove=letlen_pats_to_match=List.lengthpats_to_matchinpartition_i(funi_->i<len_pats_to_match)orig_constraintsinletnew_goals=matchnew_goalwith|None->None|Some{CHR.eigen;context;conclusion}->leteigen=matchfull_deref~adepth:max_depthenv~depth:max_deptheigenwith|(Nil|Cons_)asx->lp_list_to_list~depth:max_depthx|Discard->C.mkinterval0max_depth0|_->error"eigen not resolving to a list of names"inletmax_eigen,map=List.fold_left(fun(i,m)c->i+1,C.Map.add(Data.destConstc)im)(0,C.Map.empty)eigeninletconclusion=Ice.defrost~from:max_depth~to_:max_eigen~map(Builtin(Impl,[context;conclusion]))envmin(* TODO: check things make sense in heigen *)letprog=initial_programinSome(make_constraint_def~rid~gid:((make_subgoal_idgid(max_eigen,conclusion))[@trace])max_eigenprog[]conclusion)in[%spy"dev:CHR:try-rule:success"~rid];Some(rule_name,constraints_to_remove,new_goals,Ice.assignmentsm)withNoMatch->[%spy"dev:CHR:try-rule:fail"~rid];Noneindestroy();result;;letresumptionto_be_resumed_rev=List.map(fun{cdepth=d;prog;conclusion=g;cgid=gid[@trace]}->(repack_goal[@inlined])~depth:d(gid[@trace])progg)(List.revto_be_resumed_rev)(* all permutations of pivot+rest of length len where the
* pivot is in pivot_position. pivot may be part of rest, it is automatically
* ignored *)letmk_permutationslenpivotpivot_positionrest=letopenListinletrecinsertx=function|[]->[[x]]|(hd::tl)asl->(x::l)::map(funy->hd::y)(insertxtl)inletrecauxnl=ifn=0then[[]]elsematchlwith|[]->[]|hd::tlwhenhd==pivot->auxntl|hd::tl->flatten(map(inserthd)(aux(n-1)tl))@auxntlinletpermutations_no_pivot=aux(len-1)restinpermutations_no_pivot|>mapbeginfunl->letbefore,after=partition_i(funi_->i<pivot_position)linbefore@pivot::afterend;;letpropagation()=letto_be_resumed_rev=ref[]inletremoved=ref[]inletoutdatedcs=List.exists(funx->List.memqx!removed)csinletsome_rule_fired[@trace]=reffalseinletsome_rule_was_tried[@trace]=reffalseinletorig_store_contents[@trace]=CS.contents()inwhile!CS.new_delayed<>[]domatch!CS.new_delayedwith|[]->anomaly"Empty list"|{CS.cstr=active;cstr_blockers=overlapping}::rest->(* new_delayed may be changed by, CS.remove_old_constraint *)CS.new_delayed:=rest;letrules=CHR.rules_for(head_ofactive.conclusion)!chrulesinrules|>List.iter(funrule->forposition=0torule.CHR.patsno-1do(* don't generate perms if the pivot is already out of place *)ifnot(match_headactive(List.nthrule.CHR.patternposition))then()elseletpermutations=mk_permutationsrule.CHR.patsnoactiveposition(List.mapfst(CS.contents~overlapping()))inpermutations|>List.iter(funconstraints->(* a constraint just removed may occur in a permutation (that
* was generated before the removal *)ifoutdatedconstraintsthen()elsebeginlet()[@trace]=some_rule_was_tried:=truein[%spy"user:CHR:try"~rid~gid:active.cgidLoc.pprule.rule_locpp_urulerule];matchtry_fire_rule(active.cgid[@trace])ruleconstraintswith|None->[%spy"user:CHR:rule-failed"~rid]|Some(rule_name,to_be_removed,to_be_added,assignments)->let()[@trace]=some_rule_fired:=truein[%spy"user:CHR:rule-fired"~rid~gid:(active.cgid[@trace])pp_stringrule_name];[%spyl"user:CHR:rule-remove-constraints"~rid~gid:(active.cgid[@trace])(funfmt{cgid}->UUID.ppfmtcgid)to_be_removed];removed:=to_be_removed@!removed;List.iterCS.remove_old_constraintto_be_removed;List.iter(fun(r,t)->r@:=t)assignments;matchto_be_addedwith|None->()|Someto_be_added->to_be_resumed_rev:=to_be_added::!to_be_resumed_revend)done);done;let()[@trace]=if!some_rule_firedthenbeginorig_store_contents|>List.iter(funit->[%spy"user:CHR:store:before"~ridCS.print_giditCS.print1it]);CS.contents()|>List.iter(funit->[%spy"user:CHR:store:after"~ridCS.print_giditCS.print1it]);end;in{new_goals=resumption!to_be_resumed_rev;some_rule_was_tried=!some_rule_was_tried[@trace]}end(* }}} *)(******************************************************************************
Main loop = SLD + delay/resumption
******************************************************************************)moduleMainloop:sigvalmake_runtime:?max_steps:int->?delay_outside_fragment:bool->executable->runtimeend=struct(* {{{ *)letsteps_bound=Fork.new_localNoneletsteps_made=Fork.new_local0letpred_ofg=matchgwith|App(c,_,_)->Some(C.showc)|Constc->Some(C.showc)|Builtin(c,_)->Some(show_builtin_predicateC.showc)|_->None[@@warning"-32"]letpp_candidate~depth~kfmt({loc}ascl)=matchlocwith|Somex->Util.CData.ppfmt(Ast.cloc.Util.CData.cinx)|None->Fmt.fprintffmt"hypothetical clause: %a"(ppclause~hd:k)cl[@@warning"-32"]lethd_c_of=function|Const_asx->x|App(x,_,_)->C.mkConstx|Builtin(x,_)->C.mkConst(const_of_builtin_predicatex)|_->C.dummy[@@warning"-32"]letpp_resumed_goal{depth;program;goal;gid=gid[@trace]}=[%spy"user:rule:resume:resumed"~rid~gid(upptermdepth[]~argsdepth:0empty_env)goal][@@warning"-32"]letpp_CHR_resumed_goal{depth;program;goal;gid=gid[@trace]}=[%spy"user:CHR:resumed"~rid~gid(upptermdepth[]~argsdepth:0empty_env)goal][@@warning"-32"](* The block of recursive functions spares the allocation of a Some/None
* at each iteration in order to know if one needs to backtrack or continue *)letmake_runtime:?max_steps:int->?delay_outside_fragment:bool->executable->runtime=(* Input to be read as the orl (((p,g)::gs)::next)::alts
depth >= 0 is the number of variables in the context. *)letrecrundepthpg(gid[@trace])gs(next:frame)altscutto_alts=[%cur_pred(pred_ofg)];[%trace"run"~ridbeginbeginmatch!steps_boundwith|Somebound->incrsteps_made;if!steps_made>boundthenraiseNo_more_steps|None->()end;matchresume_all()with|None->[%tcallnext_altalts]|Some({depth=ndepth;program;goal;gid=ngid[@trace]}::goals)->[%tcallrunndepthprogramgoal(ngid[@trace])(goals@(repack_goal[@inlined])(gid[@trace])~depthpg::gs)nextaltscutto_alts]|Some[]->[%spyl"user:curgoal"~rid~gid(upptermdepth[]~argsdepth:0empty_env)[hd_c_ofg;g]];matchgwith|Builtin(Cut,[])->[%tcallcut(gid[@trace])gsnext(alts[@trace])cutto_alts]|Builtin(Findall,[q;sol])->[%tcallfindalldepthpqsol(gid[@trace])gsnextaltscutto_alts]|Builtin(And,g::gs')->[%spy"user:rule"~rid~gidpp_string"and"];letgid'[@trace]=make_subgoal_idgid((depth,g)[@trace])inletgs'=List.map(funx->(make_subgoal[@inlined])~depth(gid[@trace])px)gs'in[%spy"user:rule:and"~rid~gidpp_string"success"];[%tcallrundepthpg(gid'[@trace])(gs'@gs)nextaltscutto_alts]|Builtin(Eq,[l;r])->[%spy"user:rule"~rid~gidpp_string"eq"];[%spy"user:rule:builtin:name"~rid~gidpp_string(show_builtin_predicateC.showEq)];ifunif~oc:true~argsdepth:depth~matching:false(gid[@trace])depthempty_envdepthlrthenbegin[%spy"user:rule:eq"~rid~gidpp_string"success"];matchgswith|[]->[%tcallpop_andlaltsnextcutto_alts]|{depth;program;goal;gid=gid[@trace]}::gs->[%tcallrundepthprogramgoal(gid[@trace])gsnextaltscutto_alts]endelsebegin[%spy"user:rule:eq"~rid~gidpp_string"fail"];[%tcallnext_altalts]end|Builtin(Match,[r;p])->[%spy"user:rule"~rid~gidpp_string"eq"];[%spy"user:rule:builtin:name"~rid~gidpp_string(show_builtin_predicateC.showMatch)];ifunif~oc:true~argsdepth:depth~matching:true(gid[@trace])depthempty_envdepthrpthenbegin[%spy"user:rule:eq"~rid~gidpp_string"success"];matchgswith|[]->[%tcallpop_andlaltsnextcutto_alts]|{depth;program;goal;gid=gid[@trace]}::gs->[%tcallrundepthprogramgoal(gid[@trace])gsnextaltscutto_alts]endelsebegin[%spy"user:rule:eq"~rid~gidpp_string"fail"];[%tcallnext_altalts]end|Builtin(RImpl,[g2;g1])->[%spy"user:rule"~rid~gidpp_string"implication"];let[@warning"-26"]loc=Noneinletloc[@trace]=Some(Loc.initial("(context step_id:"^string_of_int(Trace_ppx_runtime.Runtime.get_cur_step~runtime_id:!rid"run")^")"))inletclauses,pdiff,lcs=clausify~tail_cut:false~locp~depthg1inletg2=hmove~from:depth~to_:(depth+lcs)g2inletgid[@trace]=make_subgoal_idgid((depth,g2)[@trace])in[%spy"user:rule:implication"~rid~gidpp_string"success"];[%tcallrun(depth+lcs)(add_clauses~depthclausespdiffp)g2(gid[@trace])gsnextaltscutto_alts]|Builtin((Impl|ImplBang)asik,[g1;g2])->[%spy"user:rule"~rid~gidpp_string"implication"];let[@warning"-26"]loc=Noneinletloc[@trace]=Some(Loc.initial("(context step_id:"^string_of_int(Trace_ppx_runtime.Runtime.get_cur_step~runtime_id:!rid"run")^")"))inletclauses,pdiff,lcs=clausify~tail_cut:(ik=ImplBang)~locp~depthg1inletg2=hmove~from:depth~to_:(depth+lcs)g2inletgid[@trace]=make_subgoal_idgid((depth,g2)[@trace])in[%spy"user:rule:implication"~rid~gidpp_string"success"];[%tcallrun(depth+lcs)(add_clauses~depthclausespdiffp)g2(gid[@trace])gsnextaltscutto_alts]|Builtin(Pi,[arg])->[%spy"user:rule"~rid~gidpp_string"pi"];letf=get_lambda_body~deptharginletgid[@trace]=make_subgoal_idgid((depth+1,f)[@trace])in[%spy"user:rule:pi"~rid~gidpp_string"success"];[%tcallrun(depth+1)pf(gid[@trace])gsnextaltscutto_alts]|Builtin(Sigma,[arg])->[%spy"user:rule"~rid~gidpp_string"sigma"];letf=get_lambda_body~deptharginletv=UVar(oref~depthC.dummy,0)inletfv=substdepth[v]finletgid[@trace]=make_subgoal_idgid((depth,fv)[@trace])in[%spy"user:rule:sigma"~rid~gidpp_string"success"];[%tcallrundepthpfv(gid[@trace])gsnextaltscutto_alts]|Builtin(Delay,args)->[%spy"user:rule"~rid~gidpp_string"builtin"];[%spy"user:rule:builtin:name"~rid~gidpp_string(show_builtin_predicateC.showDelay)];beginmatchConstraints.declare_constraint~depthp(gid[@trace])argswith|()->[%spy"user:rule:builtin"~rid~gidpp_string"success"];(matchgswith|[]->[%tcallpop_andlaltsnextcutto_alts]|{depth;program;goal;gid=gid[@trace]}::gs->[%tcallrundepthprogramgoal(gid[@trace])gsnextaltscutto_alts])|exceptionNo_clause->[%spy"user:rule:builtin"~rid~gidpp_string"fail"];[%tcallnext_altalts]end|Builtin(Hostc,args)->[%spy"user:rule"~rid~gidpp_string"builtin"];[%spy"user:rule:builtin:name"~rid~gidpp_string(C.showc)];letonce~depthgstate=CS.state:=state;let{depth;program;goal;gid=gid[@trace]}=(make_subgoal[@inlined])(gid[@trace])~depthpginlet_alts=rundepthprogramgoal(gid[@trace])[]FNilnoaltsnoaltsin!CS.stateinbeginmatchConstraints.exect_builtin_predicate~oncec~depthp(gid[@trace])argswith|gs'->[%spy"user:rule:builtin"~rid~gidpp_string"success"];(matchList.map(fung->(make_subgoal[@inlined])(gid[@trace])~depthpg)gs'@gswith|[]->[%tcallpop_andlaltsnextcutto_alts]|{depth;program;goal;gid=gid[@trace]}::gs->[%tcallrundepthprogramgoal(gid[@trace])gsnextaltscutto_alts])|exceptionNo_clause->[%spy"user:rule:builtin"~rid~gidpp_string"fail"];[%tcallnext_altalts]end|Cons(g,gs')->[%spy"user:rule"~rid~gidpp_string"and"];letgid'[@trace]=make_subgoal_idgid((depth,g)[@trace])inletgs'=(make_subgoal[@inlined])~depth(gid[@trace])pgs'in[%spy"user:rule:and"~rid~gidpp_string"success"];[%tcallrundepthpg(gid'[@trace])(gs'::gs)nextaltscutto_alts]|Nil->[%spy"user:rule"~rid~gidpp_string"true"];[%spy"user:rule:true"~rid~gidpp_string"success"];beginmatchgswith|[]->[%tcallpop_andlaltsnextcutto_alts]|{depth;program;goal;gid=gid[@trace]}::gs->[%tcallrundepthprogramgoal(gid[@trace])gsnextaltscutto_alts]end|UVar({contents=g}asr,args)wheng!=C.dummy->[%spy"user:rule"~rid~gidpp_string"deref"];[%spy"user:rule:deref"~rid~gidpp_string"success"];[%tcallrundepthp(deref_uv~to_:depthrargs)(gid[@trace])gsnextaltscutto_alts]|AppUVar({contents=t}asr,args)whent!=C.dummy->[%spy"user:rule"~rid~gidpp_string"deref"];[%spy"user:rule:deref"~rid~gidpp_string"success"];[%tcallrundepthp(deref_appuv~to_:depthrargs)(gid[@trace])gsnextaltscutto_alts]|Constk->letclauses=get_clauses~depthkgp.indexin[%spy"user:rule"~rid~gidpp_string"backchain"];[%spyl"user:rule:backchain:candidates"~rid~gid(pp_candidate~depth~k)(Bl.to_listclauses)];[%tcallbackchaindepthp(k,C.dummy,[],gs)(gid[@trace])nextaltscutto_altsclauses]|App(k,x,xs)->letclauses=get_clauses~depthkgp.indexin[%spy"user:rule"~rid~gidpp_string"backchain"];[%spyl"user:rule:backchain:candidates"~rid~gid(pp_candidate~depth~k)(Bl.to_listclauses)];[%tcallbackchaindepthp(k,x,xs,gs)(gid[@trace])nextaltscutto_altsclauses]|Builtin(Cut,_)->anomaly"cut with arguments"|Builtin(And,[])->anomaly"and without arguments"|Builtin(Eq,_)->anomaly"eq without 2 arguments"|Builtin(Match,_)->anomaly"match without 2 arguments"|Builtin(Impl,_)->anomaly"impl without 2 arguments"|Builtin(RImpl,_)->anomaly"rimpl without 2 arguments"|Builtin(ImplBang,_)->anomaly"implbang without 2 arguments"|Builtin(Pi,_)->anomaly"pi without 1 argument"|Builtin(Sigma,_)->anomaly"sigma without 1 argument"|Builtin(Findall,_)->anomaly"findall without 2 arguments"|Arg_|AppArg_->anomaly"The goal is not a heap term"|Lam_|CData_->type_error("The goal is not a predicate:"^(show_termg))|UVar_|AppUVar_|Discard->error"The goal is a flexible term"end](* We pack some arguments into a tuple otherwise we consume too much stack *)andbackchaindepthp(k,arg,args_of_g,gs)(gid[@trace])nextaltscutto_altscp=[%trace"select"~ridbeginifBl.is_emptycpthenbegin[%spy"user:rule:backchain"~rid~gidpp_string"fail"];[%tcallnext_altalts]endelselet{depth=c_depth;mode=c_mode;args=c_args;hyps=c_hyps;vars=c_vars;oc;loc},cs=Bl.nextcpin[%spy"user:rule:backchain:try"~rid~gid(pp_optionUtil.CData.pp)(Util.option_mapAst.cloc.Util.CData.cinloc)(ppclause~hd:k){depth=c_depth;mode=c_mode;args=c_args;hyps=c_hyps;vars=c_vars;loc;timestamp=[];oc=true}];letold_trail=!T.trailinT.last_call:=alts==noalts&&Bl.is_emptycs;letenv=Array.makec_varsC.dummyinmatchmatchc_argswith|[]->arg==C.dummy&&args_of_g==[]|x::xs->arg!=C.dummy&&matchc_modewith|[]->unif~oc~argsdepth:depth~matching:false(gid[@trace])depthenvc_depthargx&&for_all23~argsdepth:depth(unif~oc(gid[@trace]))depthenvc_depthargs_of_gxs|arg_mode::ms->unif~oc~argsdepth:depth~matching:(Mode.get_headarg_mode==Input)(gid[@trace])depthenvc_depthargx&&for_all3b3~argsdepth:depth(unif~oc(gid[@trace]))depthenvc_depthargs_of_gxsmsfalsewith|false->T.undo~old_trail();[%tcallbackchaindepthp(k,arg,args_of_g,gs)(gid[@trace])nextaltscutto_altscs]|true->letoldalts=altsinletalts=ifBl.is_emptycsthenaltselse{program=p;adepth=depth;agoal_hd=k;ogoal_arg=arg;ogoal_args=args_of_g;agid=gid[@trace];goals=gs;stack=next;trail=old_trail;state=!CS.state;clauses=cs;cutto_alts=cutto_alts;next=alts}inbeginmatchc_hypswith|[]->[%spy"user:rule:backchain"~rid~gidpp_string"success"];beginmatchgswith|[]->[%tcallpop_andlaltsnextcutto_alts]|{depth;program;goal;gid=gid[@trace]}::gs->[%tcallrundepthprogramgoal(gid[@trace])gsnextaltscutto_alts]end|h::hs->letnext=ifgs=[]thennextelseFCons(cutto_alts,gs,next)inleth=move~argsdepth:depth~from:c_depth~to_:depthenvhinletgid[@trace]=make_subgoal_idgid((depth,h)[@trace])inleths=List.map(funx->(make_subgoal[@inlined])(gid[@trace])~depthp(move~argsdepth:depth~from:c_depth~to_:depthenvx))hsin[%spy"user:rule:backchain"~rid~gidpp_string"success"];[%tcallrundepthph(gid[@trace])hsnextaltsoldalts]endend]andcut(gid[@trace])gsnext(alts[@trace])cutto_alts=[%spy"user:rule"~rid~gidpp_string"cut"];let()[@trace]=letrecprune({agid=agid[@trace];clauses;adepth=depth;agoal_hd=hd}asalts)=ifalts!=cutto_altsthenbeginList.iter(func->[%spy"user:rule:cut:branch"~ridUUID.ppagid(pp_optionUtil.CData.pp)(Util.option_mapAst.cloc.Util.CData.cinc.loc)(ppclause~hd)c])(clauses|>Bl.to_list);prunealts.nextendinprunealtsinifcutto_alts==noaltsthen(T.cut_trail[@inlined])();[%spy"user:rule:cut"~rid~gidpp_string"success"];matchgswith|[]->pop_andlcutto_altsnextcutto_alts|{depth;program;goal;gid=gid[@trace]}::gs->rundepthprogramgoal(gid[@trace])gsnextcutto_altscutto_altsandfindalldepthpgs(gid[@trace])gsnextaltscutto_alts=[%spy"user:rule"~rid~gidpp_string"findall"];letg,fresh_g=copy_heap_drop_csts~depthgin(* so that Discard becomes a variable *)[%trace"findall"~rid("@[<hov 2>query: %a@]"(upptermdepth[]~argsdepth:0empty_env)g)beginletexecutable={(* same program *)compiled_program=p;(* no meta meta level *)chr=CHR.empty;initial_goal=g;assignments=StrMap.empty;initial_depth=depth;initial_runtime_state=!CS.initial_state;symbol_table=!C.table;builtins=!FFI.builtins;}inlet{search;next_solution;destroy;get;_}=!do_make_runtimeexecutableinletsolutions=ref[]inletadd_sol()=ifgetCS.Ugly.delayed<>[]thenerror"findall search must not declare constraint(s)";letsol,_=HO.copy_heap_drop_csts~depth~keep_if_outside:fresh_ggin[%spy"findall solution:"~rid~gid(pptermdepth[]~argsdepth:0empty_env)g];solutions:=sol::!solutionsinletalternatives=refnoaltsintryalternatives:=search();add_sol();whiletruedoalternatives:=next_solution!alternatives;add_sol();done;raiseNo_clausewithNo_clause->letsolutions=list_to_lp_list(List.rev!solutions)in[%spy"findall solutions:"~rid~gid(pptermdepth[]~argsdepth:0empty_env)solutions];destroy();[%spy"findall solutions:"~rid~gid(pptermdepth[]~argsdepth:0empty_env)solutions];matchunif~oc:true~argsdepth:depth~matching:false(gid[@trace])depthempty_envdepthssolutionswith|false->[%spy"user:rule:findall"~rid~gidpp_string"fail"];[%tcallnext_altalts]|true->[%spy"user:rule:findall"~rid~gidpp_string"success"];beginmatchgswith|[]->[%tcallpop_andlaltsnextcutto_alts]|{depth;program;goal;gid=gid[@trace]}::gs->[%tcallrundepthprogramgoal(gid[@trace])gsnextaltscutto_alts]endend]andpop_andlaltsnextcutto_alts=matchnextwith|FNil->(matchresume_all()withNone->Fmt.fprintfFmt.std_formatter"Undo triggered by goal resumption\n%!";[%tcallnext_altalts]|Some({depth;program;goal;gid=gid[@trace]}::gs)->rundepthprogramgoal(gid[@trace])gsFNilaltscutto_alts|Some[]->alts)|FCons(_,[],_)->anomaly"empty stack frame"|FCons(cutto_alts,{depth;program;goal;gid=gid[@trace]}::gs,next)->rundepthprogramgoal(gid[@trace])gsnextaltscutto_altsandresume_all():goallistoption=(* if fm then Some [] else *)(*if (!to_resume <> []) then begin
prerr_endline ("## RESUME ALL R " ^ string_of_int (List.length !to_resume));
prerr_endline ("## RESUME ALL D " ^ string_of_int (List.length !delayed));
end;*)letok=reftrueinletto_be_resumed=ref[]in(* Phase 1: we analyze the goals to be resumed *)while!ok&&!CS.to_resume<>[]domatch!CS.to_resumewith|{kind=Unification{adepth;bdepth;env;a;b;matching;oc}}asdg::rest->CS.remove_olddg;CS.to_resume:=rest;[%spy"user:resume-unif"~rid(funfmt()->Fmt.fprintffmt"@[<hov 2>^%d:%a@ == ^%d:%a@]\n%!"adepth(upptermadepth[]~argsdepth:0empty_env)abdepth(upptermbdepth[]~argsdepth:adepthenv)b)()];ok:=unif~oc~argsdepth:adepth~matching((UUID.make())[@trace])adepthenvbdepthab|{kind=Constraintdpg}asc::rest->CS.remove_oldc;CS.to_resume:=rest;(*Fmt.fprintf Fmt.std_formatter
"Resuming goal: @[<hov 2> ...@ ⊢^%d %a@]\n%!"
(*"Resuming goal: @[<hov 2> %a@ ⊢^%d %a@]\n%!"*)
(*(pplist (uppterm depth [] ~argsdepth:0 empty_env) ",") pdiff*)
depth (uppterm depth [] ~argsdepth:0 empty_env) g ;*)to_be_resumed:=dpg::!to_be_resumed|_->anomaly"Unknown constraint type"done;(* Phase 2: we propagate the constraints *)if!okthenletto_be_resumed=Constraints.resumption!to_be_resumedinlet()[@trace]=ifto_be_resumed!=[]thenbegin[%spy"user:rule"~ridpp_string"resume"];List.iterpp_resumed_goalto_be_resumed;[%spy"user:rule:resume"~ridpp_string"success"];endin(* Optimization: check here new_delayed *)if!CS.new_delayed<>[]thenbeginlet()[@trace]=ifto_be_resumed!=[]thenbeginTrace_ppx_runtime.Runtime.incr_cur_step~runtime_id:!rid"run";endinlet{Constraints.new_goals;some_rule_was_tried=some_rule_was_tried[@trace]}=Constraints.propagation()inlet()[@trace]=List.iterpp_CHR_resumed_goalnew_goals;ifsome_rule_was_tried&&new_goals=[]thenbeginTrace_ppx_runtime.Runtime.incr_cur_step~runtime_id:!rid"run";endinSome(to_be_resumed@new_goals)endelseSometo_be_resumedelsebegin[%spy"user:rule"~ridpp_string"constraint-failure"];Noneendandnext_altalts=ifalts==noaltsthenraiseNo_clauseelselet{program=p;clauses;agoal_hd=k;ogoal_arg=arg;ogoal_args=args;agid=gid[@trace];goals=gs;stack=next;trail=old_trail;state=old_state;adepth=depth;cutto_alts=cutto_alts;next=alts}=altsinT.undo~old_trail~old_state();[%trace"run"~ridbegin[%cur_pred(Some(C.showk))];[%spyl"user:curgoal"~rid~gid(upptermdepth[]~argsdepth:0empty_env)[Constk;App(k,arg,args)]];[%spy"user:rule"~rid~gidpp_string"backchain"];[%spyl"user:rule:backchain:candidates"~rid~gid(pp_candidate~depth~k)(Bl.to_listclauses)];[%tcallbackchaindepthp(k,arg,args,gs)(gid[@trace])nextaltscutto_altsclauses]end]in(* Finally the runtime *)fun?max_steps?(delay_outside_fragment=false){compiled_program;chr;initial_depth;initial_goal;initial_runtime_state;assignments;symbol_table;builtins;}->let{Fork.exec=exec;get=get;set=set}=Fork.fork()insetorig_prolog_programcompiled_program;setConstraints.chruleschr;setT.initial_trailT.empty;setT.trailT.empty;setT.last_callfalse;setCS.new_delayed[];setCS.to_resume[];setCS.blockers_mapIntMap.empty;setCS.Ugly.delayed[];setsteps_boundmax_steps;setdelay_hard_unif_problemsdelay_outside_fragment;setsteps_made0;setCS.stateinitial_runtime_state;setCS.initial_stateinitial_runtime_state;setC.tablesymbol_table;setFFI.builtinsbuiltins;setrid!max_runtime_id;letsearch=exec(fun()->[%spy"dev:trail:init"~rid(funfmt()->T.print_trailfmt)()];letgid[@trace]=UUID.make()in[%spy"user:newgoal"~rid~gid(uppterminitial_depth[]~argsdepth:0empty_env)initial_goal];T.initial_trail:=!T.trail;runinitial_depth!orig_prolog_programinitial_goal(gid[@trace])[]FNilnoaltsnoalts)inletdestroy()=exec(fun()->T.undo~old_trail:T.empty())()inletnext_solution=execnext_altinincrmax_runtime_id;{search;next_solution;destroy;exec;get};;do_make_runtime:=make_runtime;;end(* }}} *)openMainloop(******************************************************************************
API
******************************************************************************)letmk_outcomesearchget_csassignmentsdepth=tryletalts=search()inletsyn_csts,reloc_state,final_state,pp_ctx=get_cs()inletsolution={assignments;constraints=syn_csts;state=final_state;pp_ctx=pp_ctx;state_for_relocation=reloc_state;}inSuccesssolution,altswith|No_clause(*| Non_linear*)->Failure,noalts|No_more_steps->NoMoreSteps,noaltsletexecute_once?max_steps?delay_outside_fragmentexec=let{search;get}=make_runtime?max_steps?delay_outside_fragmentexecintryletresult=fst(mk_outcomesearch(fun()->getCS.Ugly.delayed,(exec.initial_depth,getC.table),getCS.state|>State.end_execution,{Data.uv_names=ref(getPp.uv_names);table=getC.table})exec.assignmentsexec.initial_depth)in[%end_trace"execute_once"~rid];resultwithe->[%end_trace"execute_once"~rid];raisee;;letexecute_loop?delay_outside_fragmentexec~more~pp=let{search;next_solution;get;destroy=_}=make_runtime?delay_outside_fragmentexecinletk=refnoaltsinletdo_with_infosf=lettime0=Unix.gettimeofday()inleto,alts=mk_outcomef(fun()->getCS.Ugly.delayed,(exec.initial_depth,getC.table),getCS.state|>State.end_execution,{Data.uv_names=ref(getPp.uv_names);table=getC.table})exec.assignmentsexec.initial_depthinlettime1=Unix.gettimeofday()ink:=alts;pp(time1-.time0)oindo_with_infossearch;while!k!=noaltsdoifnot(more())thenk:=noaltselsetrydo_with_infos(fun()->next_solution!k)with|No_clause->pp0.0Failure;k:=noalts;[%end_trace"execute_loop"~rid]|e->pp0.0Failure;k:=noalts;[%end_trace"execute_loop"~rid];raiseedone;;letpp_stuck_goal?pp_ctxfmts=CS.pp_stuck_goal?pp_ctxfmtsletis_flex=HO.is_flexletderef_uv=HO.deref_uvletderef_appuv=HO.deref_appuvletderef_apparg=HO.deref_appargletderef_head=HO.deref_headletfull_deref=HO.full_deref~adepth:0empty_envleteta_contract_flex=HO.eta_contract_flexletlp_list_to_list=Clausify.lp_list_to_listletlist_to_lp_list=HO.list_to_lp_listletsplit_conj=Clausify.split_conjletmkAppArg=HO.mkAppArgletsubst~depth=HO.substdepthletmove=HO.movelethmove=HO.hmoveletmkinterval=C.mkintervalletmkAppL=C.mkAppLletlex_insertion=lex_insertionletexpand_uv~depthr~ano=lett,assignment=HO.expand_uv~depthr~anoinoption_iter(fun(r,assignment)->r@:=assignment)assignment;tletexpand_appuv~depthr~args=lett,assignment=HO.expand_appuv~depthr~argsinoption_iter(fun(r,assignment)->r@:=assignment)assignment;tmoduleCompileTime=structletupdate_indexing=update_indexingletadd_to_index=add_to_index_compile_timeletclausify1=Clausify.clausify1letget_clauses~depthgoalargs_idx:overlap_clauseBl.scan=get_clauses_dt~check_mut_excl:On~pp_clause:pp_overlap_clause~cmp_clause:(fun(c1:overlap_clause)c2->lex_insertionc1.timestampc2.timestamp)~depthgoalargs_idxletfresh_uvar~depth=oref~depthC.dummyend