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(_)).
|