1 (* Copyright (C) 2000, HELM Team.
3 * This file is part of HELM, an Hypertextual, Electronic
4 * Library of Mathematics, developed at the Computer Science
5 * Department, University of Bologna, Italy.
7 * HELM is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * HELM is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with HELM; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 * For details, see the HELM World-Wide-Web page,
23 * http://cs.unibo.it/helm/.
26 (* AUTOR: Ferruccio Guidi <fguidi@cs.unibo.it>
34 (* external function specification ******************************************)
36 type arity_t = Const of int
40 type eval_spec = {eval : M.query -> M.result;
44 type text_out_spec = {out : string -> unit;
45 path : M.path -> unit;
46 query : M.query -> unit;
47 result : M.result -> unit
50 type fun_spec = {arity_p : arity_t;
52 body : eval_spec -> text_out_spec ->
53 M.path list -> M.query list -> M.result;
54 txt_out : text_out_spec ->
55 M.path list -> M.query list -> unit
58 exception ArityError of M.path * arity_t * int
60 exception NameError of M.path
62 exception NumberError of M.result
64 (* external functions implementation ****************************************)
68 | [s, _] -> int_of_string s
69 | _ -> raise (Failure "int_of_string")
70 with Failure "int_of_string" -> raise (NumberError s)
72 let out_txt2 o n x1 x2 =
73 o.out "(" ; o.query x1; o.out (" " ^ n ^ " "); o.query x2; o.out ")"
76 if p <> [] then begin o.path p; o.out " " end;
77 o.out "{"; P.flat_list o.out o.query ", " xl; o.out "}"
79 let out_txt_full o p pl xl =
80 o.path p; o.out " {"; P.flat_list o.out o.path ", " pl; o.out "} {";
81 P.flat_list o.out o.query ", " xl; o.out "}"
84 let arity_p = Const 0 in
85 let arity_s = Const 0 in
86 let body _ _ _ _ = U.mql_true in
87 let txt_out o _ _ = o.out n in
88 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
91 let arity_p = Const 0 in
92 let arity_s = Const 1 in
93 let body e _ _ = function
97 let txt_out o _ = function
98 | [x] -> o.out (n ^ " "); o.query x
101 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
104 let arity_p = Const 0 in
105 let arity_s = Const 2 in
106 let body e _ _ = function
107 | [x1; x2] -> f (e.eval x1) (e.eval x2)
110 let txt_out o _ = function
111 | [x1; x2] -> out_txt2 o n x1 x2
114 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
117 let s = if b then "false" else "empty" in
120 let true_fun = arity0 "true" U.mql_true
123 let aux r = if r = U.mql_false then U.mql_true else U.mql_false in
127 let aux r = [string_of_int (List.length r), []] in
130 let diff_fun = arity2 "diff" U.mql_diff
132 let xor_fun = arity2 "xor" U.xor
134 let sub_fun = arity2 "sub" U.set_sub
136 let meet_fun = arity2 "meet" U.set_meet
138 let eq_fun = arity2 "==" U.set_eq
142 if int_of_set v1 <= int_of_set v2 then U.mql_true else U.mql_false
148 if int_of_set v1 < int_of_set v2 then U.mql_true else U.mql_false
153 let arity_p = Const 0 in
154 let arity_s = Const 1 in
155 let body e o _ = function
157 let t = P.start_time () in
158 let r = (e.eval x) in
159 let s = P.stop_time t in
160 o.out (Printf.sprintf "Stat: %s,%i\n" s (List.length r));
164 let txt_out o _ = function
165 | [x] -> o.out "stat "; o.query x
168 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
170 let log_fun xml src =
172 let t = P.start_time () in o.query x;
173 let s = P.stop_time t in
174 if C.set e.conn C.Stat then o.out (Printf.sprintf "Log source: %s\n" s);
179 let t = P.start_time () in o.result s;
180 let r = P.stop_time t in
181 if C.set e.conn C.Stat then o.out (Printf.sprintf "Log: %s\n" r); s
184 if xml then o.out "xml ";
185 if src then o.out "source "
187 let arity_p = Const 0 in
188 let arity_s = Const 1 in
189 let body e o _ = function
190 | [x] -> if src then log_src e o x else log_res e o x
193 let txt_out o _ = function
194 | [x] -> o.out "log "; txt_log o; o.query x
197 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
201 let c = String.length v in
202 if c < l then [(String.make (l - c) ' ' ^ v), g] else [v, g]
204 let arity_p = Const 0 in
205 let arity_s = Const 2 in
206 let body e _ _ = function
208 let l = int_of_set (e.eval y) in
209 U.mql_iter (aux l) (e.eval x)
212 let txt_out o _ = function
213 | [y; x] -> o.out "align "; o.query y; o.out " in "; o.query x
216 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
219 let arity_p = Const 0 in
220 let arity_s = Const 3 in
221 let body e _ _ = function
223 if (e.eval y) = U.mql_false then (e.eval x2) else (e.eval x1)
226 let txt_out o _ = function
228 o.out "if "; o.query y; o.out " then "; o.query x1;
229 o.out " else "; o.query x2
232 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
235 let rec iter f = function
238 | head :: tail -> U.mql_intersect (f head) (iter f tail)
240 let arity_p = Const 0 in
241 let arity_s = Positive in
242 let body e _ _ xl = iter e.eval xl in
243 let txt_out o _ = function
245 | [x1; x2] -> out_txt2 o "/\\" x1 x2
246 | xl -> out_txt_ o ["intersect"] xl
248 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
251 let arity_p = Const 0 in
253 let body e _ _ xl = U.mql_iter e.eval xl in
254 let txt_out o _ xl = out_txt_ o [] xl
256 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
259 let rec iter f = function
263 if r1 = U.mql_false then (iter f tail) else r1
265 let arity_p = Const 0 in
267 let body e _ _ xl = iter e.eval xl in
268 let txt_out o _ = function
269 | [x1; x2] -> out_txt2 o "||" x1 x2
270 | xl -> out_txt_ o ["or"] xl
272 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
275 let rec iter f = function
278 if f head = U.mql_false then U.mql_false else iter f tail
280 let arity_p = Const 0 in
282 let body e _ _ xl = iter e.eval xl in
283 let txt_out o _ = function
284 | [x1; x2] -> out_txt2 o "&&" x1 x2
285 | xl -> out_txt_ o ["and"] xl
287 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
290 let rec iter f = function
292 | head :: tail -> ignore (f head); iter f tail
294 let arity_p = Const 0 in
296 let body e _ _ xl = iter e.eval xl in
297 let txt_out o _ = function
298 | [x1; x2] -> o.query x1; o.out " ;; "; o.query x2
299 | xl -> out_txt_ o ["seq"] xl
301 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
304 let proj_group_aux p (q, v) = if q = p then U.mql_subj v else [] in
305 let proj_group p a = U.mql_iter (proj_group_aux p) a in
306 let proj_set p (_, g) = U.mql_iter (proj_group p) g in
307 let arity_p = Const 1 in
308 let arity_s = Const 1 in
311 | [p], [x] -> U.mql_iter (proj_set p) (e.eval x)
314 let txt_out o pl xl =
316 | [p], [x] -> o.out "proj "; o.path p; o.out " of "; o.query x
319 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
322 let proj (r, _) = (r, []) in
323 let keep_path l (p, v) t = if List.mem p l = b then t else (p, v) :: t in
324 let keep_grp l a = List.fold_right (keep_path l) a [] in
326 let kg = keep_grp l a in
327 if kg = [] then g else kg :: g
329 let keep_av l (s, g) = (s, List.fold_right (keep_set l) g []) in
330 let txt_allbut o = if b then o.out "allbut " in
331 let txt_path_list o l = P.flat_list o.out o.path ", " l in
333 let arity_s = Const 1 in
336 | true, [], [x] -> e.eval x
337 | false, [], [x] -> List.map proj (e.eval x)
338 | _, l, [x] -> List.map (keep_av l) (e.eval x)
341 let txt_out o pl xl =
343 | [], [x] -> o.out "keep "; txt_allbut o; o.query x
345 o.out "keep "; txt_allbut o; txt_path_list o l;
346 o.out " in "; o.query x
349 {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
351 (* external functions interface *********************************************)
353 let get_spec = function
354 | ["empty"] -> false_fun false
355 | ["false"] -> false_fun true
356 | ["true"] -> true_fun
358 | ["count"] -> count_fun
359 | ["stat"] -> stat_fun
360 | ["log"; "text"; "result"] -> log_fun false false
361 | ["log"; "text"; "source"] -> log_fun false true
362 | ["diff"] -> diff_fun
365 | ["meet"] -> meet_fun
369 | ["align"] -> align_fun
371 | ["intersect"] -> intersect_fun
372 | ["union"] -> union_fun
376 | ["proj"] -> proj_fun
377 | ["keep"; "these"] -> keep_fun false
378 | ["keep"; "allbut"] -> keep_fun true
379 | p -> raise (NameError p)
381 let check_arity p m n =
383 | Const k when i = k -> ()
384 | Positive when i > 0 -> ()
386 | a -> raise (ArityError (p, a, i))
388 aux m (get_spec p).arity_p; aux n (get_spec p).arity_s
390 let eval e o p pl xl = (get_spec p).body e o pl xl
392 let txt_out o p pl xl =
393 try (get_spec p).txt_out o pl xl
394 with NameError q when q = p -> out_txt_full o p pl xl