1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603(*********************************************************************************)(* OCaml-RDF *)(* *)(* Copyright (C) 2012-2021 Institut National de Recherche en Informatique *)(* et en Automatique. All rights reserved. *)(* *)(* This program is free software; you can redistribute it and/or modify *)(* it under the terms of the GNU Lesser General Public License version *)(* 3 as published by the Free Software Foundation. *)(* *)(* This program is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU General Public License for more details. *)(* *)(* You should have received a copy of the GNU General Public License *)(* along with this program; if not, write to the Free Software *)(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA *)(* 02111-1307 USA *)(* *)(* Contact: Maxence.Guesdon@inria.fr *)(* *)(*********************************************************************************)(** *)moduleN=TermopenDtopenSparql_typesopenSparql_algebralet()=Random.self_init();;typeerror=|Unbound_variableofvar|Not_a_integerofTerm.literal|Not_a_double_or_decimalofTerm.literal|Type_mismatchofDt.value*Dt.value|Invalid_fun_argumentofIri.t|Unknown_funofIri.t|Invalid_built_in_fun_argumentofstring*expressionlist|Unknown_built_in_funofstring|No_term|Cannot_compare_for_datatypeofIri.t|Unhandled_regex_flagofchar|Incompatible_string_literalsofDt.value*Dt.value|Empty_setofstring(** sparql function name *)|Missing_values_in_inline_dataofinline_data_full|Missing_implementationofstring|No_such_graphofDs.nameexceptionErroroferrorleterrore=raise(Errore)letstring_of_error=function|Unbound_variablev->Printf.sprintf"%sUnbound variable %S"(Loc.string_of_locv.var_loc)v.var_name|Not_a_integerlit->"Not an integer: "^(Term.string_of_literallit)|Not_a_double_or_decimallit->"Not an double: "^(Term.string_of_literallit)|Type_mismatch(v1,v2)->"Type mismatch: "^(Dt.string_of_valuev1)^" <!> "^(Dt.string_of_valuev2)|Invalid_fun_argumentiri->"Invalid argument for function "^(Iri.to_stringiri)|Unknown_funiri->"Unknown function "^(Iri.to_stringiri)|Invalid_built_in_fun_argument(name,_)->"Invalid argument list for builtin function "^name|Unknown_built_in_funname->"Unknown builtit function "^name|No_term->"No term"|Cannot_compare_for_datatypeiri->"Cannot compare values of datatype "^(Iri.to_stringiri)|Unhandled_regex_flagc->"Unhandled regexp flag "^(String.make1c)|Incompatible_string_literals(v1,v2)->(* FIXME: show values *)"Incompatible string literals"|Empty_setname->"Empty set in function "^name|Missing_values_in_inline_dataidf->"Missing values in inline data"|Missing_implementationmsg->Printf.sprintf"Missing implementation: %s"msg|No_such_graphname->Printf.sprintf"No such graph %s"(Ds.string_of_namename)let()=Printexc.register_printer(function|Errore->Some(string_of_errore)|_->None)moduleNSet=Ds.NameSetmoduleNMap=Ds.NameMaptypecontext={base:Iri.t;named:NSet.t;dataset:Ds.dataset;active:Graph.graph;now:Term.datetime;(** because all calls to NOW() must return the same value,
we get it at the beginning of the evaluation and use it when required *)}letcontext~base?(from=[])?(from_named=NSet.empty)dataset=letactive=matchfromwith[]whenNSet.is_emptyfrom_named->dataset.Ds.default|[]->(* default graph is empty *)Graph.open_graphbase|[name]->(matchdataset.Ds.get_namednamewith|None->error(No_such_graphname)|Someg->g)|names->(* merge graphs to get the active graph *)letg=Graph.open_graphbaseinletgraphs=Ds.graphsdatasetinList.iter(fun(_,g2)->Graph.mergegg2)graphs;ginletnamed=(* if no named graph is specified, then use the named graphs of
dataset *)ifNSet.is_emptyfrom_namedthendataset.Ds.named()elsefrom_namedin{base;named=named;dataset;active;now=Term.now();};;moduleGExprOrdered=structtypet=Term.termoptionlistletcompare=letcompab=matcha,bwithNone,None->0|Some_,None->1|None,Some_->-1|Somea,Someb->Term.compareabinMisc.compare_listcompendmoduleGExprMap=Map.Make(GExprOrdered)(** Evaluate boolean expression.
See http://www.w3.org/TR/sparql11-query/#ebv *)letebv=function|Erre->Dt.errore|Boolb->b|HexBinary""->false|HexBinary_->true|String""->false|String_->true|Ltrl("",_)->false|Ltrl_->true|Ltrdt("",_)->false|Ltrdt_->true|Int(n,_)->n<>0|Floatf->beginmatchStdlib.classify_floatfwithFP_nan|FP_zero->false|_->trueend|Datetime_|Dt.Iri_|Dt.Blank_->false(* FIXME: or error ? *);;letreccompare?(sameterm=false)v1v2=(*prerr_endline
("compare v1="^(Dt.string_of_value v1)^" v2="^(Dt.string_of_value v2));*)matchv1,v2with|Err_,_->1|_,Err_->-1|Dt.Irit1,Dt.Irit2->Iri.comparet1t2|Dt.Blanks1,Dt.Blanks2->String.compares1s2|Strings1,Strings2|Ltrl(s1,None),Strings2|Strings1,Ltrl(s2,None)->String.compares1s2|Int(n1,_),Int(n2,_)->Stdlib.comparen1n2|Int_,Float_->compare(Dt.floatv1)v2|Float_,Int_->comparev1(Dt.floatv2)|Floatf1,Floatf2->Stdlib.comparef1f2|Boolb1,Boolb2->Stdlib.compareb1b2|HexBinaryb1,HexBinaryb2->(* remember that both values are in lowercase *)Stdlib.compareb1b2|Datetimet1,Datetimet2->Ptime.comparet1.Term.stampt2.Term.stamp|Ltrl(l1,lang1),Ltrl(l2,lang2)->beginmatchMisc.opt_compareString.comparelang1lang2with0->String.comparel1l2|n->nend|Ltrdt(s1,dt1),Ltrdt(s2,dt2)->(matchIri.comparedt1dt2with0->ifsametermthenString.compares1s2elseerror(Cannot_compare_for_datatypedt1)|_->error(Type_mismatch(v1,v2)))|_,_->Dt.ValueOrdered.comparev1v2(*error (Type_mismatch (v1, v2))*)(** Implement the sorting order used in sparql order by clause:
http://www.w3.org/TR/sparql11-query/#modOrderBy *)letsortby_comparev1v2=trycomparev1v2with_->Dt.ValueOrdered.comparev1v2;;(** Predefined functions *)letxsd_datetime=Rdf_.xsd_"dateTime";;letfun_datetime=function[]|_::_::_->error(Invalid_fun_argumentxsd_datetime)|[v]->Dt.datetimevletiri_funs_=[xsd_datetime,fun_datetime;];;letiri_funs=ref(List.fold_left(funacc(iri,f)->Iri.Map.addirifacc)Iri.Map.emptyiri_funs_);;letadd_iri_funirif=iri_funs:=Iri.Map.addirif!iri_funs;;(** Builtin functions; they take an expression evaluation function
in parameter, as all arguments must not be always evaluated,
for example in the IF. *)letbi_bnodenameeval_exprctxmu=function[]->Blank(Sparql_ms.gen_blank_id())|[e]->beginletv=eval_exprctxmueinmatchvwithString_|Ltrl(_,None)->Sparql_ms.get_bnodemuv|_->Err(Dt.Type_error(v,"simple literal or string"))end|l->error(Invalid_built_in_fun_argument(name,l));;letbi_coalesce_=letrecitereval_exprctxmu=function[]->errorNo_term|h::q->letv=trymatcheval_exprctxmuhwithErr_->None|v->Somevwith_->NoneinmatchvwithNone->itereval_exprctxmuq|Somev->viniter;;letbi_datatypename=letfeval_exprctxmu=function[e]->Dt.datatype(eval_exprctxmue)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_ifnameeval_exprctxmu=function[e1;e2;e3]->beginifebv(eval_exprctxmue1)theneval_exprctxmue2elseeval_exprctxmue3end|l->error(Invalid_built_in_fun_argument(name,l));;letbi_irinameeval_exprctxmu=function[e]->Dt.irictx.base(eval_exprctxmue)|l->error(Invalid_built_in_fun_argument(name,l));;letbi_urinameeval_exprctxmu=function[e]->Dt.irictx.base(eval_exprctxmue)|l->error(Invalid_built_in_fun_argument(name,l));;letbi_isblankname=letfeval_exprctxmu=function[e]->(matcheval_exprctxmuewithDt.Blank_->Booltrue|_->Boolfalse)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_isiriname=letfeval_exprctxmu=function[e]->(matcheval_exprctxmuewithDt.Iri_->Booltrue|_->Boolfalse)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_isliteralname=letfeval_exprctxmu=function[e]->(matcheval_exprctxmuewithDt.Blank_|Dt.Iri_|Dt.Err_->Boolfalse|Dt.String_|Dt.Int_|Dt.Float_|Dt.Bool_|Dt.HexBinary_|Dt.Datetime_|Dt.Ltrl_|Dt.Ltrdt_->Booltrue)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_langname=letfeval_exprctxmu=function[e]->(matcheval_exprctxmuewithLtrl(_,Somel)->Stringl|_->String"")|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_isnumericname=letfeval_exprctxmu=function[e]->(matcheval_exprctxmuewith|Dt.Int_|Dt.Float_->Booltrue|Dt.Blank_|Dt.Iri_|Dt.Err_|Dt.String_|Dt.Bool_|Dt.HexBinary_|Dt.Datetime_|Dt.Ltrl_|Dt.Ltrdt_->Boolfalse)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letregex_flag_of_char=function|'s'->`DOTALL|'m'->`MULTILINE|'i'->`CASELESS(* FIXME: 'x' not handled yet *)|c->error(Unhandled_regex_flagc);;(** See http://www.w3.org/TR/xpath-functions/#regex-syntax *)letbi_regexname=letflag_of_charrc=r:=(regex_flag_of_charc)::!rinletfeval_exprctxmul=let(s,pat,flags)=matchlwith|[e1;e2]->(eval_exprctxmue1,eval_exprctxmue2,None)|[e1;e2;e3]->(eval_exprctxmue1,eval_exprctxmue2,Some(eval_exprctxmue3))|_->error(Invalid_built_in_fun_argument(name,l))intrylet(s,_)=Dt.string_literalsinletpat=matchpatwithStrings->s|_->Dt.error(Dt.Type_error(pat,"simple string"))inletflags=matchflagswithNone->[]|Some(Strings)->letl=ref[]inString.iter(flag_of_charl)s;!l|Somev->Dt.error(Dt.Type_error(v,"simple string"))inletflags=`UTF8::flagsinLog.debug(funm->m"%s s=%s pat=%s"namespat);Bool(!Stubs.pcre_pmatch~flags~pats)withe->Log.debug(funm->m"%s: %s"name(Printexc.to_stringe));Err(Dt.Exceptione)inf;;letbi_sametermname=letfeval_exprctxmu=function[e1;e2]->letv1=eval_exprctxmue1inletv2=eval_exprctxmue2inBool(compare~sameterm:truev1v2=0)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_strname=letfeval_exprctxmu=function[e]->(tryDt.string(eval_exprctxmue)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_strdtname=letfeval_exprctxmu=function[e1;e2]->(trylet(s,_)=Dt.string_literal(eval_exprctxmue1)inletiri=matchDt.irictx.base(eval_exprctxmue2)withDt.Irit->t|_->assertfalseinLtrdt(s,iri)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_strlangname=letfeval_exprctxmu=function[e1;e2]->(trylet(s,_)=Dt.string_literal(eval_exprctxmue1)inlet(lang,_)=Dt.string_literal(eval_exprctxmue2)inLtrl(s,Somelang)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letstring_lit_compatiblelit1lit2=matchlit1,lit2with(_,Somex),(_,Somey)->x=y|_->true;;letbi_strlenname=letfeval_exprctxmu=function[e]->(trylet(s,_)=Dt.string_literal(eval_exprctxmue)inInt(Utf8.utf8_lengths,Rdf_.xsd_int)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_substrname=letfeval_exprctxmuargs=let(e,pos,len)=matchargswith[e1;e2]->(e1,e2,None)|[e1;e2;e3]->(e1,e2,Somee3)|_->error(Invalid_built_in_fun_argument(name,args))intrylet(s,lang)=Dt.string_literal(eval_exprctxmue)inletpos=matchDt.int(eval_exprctxmupos)withErre->Dt.errore|Int(n,_)->n|_->assertfalseinletlen=matchlenwithNone->None|Somee->matcheval_exprctxmuewithErre->Dt.errore|Int(n,_)->Somen|_->assertfalsein(* Convert positions to 0-based positions, and according
to string length, since we return empty string in case of invalid bounds. *)letlen_s=Utf8.utf8_lengthsinletstart=pos-1inletlen=matchlenwithNone->len_s-start|Somelen->letlen=start+len+1(* + 1 because we cremented start above *)inmin(len_s-start)leninletstart=ifstart<0then0elseifstart>=len_sthenlen_s-1elsestartinlets=Utf8.utf8_substrsstartleninLtrl(s,lang)withe->Err(Dt.Exceptione)inf;;letbi_strendsname=letfeval_exprctxmu=function[e1;e2]->(tryletv1=eval_exprctxmue1inletv2=eval_exprctxmue2inlet((s1,lang1)aslit1)=Dt.string_literalv1inlet((s2,lang2)aslit2)=Dt.string_literalv2inifnot(string_lit_compatiblelit1lit2)thenerror(Incompatible_string_literals(v1,v2));Bool(Utf8.utf8_is_suffixs1s2)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_strstartsname=letfeval_exprctxmu=function[e1;e2]->(tryletv1=eval_exprctxmue1inletv2=eval_exprctxmue2inlet((s1,lang1)aslit1)=Dt.string_literalv1inlet((s2,lang2)aslit2)=Dt.string_literalv2inifnot(string_lit_compatiblelit1lit2)thenerror(Incompatible_string_literals(v1,v2));Bool(Utf8.utf8_is_prefixs1s2)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_containsname=letfeval_exprctxmu=function[e1;e2]->(tryletv1=eval_exprctxmue1inletv2=eval_exprctxmue2inlet((s1,lang1)aslit1)=Dt.string_literalv1inlet((s2,lang2)aslit2)=Dt.string_literalv2inifnot(string_lit_compatiblelit1lit2)thenerror(Incompatible_string_literals(v1,v2));Bool(Utf8.utf8_containss1s2)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_strbeforename=letfeval_exprctxmu=function[e1;e2]->(tryletv1=eval_exprctxmue1inletv2=eval_exprctxmue2inlet((s1,lang1)aslit1)=Dt.string_literalv1inlet((s2,lang2)aslit2)=Dt.string_literalv2inifnot(string_lit_compatiblelit1lit2)thenerror(Incompatible_string_literals(v1,v2));String(Utf8.utf8_strbefores1s2)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_straftername=letfeval_exprctxmu=function[e1;e2]->(tryletv1=eval_exprctxmue1inletv2=eval_exprctxmue2inlet((s1,lang1)aslit1)=Dt.string_literalv1inlet((s2,lang2)aslit2)=Dt.string_literalv2inifnot(string_lit_compatiblelit1lit2)thenerror(Incompatible_string_literals(v1,v2));String(Utf8.utf8_strafters1s2)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_struuidname=letf___=function[]->letuuid=Uuidm.v`V4inString(Uuidm.to_stringuuid)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_uuidname=letf___=function[]->letuuid=Uuidm.v`V4inletuuid=Uuidm.to_stringuuidinDt.Iri(Iri.of_string("urn:uuid:"^uuid))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_encode_for_uriname=letfeval_exprctxmu=function[e]->(trylet(s,_)=Dt.string_literal(eval_exprctxmue)inString(Uri.pct_encodes)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_concatname=letrecitereval_exprctxmublang=function[]whenlang=None->String(Buffer.contentsb)|[]->Ltrl(Buffer.contentsb,lang)|e::q->let(s,lang2)aslit=Dt.string_literal(eval_exprctxmue)inletlang=matchlang,lang2withNone,None->None|None,Some_->lang2|Some_,None->lang|Somex,Someywhenx<>y->error(Incompatible_string_literals(Ltrl(Buffer.contentsb,lang),Ltrl(s,lang2)))|_->langinBuffer.add_stringbs;itereval_exprctxmublangqinfuneval_exprctxmu->letb=Buffer.create256initereval_exprctxmubNone;;letbi_langmatchesname=letfeval_exprctxmu=function[e1;e2]->(tryletv1=eval_exprctxmue1inletv2=eval_exprctxmue2inlet((s1,_)aslit1)=Dt.string_literalv1inlet((s2,_)aslit2)=Dt.string_literalv2inletb=matchs2with"*"->s1<>""|_->(* by now, just check language spec s2 is a prefix of
the given language tag s1 *)lets1=String.lowercase_asciis1inlets2=String.lowercase_asciis2inletlen1=String.lengths1inletlen2=String.lengths2in(len1>=len2)&&(String.subs10len2=s2)inBoolbwithe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_replacename=letflag_of_charrc=r:=(regex_flag_of_charc)::!rinletfeval_exprctxmul=let(s,pat,templ,flags)=matchlwith|[e1;e2;e3]->(eval_exprctxmue1,eval_exprctxmue2,eval_exprctxmue3,None)|[e1;e2;e3;e4]->(eval_exprctxmue1,eval_exprctxmue2,eval_exprctxmue3,Some(eval_exprctxmue4))|_->error(Invalid_built_in_fun_argument(name,l))intrylet(s,_)=Dt.string_literalsinletpat=matchpatwithStrings->s|_->Dt.error(Dt.Type_error(pat,"simple string"))inlet(templ,_)=Dt.string_literaltemplinletflags=matchflagswithNone->[]|Some(Strings)->letl=ref[]inString.iter(flag_of_charl)s;!l|Somev->Dt.error(Dt.Type_error(v,"simple string"))inletflags=`UTF8::flagsinLog.debug(funm->m"%s: s=%s pat=%s templ=%s"namespattempl);String(!Stubs.pcre_replace~flags~pat~templs)withe->Log.debug(funm->m"%s: %s"name(Printexc.to_stringe));Err(Dt.Exceptione)inf;;letbi_numericfname=letfeval_exprctxmu=function[e]->letv=tryDt.numeric(eval_exprctxmue)withe->Err(Dt.Exceptione)in(matchvwithErre->Erre|_->fv)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_num_abs=functionInt(n,dt)->Int(absn,Rdf_.xsd_nonNegativeInteger)|Floatf->Float(abs_floatf)|_->assertfalse;;letbi_num_round=functionInt_asx->x|Floatf->Float(Stdlib.float(int_of_float(floor(f+.0.5))))|_->assertfalse;;letbi_num_ceil=function|Int_asx->x|Floatf->Float(ceilf)|_->assertfalse;;letbi_num_floor=function|Int_asx->x|Floatf->Float(floorf)|_->assertfalse;;letbi_randname___=function[]->Float(Random.float1.0)|l->error(Invalid_built_in_fun_argument(name,l));;letbi_nowname_ctx_=function[]->Datetimectx.now|l->error(Invalid_built_in_fun_argument(name,l));;letbi_on_datefname=letfeval_exprctxmu=function[e]->letv=tryDt.datetime(eval_exprctxmue)withe->Err(Dt.Exceptione)in(matchvwithErre->Erre|Datetimet->ft|_->assertfalse)|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_date_yeart=let((y,_,_),_)=Ptime.to_date_time?tz_offset_s:t.N.tzt.N.stampinInt(y,Rdf_.xsd_int);;letbi_date_montht=let((_,m,_),_)=Ptime.to_date_time?tz_offset_s:t.N.tzt.N.stampinInt(m,Rdf_.xsd_int)letbi_date_dayt=let((_,_,d),_)=Ptime.to_date_time?tz_offset_s:t.N.tzt.N.stampinInt(d,Rdf_.xsd_int)letbi_date_hourst=let(_,((h,_,_),_))=Ptime.to_date_time?tz_offset_s:t.N.tzt.N.stampinInt(h,Rdf_.xsd_int);;letbi_date_minutest=let(_,((_,m,_),_))=Ptime.to_date_time?tz_offset_s:t.N.tzt.N.stampinInt(m,Rdf_.xsd_int);;letbi_date_secondst=let(_,((_,_,s),_))=Ptime.to_date_time?tz_offset_s:t.N.tzt.N.stampinFloat(float_of_ints);;letbi_hashfname=letfeval_exprctxmu=function[e]->letv=tryDt.(eval_exprctxmue)withe->Err(Dt.Exceptione)in(matchvwithErre->Erre|Strings->fs|_->Dt.error(Dt.Type_error(v,"simple string")))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_md5s=String(String.lowercase_ascii(Digest.to_hex(Digest.strings)));;letbi_sha1s=String(String.lowercase_ascii(!Stubs.sha1s));;letbi_sha256s=String(String.lowercase_ascii(!Stubs.sha256s));;letbi_lcasename=letfeval_exprctxmu=function[e]->(trylet(s,_)=Dt.string_literal(eval_exprctxmue)inString(Utf8.utf8_lowercases)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbi_ucasename=letfeval_exprctxmu=function[e]->(trylet(s,_)=Dt.string_literal(eval_exprctxmue)inString(Utf8.utf8_uppercases)withe->Err(Dt.Exceptione))|l->error(Invalid_built_in_fun_argument(name,l))inf;;letbuilt_in_funs=letl=["ABS",bi_numericbi_num_abs;"BNODE",bi_bnode;"CEIL",bi_numericbi_num_ceil;"COALESCE",bi_coalesce;"CONCAT",bi_concat;"CONTAINS",bi_contains;"DATATYPE",bi_datatype;"DAY",bi_on_datebi_date_day;"ENCODE_FOR_URI",bi_encode_for_uri;"FLOOR",bi_numericbi_num_floor;"HOURS",bi_on_datebi_date_hours;"IF",bi_if;"ISBLANK",bi_isblank;"IRI",bi_iri;"ISIRI",bi_isiri;"ISLITERAL",bi_isliteral;"ISNUMERIC",bi_isnumeric;"ISURI",bi_isiri;"LANG",bi_lang;"LANGMATCHES",bi_langmatches;"LCASE",bi_lcase;"MD5",bi_hashbi_md5;"MINUTES",bi_on_datebi_date_minutes;"MONTH",bi_on_datebi_date_month;"NOW",bi_now;"RAND",bi_rand;"REGEX",bi_regex;"REPLACE",bi_replace;"ROUND",bi_numericbi_num_round;"SAMETERM",bi_sameterm;"SECONDS",bi_on_datebi_date_seconds;"SHA1",bi_hashbi_sha1;"SHA256",bi_hashbi_sha256;"STR",bi_str;"STRAFTER",bi_strafter;"STRBEFORE",bi_strbefore;"STRDT",bi_strdt;"STRENDS",bi_strends;"STRLANG",bi_strlang;"STRLEN",bi_strlen;"STRSTARTS",bi_strstarts;"STRUUID",bi_struuid;"SUBSTR",bi_substr;"UCASE",bi_ucase;"URI",bi_iri;"UUID",bi_uuid;"YEAR",bi_on_datebi_date_year;]inList.fold_left(funacc(name,f)->SMap.addname(fname)acc)SMap.emptyl;;letget_built_in_funname=letname=String.uppercase_asciinameintrySMap.findnamebuilt_in_funswithNot_found->error(Unknown_built_in_funname);;leteval_varmuv=tryletterm=Sparql_ms.mu_find_varvmuinDt.of_termtermwithNot_found->error(Unbound_variablev);;leteval_iri=functionSparql_types.Iriiri->Dt.Iriiri.iri_iri|PrefixedName_|Iriref_->assertfalse;;letreceval_numeric2f_intf_float(v1,v2)=trymatch(v1,v2)with|(Floatf1,Floatf2)->Float(f_floatf1f2)|(Int(n1,_),Int(n2,_))->Int(f_intn1n2,Rdf_.xsd_int)|((Float_)asv1,((Int_)asv2))->eval_numeric2f_intf_float(v1,Dt.floatv2)|((Int_)asv1,((Float_)asv2))->eval_numeric2f_intf_float(Dt.floatv1,v2)|v1,v2->eval_numeric2f_intf_float((Dt.numericv1),(Dt.numericv2))withe->Err(Dt.Exceptione);;leteval_plus=eval_numeric2(+)(+.)leteval_minus=eval_numeric2(-)(-.)leteval_mult=eval_numeric2(*)(*.)leteval_div=eval_numeric2(/)(/.)leteval_equal(v1,v2)=Bool(comparev1v2=0)leteval_not_equal(v1,v2)=Bool(comparev1v2<>0)leteval_lt(v1,v2)=Bool(comparev1v2<0)leteval_lte(v1,v2)=Bool(comparev1v2<=0)leteval_gt(v1,v2)=Bool(comparev1v2>0)leteval_gte(v1,v2)=Bool(comparev1v2>=0)leteval_or=function(Erre,Err_)->Erre|(Erre,v)|(v,Erre)->ifebvvthenBooltrueelseErre|v1,v2->Bool((ebvv1)||(ebvv2))leteval_and=function(Erre,Err_)->Erre|(Erre,v)|(v,Erre)->ifebvvthenErreelseBoolfalse|v1,v2->Bool((ebvv1)&&(ebvv2))leteval_bin=function|EPlus->eval_plus|EMinus->eval_minus|EMult->eval_mult|EDiv->eval_div|EEqual->eval_equal|ENotEqual->eval_not_equal|ELt->eval_lt|EGt->eval_gt|ELte->eval_lte|EGte->eval_gte|EOr->eval_or|EAnd->eval_andletreceval_expr:context->Sparql_ms.mu->expression->Dt.value=functxmue->matche.exprwithEVarv->eval_varmuv|EIriiri->eval_iriiri|EBin(e1,op,e2)->letv1=eval_exprctxmue1inletv2=eval_exprctxmue2ineval_binop(v1,v2)|ENote->letb=ebv(eval_exprctxmue)inBool(notb)|EUMinuse->letv=eval_exprctxmueineval_binEMinus(Int(0,Rdf_.xsd_int),v)|EBicc->eval_bicctxmuc|EFuncallc->eval_funcallctxmuc|ELitlit|ENumericlit|EBooleanlit->Dt.of_literallit.rdf_lit|EIn(e,l)->eval_inctxmuel|ENotIn(e,l)->matcheval_inctxmuelwithBoolb->Bool(notb)|Erre->Erre|_->assertfalseandeval_bicctxmu=function|Bic_aggagg->assertfalse|Bic_fun(name,args)->letf=get_built_in_funnameinbegintryfeval_exprctxmuargswithStubs.Not_implementedstr->error(Missing_implementationstr)end|Bic_BOUNDv->(tryignore(Sparql_ms.mu_find_varvmu);Booltruewith_->Boolfalse)|Bic_EXISTS_|Bic_NOTEXISTS_->assertfalse(* FIXME: need to translate this in algebra, with type parameter for expressions ... ? *)andeval_funcallctxmuc=letf=letiri=matchc.func_iriwithIriiri->iri.iri_iri|_->assertfalseintryIri.Map.findiri!iri_funswithNot_found->error(Unknown_funiri)inletargs=List.map(eval_exprctxmu)c.func_args.arglinfargsandeval_in=letevaleval_exprctxmuv0eacc=letv=eval_exprctxmueinletb=tryBool(comparev0v=0)withe->Err(Dt.Exceptione)ineval_or(b,acc)infunctxmue0l->matchlwith[]->Boolfalse|_->letv0=eval_exprctxmue0inList.fold_right(evaleval_exprctxmuv0)l(Boolfalse)andebv_litv=Term.mk_literal_bool(ebvv)leteval_filterctxmuc=lete=matchcwithConstrBuiltInCallc->{expr_loc=Loc.dummy_loc;expr=EBicc}|ConstrFunctionCallc->{expr_loc=Loc.dummy_loc;expr=EFuncallc}|ConstrExpre->einebv(eval_exprctxmue)letfilter_omega=letpredctxfiltersmu=List.for_all(eval_filterctxmu)filtersinfunctxfilterso->Sparql_ms.omega_filter(predctxfilters)oletjoin_omegactxo1o2=Sparql_ms.omega_joino1o2letunion_omegao1o2=Sparql_ms.omega_uniono1o2letleftjoin_omega=letpredctxfiltersmu=List.for_all(eval_filterctxmu)filtersinfunctxo1o2filters->letpred=predctxfiltersinletfilter_part=Sparql_ms.omega_join~predo1o2inletdiff_part=Sparql_ms.omega_diff_predpredo1o2inunion_omegafilter_partdiff_partletminus_omegao1o2=Sparql_ms.omega_minuso1o2letextend_omegactxovarexpr=letevalmu=Dt.to_term(eval_exprctxmuexpr)inSparql_ms.omega_extendevalovarletrecbuild_sort_comp_fun=function|OrderAsce->beginfunctxmu1mu2->letv1=eval_exprctxmu1einletv2=eval_exprctxmu2einsortby_comparev1v2end|OrderDesce->beginfunctxmu1mu2->letv1=eval_exprctxmu1einletv2=eval_exprctxmu2einsortby_comparev2v1end|OrderVarv->beginfunctxmu1mu2->letv1=tryDt.of_term(Sparql_ms.mu_find_varvmu1)withe->Dt.Err(Dt.Exceptione)inletv2=tryDt.of_term(Sparql_ms.mu_find_varvmu2)withe->Dt.Err(Dt.Exceptione)insortby_comparev1v2end|OrderConstrt->matchtwith(ConstrExpre)->build_sort_comp_fun(OrderAsce)|(ConstrBuiltInCallbic)->lete={expr_loc=Loc.dummy_loc;expr=EBicbic}inbuild_sort_comp_fun(OrderAsce)|(ConstrFunctionCallfc)->lete={expr_loc=Loc.dummy_loc;expr=EFuncallfc}inbuild_sort_comp_fun(OrderAsce);;letsort_solutions=letrecsortctxmu1mu2=function[]->0|f::q->matchfctxmu1mu2with0->sortctxmu1mu2q|n->ninfunctxcomp_funsmu1mu2->sortctxmu1mu2comp_funs;;letsort_sequencectxorder_condssolutions=(*prerr_endline
(Printf.sprintf "sort_sequence: %d solutions, %d order_conds"
(List.length solutions) (List.length order_conds));
*)letcomp_funs=List.mapbuild_sort_comp_funorder_condsinletcompare=sort_solutionsctxcomp_funsinList.sortcomparesolutions;;letproject_sequencevarsl=letvars=Sparql_algebra.VS.fold(funvacc->Sparql_types.SSet.addv.var_nameacc)varsSparql_types.SSet.emptyinList.map(Sparql_ms.mu_projectvars)lletdistinct=letf(set,acc)mu=ifSparql_ms.MuSet.memmusetthen(set,acc)else(Sparql_ms.MuSet.addmuset,mu::acc)infunl->let(_,l)=List.fold_leftf(Sparql_ms.MuSet.empty,[])linList.revl;;letslice=letrecuntillenacci=function[]->List.revacc|_wheni>=len->List.revacc|h::q->untillen(h::acc)(i+1)qinletreciterstartleni=function[]->[]|h::qwheni<start->iterstartlen(i+1)q|q->matchlenwithNone->q|Somelen->untillen[]0qinfunlofflim->matchoff,limwithNone,None->l|Someoff,None->iteroffNone0l|None,Somelim->untillim[]0l|Someoff,Somelim->iteroff(Somelim)0l;;letgroup_omega=letmake_eexpr={expr_loc=Loc.dummy_loc;expr}inletmap_conds=function|GroupBuiltInCallc->make_e(EBicc)|GroupFunctionCallc->make_e(EFuncallc)|GroupVargv->matchgv.grpvar_expr,gv.grpvarwithNone,None->assertfalse|Somee,None->e|None,Somev->make_e(EVarv)|Somee,Somev->assertfalse(* what to evaluate ? *)inleteval_onectxmue=trySome(Dt.to_term(eval_exprctxmue))with_->Noneinfunctxcondso->letconds=List.mapmap_condscondsinletevalctxmu=List.map(eval_onectxmu)condsinSparql_ms.omega_fold(funmuacc->letv=evalctxmuinleto=tryGExprMap.findvaccwithNot_found->Sparql_ms.Multimu.emptyinleto=Sparql_ms.omega_addmuoinGExprMap.addvoacc)oGExprMap.emptyletagg_countctxdmseopt=letfmu(muset,vset,n)=matcheoptwithNone->ifdthenifSparql_ms.MuSet.memmumusetthen(muset,vset,n)else(Sparql_ms.MuSet.addmumuset,vset,n+1)else(muset,vset,n+1)|Somee->matcheval_exprctxmuewithErr_->(muset,vset,n)|v->ifdthenifDt.VSet.memvvsetthen(muset,vset,n)else(muset,Dt.VSet.addvvset,n+1)else(muset,vset,n+1)inlet(_,_,n)=Sparql_ms.omega_foldfms(Sparql_ms.MuSet.empty,Dt.VSet.empty,0)inLog.debug(funm->m"COUNT(...)=%d"n);Int(n,Rdf_.xsd_int);;letagg_sumctxdmse=letfmu(vset,v)=matcheval_exprctxmuewithErr_->(vset,v)|v2->ifdthenifDt.VSet.memv2vsetthen(vset,v)else(Dt.VSet.addv2vset,eval_plus(v,v2))else(vset,eval_plus(v,v2))inlet(_,v)=Sparql_ms.omega_foldfms(Dt.VSet.empty,Int(0,Rdf_.xsd_int))inv;;letagg_foldgbasectxdmse=letfmu(vset,v)=letv2=eval_exprctxmueinifdthenifDt.VSet.memv2vsetthen(vset,v)else(Dt.VSet.addv2vset,gvv2)else(vset,gvv2)inlet(_,v)=Sparql_ms.omega_foldfms(Dt.VSet.empty,base)inv;;letagg_min=letgv1v2=matchv1,v2withErr_,_->v2|_,Err_->v1|_,_->ifsortby_comparev1v2>0thenv2elsev1inagg_foldg(Err(Dt.Exception(Error(Empty_set"MIN"))));;letagg_max=letgv1v2=matchv1,v2withErr_,_->v2|_,Err_->v1|_,_->ifsortby_comparev1v2>0thenv1elsev2inagg_foldg(Err(Dt.Exception(Error(Empty_set"MAX"))));;letagg_avgctxdmse=letfmu(vset,v,cpt)=matcheval_exprctxmuewithErr_->(vset,v,cpt)|v2->ifdthenifDt.VSet.memv2vsetthen(vset,v,cpt)else(Dt.VSet.addv2vset,eval_plus(v,v2),cpt+1)else(vset,eval_plus(v,v2),cpt+1)inlet(_,v,cpt)=Sparql_ms.omega_foldfms(Dt.VSet.empty,Int(0,Rdf_.xsd_int),0)inmatchcptwith0->Int(0,Rdf_.xsd_int)|_->eval_div(v,Int(cpt,Rdf_.xsd_int));;letagg_samplectxdmse=assertfalseletagg_group_concatctxdmsesopt=letsep=matchsoptwithNone->" "|Somes->sinletgcurrentv=trymatchDt.stringvwithErr_->current|Strings->(matchcurrentwithNone->Somes|Somecur->Some(cur^sep^s))|_->assertfalsewith_->currentinmatchagg_foldgNonectxdmsewithNone->String""|Somes->Strings;;leteval_aggctxaggms=matchaggwithBic_COUNT(d,eopt)->agg_countctxdmseopt|Bic_SUM(d,e)->agg_sumctxdmse|Bic_MIN(d,e)->agg_minctxdmse|Bic_MAX(d,e)->agg_maxctxdmse|Bic_AVG(d,e)->agg_avgctxdmse|Bic_SAMPLE(d,e)->let(_,sample_mu)=trySparql_ms.Multimu.choosemswithNot_found->assertfalseineval_exprctxsample_mue|Bic_GROUP_CONCAT(d,e,s_opt)->agg_group_concatctxdmses_opt;;letaggregationctxagggroups=letfms=eval_aggctxaggmsinGExprMap.mapfgroups;;letaggregate_join=letcompute_aggctxms(i,acc_mu)=functionAggregationagg->letterm=Dt.to_term(eval_aggctxaggms)inletvar="__agg"^(string_of_inti)in(i+1,Sparql_ms.mu_addvartermacc_mu)|_->assertfalseinletcompute_groupctxaggskeymsacc=let(_,mu)=List.fold_left(compute_aggctxms)(1,Sparql_ms.mu_0)aggsinSparql_ms.omega_addmuaccinfunevalctx(conds,a)aggs->leto=evalctxainletgroups=group_omegactxcondsoinGExprMap.fold(compute_groupctxaggs)groupsSparql_ms.Multimu.emptyletconshq=h::q;;let__print_mumu=Sparql_ms.SMap.iter(funnameterm->print_string(name^"->"^(Term.string_of_termterm)^" ; "))mu.Sparql_ms.mu_bindings;print_newline();;let__print_omegao=Sparql_ms.omega_iter__print_muo;;leteval_datablock=letmu_add=Sparql_ms.mu_addinletadd_var_valuemuv=function|DataBlockValueIri(Iriiri)->mu_addv.var_name(Term.Iriiri.iri_iri)mu|DataBlockValueRdflit|DataBlockValueNumericlit|DataBlockValueBooleanlit->letlit=lit.rdf_litinmu_addv.var_name(Term.Literallit)mu|DataBlockValueUndef->mu|DataBlockValueIri(PrefixedName_)->assertfalse|DataBlockValueIri(Iriref_)->assertfalseinletone_var=letfvaraccdbv=letmu=Sparql_ms.mu_0inletmu=add_var_valuemuvardbvinSparql_ms.omega_addmuaccinfunvdata->List.fold_left(fv)Sparql_ms.Multimu.emptydatainletfull_data=letf_rowidfvarsacc=functionNil->Sparql_ms.omega_addSparql_ms.mu_0acc|Valuedbv_list->letmu=Sparql_ms.mu_0inletmu=tryList.fold_left2add_var_valuemuvarsdbv_listwithInvalid_argument_->error(Missing_values_in_inline_dataidf)inSparql_ms.omega_addmuaccinfunidfvarsvalues->List.fold_left(f_rowidfvars)Sparql_ms.Multimu.emptyvaluesinfunctionInLineDataOneVar{idov_var=var;idov_data=data}->one_varvardata|InLineDataFull({idf_vars=vars;idf_values=values}asidf)->full_dataidfvarsvalues;;letrecevalctx=function|BGPtriples->letmoduleM=(valctx.active.Graph.bgp:Bgp.S)inletom=M.eval_bgptriplesin(*prerr_endline "BGP:"; __print_omega om;*)om|Join(BGP[],a)->evalctxa|Join(a1,a2)->leto1=evalctxa1inleto2=evalctxa2inleto=join_omegactxo1o2in(* prerr_endline "JOIN:"; __print_omega o;*)o|LeftJoin(a1,a2,filters)->leto1=evalctxa1inleto2=evalctxa2inleftjoin_omegactxo1o2filters|Filter(a,filters)->letomega=evalctxainfilter_omegactxfiltersomega|Union(a1,a2)->leto1=evalctxa1inleto2=evalctxa2inunion_omegao1o2|Graph(VIIri(PrefixedName_),_)->assertfalse|Graph(VIIri(Iriref_),_)->assertfalse|Graph(VIIri(Iriiri),a)->letiri=iri.iri_iriinletctx=letg=letname=(`Iiri)inmatchctx.dataset.Ds.get_namednamewith|None->error(No_such_graphname)|Someg->gin{ctxwithactive=g}inevalctxa|Graph(VIVarv,a)->letf_namenameacc_ms=letomega=letctx=letg=matchctx.dataset.Ds.get_namednamewith|None->error(No_such_graphname)|Someg->gin{ctxwithactive=g}inevalctxainletf_mumuo=Log.debug(funm->m"Add var %s with value %a"v.var_nameDs.pp_namename);letmu=Sparql_ms.mu_addv.var_name(Ds.term_of_namename)muinSparql_ms.omega_addmuoinletomega=Sparql_ms.omega_foldf_muomegaSparql_ms.Multimu.emptyinSparql_ms.omega_unionacc_msomegainNSet.foldf_namectx.namedSparql_ms.Multimu.empty|Extend(a,var,expr)->leto=evalctxainextend_omegactxovarexpr|Minus(a1,a2)->leto1=evalctxa1inleto2=evalctxa2inminus_omegao1o2|ToMultiseta->letl=eval_listctxainList.fold_left(funomu->Sparql_ms.omega_addmuo)Sparql_ms.Multimu.emptyl|AggregateJoin(Group(conds,a),l)->aggregate_joinevalctx(conds,a)l|AggregateJoin_->assertfalse(* AggregationJoin always has a Group *)|Aggregation_->assertfalse(* Aggregation always below AggregateJoin *)|Group(conds,a)->assertfalse(* no group without AggregationJoin above *)|DataToMultisetdatablock->eval_datablockdatablock|Project_->assertfalse|Distincta->assertfalse|Reduceda->assertfalse|Slice(a,offset,limit)->assertfalse|OrderBy(a,order_conds)->assertfalseandeval_listctx=function|OrderBy(a,order_conds)->letl=eval_listctxainsort_sequencectxorder_condsl|Project(a,vars)->letl=eval_listctxainproject_sequencevarsl|Distincta->letl=eval_listctxaindistinctl|Reduceda->letl=eval_listctxaindistinctl(* FIXME: still have to understand what Reduced means *)|Slice(a,off,lim)->letl=eval_listctxainslicelofflim|a->leto=evalctxainSparql_ms.omega_foldconso[];;