annotate magnatune/sparql-archived/SeRQL/sparql_runtime.pl @ 27:d95e683fbd35 tip

Enable CORS on urispace redirects as well
author Chris Cannam
date Tue, 20 Feb 2018 14:52:02 +0000
parents df9685986338
children
rev   line source
Chris@0 1 /* $Id$
Chris@0 2
Chris@0 3 Part of SWI-Prolog
Chris@0 4
Chris@0 5 Author: Jan Wielemaker
Chris@0 6 E-mail: wielemak@science.uva.nl
Chris@0 7 WWW: http://www.swi-prolog.org
Chris@0 8 Copyright (C): 2004-2006, University of Amsterdam
Chris@0 9
Chris@0 10 This program is free software; you can redistribute it and/or
Chris@0 11 modify it under the terms of the GNU General Public License
Chris@0 12 as published by the Free Software Foundation; either version 2
Chris@0 13 of the License, or (at your option) any later version.
Chris@0 14
Chris@0 15 This program is distributed in the hope that it will be useful,
Chris@0 16 but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 18 GNU General Public License for more details.
Chris@0 19
Chris@0 20 You should have received a copy of the GNU Lesser General Public
Chris@0 21 License along with this library; if not, write to the Free Software
Chris@0 22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Chris@0 23
Chris@0 24 As a special exception, if you link this library with other files,
Chris@0 25 compiled with a Free Software compiler, to produce an executable, this
Chris@0 26 library does not by itself cause the resulting executable to be covered
Chris@0 27 by the GNU General Public License. This exception does not however
Chris@0 28 invalidate any other reasons why the executable file might be covered by
Chris@0 29 the GNU General Public License.
Chris@0 30 */
Chris@0 31
Chris@0 32 :- module(sparql_runtime,
Chris@0 33 [ sparql_true/1,
Chris@0 34 sparql_eval/2
Chris@0 35 ]).
Chris@0 36 :- use_module(library('semweb/rdf_db')).
Chris@0 37 :- use_module(library(xsdp_types)).
Chris@0 38
Chris@0 39 :- discontiguous
Chris@0 40 term_expansion/2.
Chris@0 41
Chris@0 42 %% sparql_true(+Term)
Chris@0 43 %
Chris@0 44 % Generated from FILTER Term, where Term must be converted to a
Chris@0 45 % boolean as 'Effective Boolean Value'.
Chris@0 46
Chris@0 47 sparql_true(Term) :- !,
Chris@0 48 typed_eval(boolean, Term, Result),
Chris@0 49 Result = boolean(true).
Chris@0 50
Chris@0 51 %% eval(+Term, -Result)
Chris@0 52
Chris@0 53 eval(Var, unbound(Var)) :-
Chris@0 54 var(Var), !.
Chris@0 55 eval(literal(Literal), Result) :- !,
Chris@0 56 eval_literal(Literal, Result).
Chris@0 57 eval(Atom, iri(Atom)) :-
Chris@0 58 atom(Atom), !.
Chris@0 59 eval(Term, Result) :-
Chris@0 60 sparql_op(Term, Types), !,
Chris@0 61 Term =.. [Op|Args0],
Chris@0 62 eval_args(Args0, Types, Args),
Chris@0 63 EvalTerm =.. [Op|Args],
Chris@0 64 op(EvalTerm, Result).
Chris@0 65 eval(function(Term), Result) :- !,
Chris@0 66 ( xsd_cast(Term, Type, Value)
Chris@0 67 -> eval_cast(Type, Value, Result)
Chris@0 68 ; eval_function(Term, Result)
Chris@0 69 ).
Chris@0 70 eval(Term, Term). % Result of sub-eval
Chris@0 71
Chris@0 72 eval_args([], [], []).
Chris@0 73 eval_args([H0|T0], [Type0|Types], [H|T]) :-
Chris@0 74 ( typed_eval(Type0, H0, H)
Chris@0 75 -> true
Chris@0 76 ; H = boolean(error)
Chris@0 77 ),
Chris@0 78 eval_args(T0, Types, T).
Chris@0 79
Chris@0 80 %% eval(+Type, +Term, -Result)
Chris@0 81 %
Chris@0 82 % Evaluate Term, converting the resulting argument to Type.
Chris@0 83
Chris@0 84 typed_eval(no_eval, Term, Term).
Chris@0 85 typed_eval(any, Term, Result) :-
Chris@0 86 eval(Term, Result).
Chris@0 87 typed_eval(simple_literal, Term, Result) :-
Chris@0 88 eval(Term, Result).
Chris@0 89 typed_eval(boolean, Term, Result) :-
Chris@0 90 eval(Term, Result0),
Chris@0 91 effective_boolean_value(Result0, Result).
Chris@0 92 typed_eval(numeric, Term, Result) :-
Chris@0 93 eval(Term, Eval),
Chris@0 94 ( Eval = numeric(_,_)
Chris@0 95 -> Result = Eval
Chris@0 96 ; throw(error(type_error(numeric, Result), _))
Chris@0 97 ).
Chris@0 98
Chris@0 99
Chris@0 100 eval_literal(type(Type, Atom), Value) :- !,
Chris@0 101 eval_typed_literal(Type, Atom, Value).
Chris@0 102 eval_literal(lang(Lang, Atom), lang(Lang, Atom)) :- !.
Chris@0 103 eval_literal(Atom, simple_literal(Atom)) :-
Chris@0 104 atom(Atom), !.
Chris@0 105
Chris@0 106 eval_typed_literal(Type, Atom, numeric(Type, Value)) :-
Chris@0 107 xsdp_numeric_uri(Type, _), !,
Chris@0 108 to_number(Atom, Value).
Chris@0 109 eval_typed_literal(Type, Atom, boolean(Atom)) :-
Chris@0 110 rdf_equal(Type, xsd:boolean), !.
Chris@0 111 eval_typed_literal(Type, Atom, date_time(Atom)) :-
Chris@0 112 rdf_equal(Type, xsd:dateTime), !.
Chris@0 113 eval_typed_literal(Type, Atom, typed_literal(Type, Atom)).
Chris@0 114
Chris@0 115 %% to_number(+NumberOrAtom, -Number)
Chris@0 116 %
Chris@0 117 % Dubious. Comes from grammar that translates 15 into
Chris@0 118 %% literal(type(xsd:integer, 15)).
Chris@0 119
Chris@0 120 to_number(N, N) :-
Chris@0 121 number(N), !.
Chris@0 122 to_number(A, N) :-
Chris@0 123 atom_number(A, N).
Chris@0 124
Chris@0 125 %% op(+Operator, -Result) is semidet.
Chris@0 126 %
Chris@0 127 % @param Operator Term of the format Op(Arg...) where each Arg
Chris@0 128 % is embedded in its type.
Chris@0 129 % @param Result Result-value, embedded in its type.
Chris@0 130
Chris@0 131 % SPARQL Unary operators
Chris@0 132 op(not(boolean(X)), boolean(Result)) :-
Chris@0 133 not(X, Result).
Chris@0 134 op(+(numeric(Type, X)), numeric(Type, X)).
Chris@0 135 op(-(numeric(Type, X)), numeric(Type, Result)) :-
Chris@0 136 Result is -X.
Chris@0 137
Chris@0 138 % SPARQL Tests, defined in section 11.4
Chris@0 139 op(bound(X), boolean(Result)) :-
Chris@0 140 (bound(X) -> Result = true ; Result = false).
Chris@0 141 op(isiri(X), boolean(Result)) :-
Chris@0 142 (isiri(X) -> Result = true ; Result = false).
Chris@0 143 op(isuri(X), boolean(Result)) :-
Chris@0 144 (isiri(X) -> Result = true ; Result = false).
Chris@0 145 op(isblank(X), boolean(Result)) :-
Chris@0 146 (isblank(X) -> Result = true ; Result = false).
Chris@0 147 op(isliteral(X), boolean(Result)) :-
Chris@0 148 (isliteral(X) -> Result = true ; Result = false).
Chris@0 149
Chris@0 150 % SPARQL Accessors
Chris@0 151 op(str(X), simple_literal(Str)) :-
Chris@0 152 str(X, Str).
Chris@0 153 op(lang(X), simple_literal(Lang)) :-
Chris@0 154 lang(X, Lang).
Chris@0 155 op(datatype(X), Type) :-
Chris@0 156 datatype(X, Type).
Chris@0 157
Chris@0 158 % SPARQL Binary operators
Chris@0 159 % Logical connectives, defined in section 11.4
Chris@0 160 op(and(boolean(A), boolean(B)), boolean(Result)) :-
Chris@0 161 sparql_and(A, B, Result).
Chris@0 162 op(or(boolean(A), boolean(B)), boolean(Result)) :-
Chris@0 163 sparql_or(A, B, Result).
Chris@0 164
Chris@0 165 % XPath Tests
Chris@0 166 op(numeric(_, X) = numeric(_, Y), boolean(Result)) :-
Chris@0 167 (X =:= Y -> Result = true ; Result = false).
Chris@0 168 op(date_time(X) = date_time(Y), boolean(Result)) :-
Chris@0 169 (X == Y -> Result = true ; Result = false).
Chris@0 170 op(numeric(_, X) \= numeric(_, Y), boolean(Result)) :-
Chris@0 171 (X =\= Y -> Result = true ; Result = false).
Chris@0 172 op(date_time(X) \= date_time(Y), boolean(Result)) :-
Chris@0 173 (X \== Y -> Result = true ; Result = false).
Chris@0 174 %<
Chris@0 175 op(numeric(_, X) < numeric(_, Y), boolean(Result)) :-
Chris@0 176 (X < Y -> Result = true ; Result = false).
Chris@0 177 op(simple_literal(X) < simple_literal(Y), boolean(Result)) :-
Chris@0 178 (X @< Y -> Result = true ; Result = false).
Chris@0 179 op(string(X) < string(Y), boolean(Result)) :-
Chris@0 180 (X @< Y -> Result = true ; Result = false).
Chris@0 181 op(date_time(X) < date_time(Y), boolean(Result)) :-
Chris@0 182 (X @< Y -> Result = true ; Result = false).
Chris@0 183 %>
Chris@0 184 op(numeric(_, X) > numeric(_, Y), boolean(Result)) :-
Chris@0 185 (X > Y -> Result = true ; Result = false).
Chris@0 186 op(simple_literal(X) > simple_literal(Y), boolean(Result)) :-
Chris@0 187 (X @> Y -> Result = true ; Result = false).
Chris@0 188 op(string(X) > string(Y), boolean(Result)) :-
Chris@0 189 (X @> Y -> Result = true ; Result = false).
Chris@0 190 op(date_time(X) > date_time(Y), boolean(Result)) :-
Chris@0 191 (X @> Y -> Result = true ; Result = false).
Chris@0 192 %=<
Chris@0 193 op(numeric(_, X) =< numeric(_, Y), boolean(Result)) :-
Chris@0 194 (X =< Y -> Result = true ; Result = false).
Chris@0 195 op(simple_literal(X) =< simple_literal(Y), boolean(Result)) :-
Chris@0 196 (X @=< Y -> Result = true ; Result = false).
Chris@0 197 op(string(X) =< string(Y), boolean(Result)) :-
Chris@0 198 (X @=< Y -> Result = true ; Result = false).
Chris@0 199 op(date_time(X) =< date_time(Y), boolean(Result)) :-
Chris@0 200 (X @=< Y -> Result = true ; Result = false).
Chris@0 201 %>=
Chris@0 202 op(numeric(_, X) >= numeric(_, Y), boolean(Result)) :-
Chris@0 203 (X >= Y -> Result = true ; Result = false).
Chris@0 204 op(simple_literal(X) >= simple_literal(Y), boolean(Result)) :-
Chris@0 205 (X @>= Y -> Result = true ; Result = false).
Chris@0 206 op(string(X) >= string(Y), boolean(Result)) :-
Chris@0 207 (X @>= Y -> Result = true ; Result = false).
Chris@0 208 op(date_time(X) >= date_time(Y), boolean(Result)) :-
Chris@0 209 (X @>= Y -> Result = true ; Result = false).
Chris@0 210
Chris@0 211 op(numeric(TX, X) * numeric(TY, Y), numeric(Type, Result)) :-
Chris@0 212 Result is X * Y,
Chris@0 213 combine_types(TX, TY, Type).
Chris@0 214 op(numeric(TX, X) / numeric(TY, Y), numeric(Type, Result)) :-
Chris@0 215 Result is X / Y,
Chris@0 216 combine_types_div(TX, TY, Type).
Chris@0 217 op(numeric(TX, X) + numeric(TY, Y), numeric(Type, Result)) :-
Chris@0 218 Result is X + Y,
Chris@0 219 combine_types(TX, TY, Type).
Chris@0 220 op(numeric(TX, X) - numeric(TY, Y), numeric(Type, Result)) :-
Chris@0 221 Result is X - Y,
Chris@0 222 combine_types(TX, TY, Type).
Chris@0 223
Chris@0 224 % SPARQL Tests, defined in section 11.4
Chris@0 225
Chris@0 226 op(X = Y, Result) :-
Chris@0 227 rdf_equal(X, Y, Result).
Chris@0 228 op(X \= Y, boolean(Result)) :-
Chris@0 229 rdf_equal(X, Y, boolean(R0)),
Chris@0 230 not(R0, Result).
Chris@0 231 op(langmatches(simple_literal(Lang),
Chris@0 232 simple_literal(Pat)),
Chris@0 233 boolean(Result)) :-
Chris@0 234 (langmatches(Lang, Pat) -> Result = true ; Result = false).
Chris@0 235 op(regex(simple_literal(Pat),
Chris@0 236 simple_literal(String)),
Chris@0 237 boolean(Result)) :-
Chris@0 238 (regex(Pat, String, '') -> Result = true ; Result = false).
Chris@0 239 op(regex(simple_literal(Pat),
Chris@0 240 simple_literal(String),
Chris@0 241 simple_literal(Flags)),
Chris@0 242 boolean(Result)) :-
Chris@0 243 (regex(Pat, String, Flags) -> Result = true ; Result = false).
Chris@0 244
Chris@0 245 % Numeric types follows the Xpath definitions of
Chris@0 246 % http://www.w3.org/TR/xpath-functions/#numeric-functions
Chris@0 247 % TBD:
Chris@0 248
Chris@0 249 %% combine_types_div(+TypeLeft, +TypeRight, -Type)
Chris@0 250
Chris@0 251 combine_types_div(TX, TY, T) :-
Chris@0 252 rdf_equal(xsd:integer, IntType),
Chris@0 253 xsdp_numeric_uri(TX, IntType),
Chris@0 254 xsdp_numeric_uri(TY, IntType), !,
Chris@0 255 rdf_equal(xsd:decimal, T).
Chris@0 256 combine_types_div(TX, TY, T) :-
Chris@0 257 combine_types(TX, TY, T).
Chris@0 258
Chris@0 259 %% combine_types(+TypeLeft, +TypeRight, -Type)
Chris@0 260
Chris@0 261 %combine_types(T, T, T) :- !.
Chris@0 262 combine_types(TL, TR, T) :-
Chris@0 263 xsdp_numeric_uri(TL, STL),
Chris@0 264 xsdp_numeric_uri(TR, STR),
Chris@0 265 promote_types(STL, STR, T).
Chris@0 266
Chris@0 267 promote_types(TL, TR, T) :-
Chris@0 268 type_index(TL, IL),
Chris@0 269 type_index(TR, IR),
Chris@0 270 TI is max(IL, IR),
Chris@0 271 type_index(T, TI), !.
Chris@0 272
Chris@0 273 term_expansion(type_index(NS:Local, I), type_index(URI, I)) :-
Chris@0 274 rdf_global_id(NS:Local, URI).
Chris@0 275
Chris@0 276 type_index(xsd:integer, 1).
Chris@0 277 type_index(xsd:decimal, 2).
Chris@0 278 type_index(xsd:float, 3).
Chris@0 279 type_index(xsd:double, 4).
Chris@0 280
Chris@0 281
Chris@0 282 %% rdf_equal(+RDFTerm, +RDFTerm, -Boolean)
Chris@0 283 %
Chris@0 284 % RDF Term equivalence. Described as lexical equivalence, except
Chris@0 285 % where we have the logic to do value equivalence.
Chris@0 286
Chris@0 287 rdf_equal(X, X, boolean(true)) :- !.
Chris@0 288 rdf_equal(boolean(A), boolean(B), boolean(Eq)) :- !,
Chris@0 289 eq_bool(A, B, Eq).
Chris@0 290 rdf_equal(numeric(_, A), numeric(_, B), boolean(Eq)) :- !,
Chris@0 291 (A =:= B -> Eq = true ; Eq = false).
Chris@0 292 rdf_equal(_, _, boolean(false)).
Chris@0 293
Chris@0 294 eq_bool(X, X, true) :- !.
Chris@0 295 eq_bool(true, false, false) :- !.
Chris@0 296 eq_bool(false, true, false) :- !.
Chris@0 297 eq_bool(X, Y, true) :-
Chris@0 298 boolean_value(X, V1),
Chris@0 299 boolean_value(Y, V2),
Chris@0 300 V1 == V2, !.
Chris@0 301 eq_bool(_, _, false).
Chris@0 302
Chris@0 303 %% boolean_value(+Content, -Bool)
Chris@0 304 %
Chris@0 305 % Convert the value from literal(xsd:boolean, Content) into
Chris@0 306 % either 'true' or 'false'.
Chris@0 307
Chris@0 308 boolean_value(true, true) :- !.
Chris@0 309 boolean_value(false, false) :- !.
Chris@0 310 boolean_value('0', false) :- !.
Chris@0 311 boolean_value('', false) :- !.
Chris@0 312 boolean_value(False, false) :-
Chris@0 313 downcase_atom(False, false), !.
Chris@0 314 boolean_value(_, true).
Chris@0 315
Chris@0 316
Chris@0 317 :- dynamic
Chris@0 318 sparql_op/2. % +Term, -Types
Chris@0 319
Chris@0 320 make_op_declarations :-
Chris@0 321 retractall(sparql_op(_,_)),
Chris@0 322 findall(Head, clause(op(Head, _), _), Heads0),
Chris@0 323 sort(Heads0, Heads),
Chris@0 324 make_op_declarations(Heads).
Chris@0 325
Chris@0 326 make_op_declarations([]).
Chris@0 327 make_op_declarations([H0|T0]) :-
Chris@0 328 functor(H0, Op, Arity),
Chris@0 329 functor(G, Op, Arity),
Chris@0 330 same_functor(G, T0, T1, T2),
Chris@0 331 make_op_declaration([H0|T1]),
Chris@0 332 make_op_declarations(T2).
Chris@0 333
Chris@0 334 same_functor(F, [H|T0], [H|T], L) :-
Chris@0 335 \+ \+ F = H, !,
Chris@0 336 same_functor(F, T0, T, L).
Chris@0 337 same_functor(_, L, [], L).
Chris@0 338
Chris@0 339 make_op_declaration([Op|T]) :-
Chris@0 340 functor(Op, Name, Arity),
Chris@0 341 functor(G, Name, Arity),
Chris@0 342 Op =.. [Name|Args],
Chris@0 343 make_types(Args, 1, T, Types),
Chris@0 344 assert(sparql_op(G, Types)).
Chris@0 345
Chris@0 346 make_types([], _, _, []).
Chris@0 347 make_types([H0|T0], I, Alt, [H|T]) :-
Chris@0 348 alt_types(Alt, I, AT),
Chris@0 349 list_to_set([H0|AT], Types),
Chris@0 350 make_type(Types, H),
Chris@0 351 I2 is I + 1,
Chris@0 352 make_types(T0, I2, Alt, T).
Chris@0 353
Chris@0 354 alt_types([], _, []).
Chris@0 355 alt_types([H0|T0], I, [H|T]) :-
Chris@0 356 arg(I, H0, H),
Chris@0 357 alt_types(T0, I, T).
Chris@0 358
Chris@0 359 make_type([T], no_eval) :-
Chris@0 360 var(T), !.
Chris@0 361 make_type([boolean(_)], boolean) :- !.
Chris@0 362 make_type([numeric(_, _)], numeric) :- !.
Chris@0 363 make_type([simple_literal(_)], simple_literal) :- !.
Chris@0 364 make_type(_, any).
Chris@0 365
Chris@0 366 :- make_op_declarations.
Chris@0 367
Chris@0 368 /*******************************
Chris@0 369 * CASTS *
Chris@0 370 *******************************/
Chris@0 371
Chris@0 372 %% xsd_cast(+Term, -Type, -Arg)
Chris@0 373 %
Chris@0 374 % Deals with xsd:dateTime(?a), casting ?a to the XML Schema type
Chris@0 375 % dateTime. Supported types are the numeric types, xsd:boolean and
Chris@0 376 % xsd:dateTime.
Chris@0 377
Chris@0 378 term_expansion(xsd_casts, Clauses) :-
Chris@0 379 findall(Clause, xsd_cast_clause(Clause), Clauses).
Chris@0 380
Chris@0 381 xsd_cast_clause(xsd_cast(Term, Type, Arg)) :-
Chris@0 382 ( xsdp_numeric_uri(Type, _)
Chris@0 383 ; rdf_equal(xsd:dateTime, Type)
Chris@0 384 ; rdf_equal(xsd:boolean, Type)
Chris@0 385 ),
Chris@0 386 Term =.. [Type,Arg].
Chris@0 387
Chris@0 388 xsd_casts.
Chris@0 389
Chris@0 390 %% eval_cast(+Type, +Value, -Result)
Chris@0 391 %
Chris@0 392 % Case Value to Type, resulting in a typed literal. Can we only
Chris@0 393 % case simple literals?
Chris@0 394
Chris@0 395 eval_cast(Type, literal(Value), Result) :-
Chris@0 396 atom(Value), !,
Chris@0 397 eval_typed_literal(Type, Value, Result).
Chris@0 398
Chris@0 399
Chris@0 400 %% eval_function(+Term, -Result)
Chris@0 401 %
Chris@0 402 % Eval user-defined function. User-defined functions are of the
Chris@0 403 % form sparql:function(Term, Result).
Chris@0 404
Chris@0 405 eval_function(Term0, Result) :-
Chris@0 406 Term0 =.. [F|Args0],
Chris@0 407 eval_args(Args0, Args),
Chris@0 408 Term =.. [F|Args],
Chris@0 409 sparql:function(Term, Result0), !,
Chris@0 410 eval(Result0, Result).
Chris@0 411 eval_function(Term, boolean(error)) :-
Chris@0 412 functor(Term, Name, Arity),
Chris@0 413 functor(Gen, Name, Arity),
Chris@0 414 clause(sparql:function(Gen, _Result), _Body), !.
Chris@0 415 eval_function(Term, _) :-
Chris@0 416 functor(Term, Name, Arity),
Chris@0 417 throw(error(existence_error(sparql_function, Name/Arity), _)).
Chris@0 418
Chris@0 419 eval_args([], []).
Chris@0 420 eval_args([H0|T0], [H|T]) :-
Chris@0 421 sparql_eval(H0, H),
Chris@0 422 eval_args(T0, T).
Chris@0 423
Chris@0 424
Chris@0 425 /*******************************
Chris@0 426 * SUPPORT PREDICATES *
Chris@0 427 *******************************/
Chris@0 428
Chris@0 429 %% not(+Bool, -Negated)
Chris@0 430
Chris@0 431 not(true, false).
Chris@0 432 not(false, true).
Chris@0 433
Chris@0 434 %% bound(X)
Chris@0 435 %
Chris@0 436 % Does not evaluate args. If the argument is a function it
Chris@0 437 % is always bound.
Chris@0 438
Chris@0 439 bound(X) :- nonvar(X).
Chris@0 440
Chris@0 441 %% str(+RDFTerm, -Atom)
Chris@0 442 %
Chris@0 443 % Extract lexical representation from RDFTerm.
Chris@0 444
Chris@0 445 str(Var, _) :-
Chris@0 446 var(Var), !, fail.
Chris@0 447 str(literal(X), Str) :- !,
Chris@0 448 str_literal(X, Str).
Chris@0 449 str(IRI, IRI) :-
Chris@0 450 atom(IRI), !,
Chris@0 451 \+ rdf_is_bnode(IRI).
Chris@0 452 str(Expr, Str) :-
Chris@0 453 eval(Expr, Value),
Chris@0 454 str_value(Value, Str).
Chris@0 455
Chris@0 456 str_value(simple_literal(X), X) :- !.
Chris@0 457 str_value(boolean(X), X) :- !.
Chris@0 458 str_value(string(X), X) :- !.
Chris@0 459 str_value(iri(IRI), IRI) :- !.
Chris@0 460
Chris@0 461 str_literal(type(_, Str), Str) :- !.
Chris@0 462 str_literal(lang(_, Str), Str) :- !.
Chris@0 463 str_literal(Str, Str).
Chris@0 464
Chris@0 465 %% lang(+RDFTerm, -Lang)
Chris@0 466 %
Chris@0 467 % Extract language specification from an RDFTerm
Chris@0 468
Chris@0 469 lang(0, _) :- !, fail. % catch variables.
Chris@0 470 lang(lang(Lang, _), Lang) :- !.
Chris@0 471 lang(literal(lang(Lang, _)), Lang) :- !.
Chris@0 472 lang(literal(_), ''). % Fail on typed?
Chris@0 473
Chris@0 474 %% datatype(+RDFTerm, -IRI)
Chris@0 475 %
Chris@0 476 % Extract type specification from an RDFTerm
Chris@0 477
Chris@0 478 datatype(0, _) :- !, fail.
Chris@0 479 datatype(literal(type(Type, _)), iri(Type)) :- !.
Chris@0 480 datatype(numeric(Type, _), iri(Type)) :- !.
Chris@0 481 datatype(boolean(_), iri(Type)) :- !,
Chris@0 482 rdf_equal(xsd:boolean, Type).
Chris@0 483 datatype(Expr, Type) :-
Chris@0 484 eval(Expr, Value),
Chris@0 485 Value \== Expr,
Chris@0 486 datatype(Value, Type).
Chris@0 487
Chris@0 488
Chris@0 489 %% sparql_and(+A, +B, -Result)
Chris@0 490
Chris@0 491 sparql_and(true, true, true) :- !.
Chris@0 492 sparql_and(true, error, error) :- !.
Chris@0 493 sparql_and(error, true, error) :- !.
Chris@0 494 sparql_and(_, _, false).
Chris@0 495
Chris@0 496 %% sparql_or(+A, +B, -Result)
Chris@0 497
Chris@0 498 sparql_or(true, _, true) :- !.
Chris@0 499 sparql_or(_, true, true) :- !.
Chris@0 500 sparql_or(false, false, false) :- !.
Chris@0 501 sparql_or(_, _, error).
Chris@0 502
Chris@0 503 %% langmatches(+Lang, +Pattern)
Chris@0 504 %
Chris@0 505 % Section 11.4.11 function LangMatches. This is slow. Guess we
Chris@0 506 % better move this to the RDF library. Note that none of the
Chris@0 507 % functions return a language qualified literal and we therefore
Chris@0 508 % we only have to consider the case where the argument is a
Chris@0 509 % variable also appearing in the object-field of a rdf/3 call.
Chris@0 510
Chris@0 511 langmatches('', _) :- !, fail.
Chris@0 512 langmatches(_, *).
Chris@0 513 langmatches(Lang, Pattern) :-
Chris@0 514 atom_codes(Lang, LC),
Chris@0 515 atom_codes(Pattern, PC),
Chris@0 516 langmatches_codes(PC, LC).
Chris@0 517
Chris@0 518 langmatches_codes([], []) :- !.
Chris@0 519 langmatches_codes([], [0'-|_]) :- !.
Chris@0 520 langmatches_codes([H|TP], [H|TC]) :- !,
Chris@0 521 langmatches_codes(TP, TC).
Chris@0 522 langmatches_codes([HP|TP], [HC|TC]) :- !,
Chris@0 523 code_type(L, to_lower(HP)),
Chris@0 524 code_type(L, to_lower(HC)),
Chris@0 525 langmatches_codes(TP, TC).
Chris@0 526
Chris@0 527 %% isiri(+IRI)
Chris@0 528 %
Chris@0 529 % True if IRI is an IRI. We get the argument un-evaluated.
Chris@0 530
Chris@0 531 isiri(IRI) :-
Chris@0 532 atom(IRI), !,
Chris@0 533 \+ rdf_is_bnode(IRI).
Chris@0 534 isiri(literal(_)) :- !, fail.
Chris@0 535 isiri(Expr) :-
Chris@0 536 eval(Expr, Value),
Chris@0 537 Value = iri(IRI),
Chris@0 538 \+ rdf_is_bnode(IRI).
Chris@0 539
Chris@0 540 isblank(IRI) :-
Chris@0 541 atom(IRI), !,
Chris@0 542 rdf_is_bnode(IRI).
Chris@0 543 isblank(literal(_)) :- !, fail.
Chris@0 544 isblank(Expr) :-
Chris@0 545 eval(Expr, Value),
Chris@0 546 Value = iri(IRI),
Chris@0 547 rdf_is_bnode(IRI).
Chris@0 548
Chris@0 549 isliteral(literal(_)) :- !.
Chris@0 550 isliteral(Atom) :-
Chris@0 551 atom(Atom), !, fail.
Chris@0 552 isliteral(Expr) :-
Chris@0 553 eval(Expr, Value),
Chris@0 554 Value \= iri(_).
Chris@0 555
Chris@0 556
Chris@0 557 %% regex(+String, +Pattern, +Flags)
Chris@0 558 %
Chris@0 559 % TBD:
Chris@0 560 % - Avoid XPCE
Chris@0 561 % - Complete flags
Chris@0 562
Chris@0 563 :- dynamic
Chris@0 564 pattern_cache/3. % Pattern, Flags, Regex
Chris@0 565
Chris@0 566 regex(String, Pattern, Flags) :-
Chris@0 567 pattern_cache(Pattern, Flags, Regex), !,
Chris@0 568 send(Regex, search, string(String)).
Chris@0 569 regex(String, Pattern, Flags) :-
Chris@0 570 make_regex(Pattern, Flags, Regex),
Chris@0 571 send(Regex, lock_object, @on),
Chris@0 572 asserta(pattern_cache(Pattern, Flags, Regex)),
Chris@0 573 send(Regex, search, string(String)).
Chris@0 574
Chris@0 575 make_regex(Pattern, i, Regex) :- !,
Chris@0 576 new(Regex, regex(Pattern, @off)).
Chris@0 577 make_regex(Pattern, _, Regex) :- !,
Chris@0 578 new(Regex, regex(Pattern)).
Chris@0 579
Chris@0 580 %% effective_boolean_value(+Expr, -Bool)
Chris@0 581 %
Chris@0 582 % See SPARQL document, section 11.2.2: Effecitive Boolean Value
Chris@0 583
Chris@0 584 effective_boolean_value(boolean(X), boolean(True)) :- !,
Chris@0 585 True = X.
Chris@0 586 effective_boolean_value(string(X), boolean(True)) :- !,
Chris@0 587 (X == '' -> True = false ; True = true).
Chris@0 588 effective_boolean_value(simple_literal(X), boolean(True)) :- !,
Chris@0 589 (X == '' -> True = false ; True = true).
Chris@0 590 effective_boolean_value(numeric(_, X), boolean(True)) :- !,
Chris@0 591 (X =:= 0 -> True = false ; True = true).
Chris@0 592 effective_boolean_value(_, boolean(error)).
Chris@0 593
Chris@0 594 %% sparql_eval(+Expr, -Results)
Chris@0 595 %
Chris@0 596 % Evaluate an expression.
Chris@0 597
Chris@0 598 sparql_eval(Expr, Expr) :-
Chris@0 599 is_rdf(Expr), !.
Chris@0 600 sparql_eval(Expr, Result) :-
Chris@0 601 eval(Expr, Result0),
Chris@0 602 to_rdf(Result0, Result).
Chris@0 603
Chris@0 604 to_rdf(numeric(Type, Value), literal(type(Type, Atom))) :-
Chris@0 605 atom_number(Atom, Value).
Chris@0 606 to_rdf(boolean(Val), literal(Type, Val)) :-
Chris@0 607 rdf_equal(xsd:boolean, Type).
Chris@0 608 to_rdf(type(T, Val), literal(type(T, Val))).
Chris@0 609 to_rdf(simple_literal(L), literal(L)).
Chris@0 610 to_rdf(iri(IRI), IRI).
Chris@0 611
Chris@0 612 %% is_rdf(+Term)
Chris@0 613 %
Chris@0 614 % True if Term is a valid RDF term.
Chris@0 615
Chris@0 616 is_rdf(0) :- !, fail. % catch variables
Chris@0 617 is_rdf(IRI) :- atom(IRI).
Chris@0 618 is_rdf(literal(_)).