}
type text_out_spec = {out : string -> unit;
- path : M.path -> unit;
- query : M.query -> unit;
- result : M.result -> unit
+ path : (string -> unit) -> M.path -> unit;
+ query : (string -> unit) -> string -> M.query -> unit;
+ result : (string -> unit) -> string -> M.result -> unit
}
+type text_in_spec = {result_in : Lexing.lexbuf -> M.result}
+
type fun_spec = {arity_p : arity_t;
arity_s : arity_t;
- body : eval_spec -> text_out_spec ->
+ body : eval_spec -> text_out_spec -> text_in_spec ->
M.path list -> M.query list -> M.result;
- txt_out : text_out_spec ->
+ txt_out : text_out_spec ->
M.path list -> M.query list -> unit
}
exception NumberError of M.result
+type std_text_out_spec = {s_out : string -> unit;
+ s_path : M.path -> unit;
+ s_query : M.query -> unit;
+ s_result : M.result -> unit
+}
+
(* external functions implementation ****************************************)
-let int_of_set s =
- try match s with
- | [s, _] -> int_of_string s
+let std o =
+ {s_out = o.out; s_path = o.path o.out;
+ s_query = o.query o.out ""; s_result = o.result o.out "\n"
+ }
+
+type t = End
+ | Space
+ | Figure of int
+ | Error
+
+let my_int_of_string s =
+ let l = String.length s in
+ let get_t i =
+ if i = l then End else
+ match s.[i] with
+ | ' ' | '\t' | '\r' | 'n' -> Space
+ | '0' .. '9' -> Figure (Char.code s.[i] - Char.code '0')
+ | _ -> Error
+ in
+ let rec aux i xv = match get_t i, xv with
+ | Error, _
+ | End, None -> raise (Failure "int_of_string")
+ | End, Some v -> v
+ | Space, xv -> aux (succ i) xv
+ | Figure f, None -> aux (succ i) (Some f)
+ | Figure f, Some v -> aux (succ i) (Some (10 * v + f))
+ in
+ aux 0 None
+
+let int_of_set r =
+ try match r with
+ | [s, _] -> my_int_of_string s
| _ -> raise (Failure "int_of_string")
- with Failure "int_of_string" -> raise (NumberError s)
+ with Failure "int_of_string" -> raise (NumberError r)
let out_txt2 o n x1 x2 =
- o.out "(" ; o.query x1; o.out (" " ^ n ^ " "); o.query x2; o.out ")"
+ o.s_out "(" ; o.s_query x1; o.s_out (" " ^ n ^ " "); o.s_query x2; o.s_out ")"
let out_txt_ o p xl =
- if p <> [] then begin o.path p; o.out " " end;
- o.out "{"; P.flat_list o.out o.query ", " xl; o.out "}"
+ if p <> [] then begin o.s_path p; o.s_out " " end;
+ o.s_out "{"; P.flat_list o.s_out o.s_query ", " xl; o.s_out "}"
let out_txt_full o p pl xl =
- o.path p; o.out " {"; P.flat_list o.out o.path ", " pl; o.out "} {";
- P.flat_list o.out o.query ", " xl; o.out "}"
+ o.s_path p; o.s_out " {"; P.flat_list o.s_out o.s_path ", " pl; o.s_out "} {";
+ P.flat_list o.s_out o.s_query ", " xl; o.s_out "}"
let arity0 n r =
let arity_p = Const 0 in
let arity_s = Const 0 in
- let body _ _ _ _ = U.mql_true in
- let txt_out o _ _ = o.out n in
+ let body _ _ _ _ _ = r in
+ let txt_out o _ _ = (std o).s_out n in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let arity1 n f =
let arity_p = Const 0 in
let arity_s = Const 1 in
- let body e _ _ = function
+ let body e _ _ _ = function
| [x] -> f (e.eval x)
| _ -> assert false
in
let txt_out o _ = function
- | [x] -> o.out (n ^ " "); o.query x
+ | [x] -> let o = std o in o.s_out (n ^ " "); o.s_query x
| _ -> assert false
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let arity2 n f =
let arity_p = Const 0 in
let arity_s = Const 2 in
- let body e _ _ = function
+ let body e _ _ _ = function
| [x1; x2] -> f (e.eval x1) (e.eval x2)
| _ -> assert false
in
let txt_out o _ = function
- | [x1; x2] -> out_txt2 o n x1 x2
+ | [x1; x2] -> let o = std o in out_txt2 o n x1 x2
| _ -> assert false
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let count_fun =
let aux r = [string_of_int (List.length r), []] in
arity1 "#" aux
-
+
+let peek_fun =
+ let aux = function [] -> [] | hd :: _ -> [hd] in
+ arity1 "peek" aux
+
let diff_fun = arity2 "diff" U.mql_diff
let xor_fun = arity2 "xor" U.xor
let stat_fun =
let arity_p = Const 0 in
let arity_s = Const 1 in
- let body e o _ = function
+ let body e o _ _ = function
| [x] ->
let t = P.start_time () in
let r = (e.eval x) in
| _ -> assert false
in
let txt_out o _ = function
- | [x] -> o.out "stat "; o.query x
+ | [x] -> let o = std o in o.s_out "stat "; o.s_query x
| _ -> assert false
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let log_fun xml src =
let log_src e o x =
- let t = P.start_time () in o.query x;
+ let t = P.start_time () in o.s_query x;
let s = P.stop_time t in
- if C.set e.conn C.Stat then o.out (Printf.sprintf "Log source: %s\n" s);
+ if C.set e.conn C.Stat then o.s_out (Printf.sprintf "Log source: %s\n" s);
e.eval x
in
let log_res e o x =
let s = e.eval x in
- let t = P.start_time () in o.result s;
+ let t = P.start_time () in o.s_result s;
let r = P.stop_time t in
- if C.set e.conn C.Stat then o.out (Printf.sprintf "Log: %s\n" r); s
+ if C.set e.conn C.Stat then o.s_out (Printf.sprintf "Log: %s\n" r); s
in
let txt_log o =
- if xml then o.out "xml ";
- if src then o.out "source "
+ if xml then o.s_out "xml ";
+ if src then o.s_out "source "
in
let arity_p = Const 0 in
let arity_s = Const 1 in
- let body e o _ = function
- | [x] -> if src then log_src e o x else log_res e o x
+ let body e o _ _ = function
+ | [x] -> let o = std o in if src then log_src e o x else log_res e o x
| _ -> assert false
in
let txt_out o _ = function
- | [x] -> o.out "log "; txt_log o; o.query x
+ | [x] -> let o = std o in o.s_out "log "; txt_log o; o.s_query x
+ | _ -> assert false
+ in
+ {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
+
+let render_fun =
+ let arity_p = Const 0 in
+ let arity_s = Const 1 in
+ let body e o _ _ = function
+ | [x] ->
+ let rs = ref "" in
+ let out s = rs := ! rs ^ s in
+ o.result out " " (e.eval x);
+ [! rs, []]
+ | _ -> assert false
+ in
+ let txt_out o _ = function
+ | [x] -> let o = std o in o.s_out "render "; o.s_query x
+ | _ -> assert false
+ in
+ {arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
+
+let read_fun =
+ let arity_p = Const 0 in
+ let arity_s = Const 1 in
+ let body e o i _ = function
+ | [x] ->
+ let aux av =
+ let ich = open_in (fst av) in
+ let r = i.result_in (Lexing.from_channel ich) in
+ close_in ich; r
+ in
+ U.mql_iter aux (e.eval x)
+ | _ -> assert false
+ in
+ let txt_out o _ = function
+ | [x] -> let o = std o in o.s_out "read "; o.s_query x
| _ -> assert false
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
in
let arity_p = Const 0 in
let arity_s = Const 2 in
- let body e _ _ = function
+ let body e _ _ _ = function
| [y; x] ->
let l = int_of_set (e.eval y) in
U.mql_iter (aux l) (e.eval x)
| _ -> assert false
in
let txt_out o _ = function
- | [y; x] -> o.out "align "; o.query y; o.out " in "; o.query x
+ | [y; x] ->
+ let o = std o in
+ o.s_out "align "; o.s_query y; o.s_out " in "; o.s_query x
| _ -> assert false
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let if_fun =
let arity_p = Const 0 in
let arity_s = Const 3 in
- let body e _ _ = function
+ let body e _ _ _ = function
| [y; x1; x2] ->
if (e.eval y) = U.mql_false then (e.eval x2) else (e.eval x1)
| _ -> assert false
in
let txt_out o _ = function
| [y; x1; x2] ->
- o.out "if "; o.query y; o.out " then "; o.query x1;
- o.out " else "; o.query x2
+ let o = std o in
+ o.s_out "if "; o.s_query y; o.s_out " then "; o.s_query x1;
+ o.s_out " else "; o.s_query x2
| _ -> assert false
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
in
let arity_p = Const 0 in
let arity_s = Positive in
- let body e _ _ xl = iter e.eval xl in
+ let body e _ _ _ xl = iter e.eval xl in
let txt_out o _ = function
| [] -> assert false
- | [x1; x2] -> out_txt2 o "/\\" x1 x2
- | xl -> out_txt_ o ["intersect"] xl
+ | [x1; x2] -> let o = std o in out_txt2 o "/\\" x1 x2
+ | xl -> let o = std o in out_txt_ o ["intersect"] xl
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let union_fun =
let arity_p = Const 0 in
let arity_s = Any in
- let body e _ _ xl = U.mql_iter e.eval xl in
- let txt_out o _ xl = out_txt_ o [] xl
+ let body e _ _ _ xl = U.mql_iter e.eval xl in
+ let txt_out o _ xl = let o = std o in out_txt_ o [] xl
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
in
let arity_p = Const 0 in
let arity_s = Any in
- let body e _ _ xl = iter e.eval xl in
+ let body e _ _ _ xl = iter e.eval xl in
let txt_out o _ = function
- | [x1; x2] -> out_txt2 o "||" x1 x2
- | xl -> out_txt_ o ["or"] xl
+ | [x1; x2] -> let o = std o in out_txt2 o "||" x1 x2
+ | xl -> let o = std o in out_txt_ o ["or"] xl
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let and_fun =
let rec iter f = function
| [] -> U.mql_true
+ | [head] -> f head
| head :: tail ->
if f head = U.mql_false then U.mql_false else iter f tail
in
let arity_p = Const 0 in
let arity_s = Any in
- let body e _ _ xl = iter e.eval xl in
+ let body e _ _ _ xl = iter e.eval xl in
let txt_out o _ = function
- | [x1; x2] -> out_txt2 o "&&" x1 x2
- | xl -> out_txt_ o ["and"] xl
+ | [x1; x2] -> let o = std o in out_txt2 o "&&" x1 x2
+ | xl -> let o = std o in out_txt_ o ["and"] xl
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let seq_fun =
let rec iter f = function
| [] -> U.mql_true
+ | [head] -> f head
| head :: tail -> ignore (f head); iter f tail
in
let arity_p = Const 0 in
let arity_s = Any in
- let body e _ _ xl = iter e.eval xl in
+ let body e _ _ _ xl = iter e.eval xl in
let txt_out o _ = function
- | [x1; x2] -> o.query x1; o.out " ;; "; o.query x2
- | xl -> out_txt_ o ["seq"] xl
+ | [x1; x2] ->
+ let o = std o in o.s_query x1; o.s_out " ;; "; o.s_query x2
+ | xl -> let o = std o in out_txt_ o ["seq"] xl
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
let proj_set p (_, g) = U.mql_iter (proj_group p) g in
let arity_p = Const 1 in
let arity_s = Const 1 in
- let body e _ pl xl =
+ let body e _ _ pl xl =
match pl, xl with
| [p], [x] -> U.mql_iter (proj_set p) (e.eval x)
| _ -> assert false
in
let txt_out o pl xl =
match pl, xl with
- | [p], [x] -> o.out "proj "; o.path p; o.out " of "; o.query x
+ | [p], [x] ->
+ let o = std o in
+ o.s_out "proj "; o.s_path p; o.s_out " of "; o.s_query x
| _ -> assert false
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
if kg = [] then g else kg :: g
in
let keep_av l (s, g) = (s, List.fold_right (keep_set l) g []) in
- let txt_allbut o = if b then o.out "allbut " in
- let txt_path_list o l = P.flat_list o.out o.path ", " l in
+ let txt_allbut o = if b then o.s_out "allbut " in
+ let txt_path_list o l = P.flat_list o.s_out o.s_path ", " l in
let arity_p = Any in
let arity_s = Const 1 in
- let body e _ pl xl =
+ let body e _ _ pl xl =
match b, pl, xl with
| true, [], [x] -> e.eval x
| false, [], [x] -> List.map proj (e.eval x)
in
let txt_out o pl xl =
match pl, xl with
- | [], [x] -> o.out "keep "; txt_allbut o; o.query x
+ | [], [x] ->
+ let o = std o in
+ o.s_out "keep "; txt_allbut o; o.s_query x
| l, [x] ->
- o.out "keep "; txt_allbut o; txt_path_list o l;
- o.out " in "; o.query x
+ let o = std o in
+ o.s_out "keep "; txt_allbut o; txt_path_list o l;
+ o.s_out " in "; o.s_query x
| _ -> assert false
in
{arity_p = arity_p; arity_s = arity_s; body = body; txt_out = txt_out}
| ["stat"] -> stat_fun
| ["log"; "text"; "result"] -> log_fun false false
| ["log"; "text"; "source"] -> log_fun false true
+ | ["render"] -> render_fun
+ | ["read"] -> read_fun
+ | ["peek"] -> peek_fun
| ["diff"] -> diff_fun
| ["xor"] -> xor_fun
| ["sub"] -> sub_fun
| Const k when i = k -> ()
| Positive when i > 0 -> ()
| Any -> ()
- | a -> raise (ArityError (p, a, i))
+ | a -> raise (ArityError (p, a, i))
in
aux m (get_spec p).arity_p; aux n (get_spec p).arity_s
-let eval e o p pl xl = (get_spec p).body e o pl xl
+let eval e o i p pl xl = (get_spec p).body e o i pl xl
let txt_out o p pl xl =
try (get_spec p).txt_out o pl xl
- with NameError q when q = p -> out_txt_full o p pl xl
+ with NameError q when q = p -> out_txt_full (std o) p pl xl
{
open MQueryTParser
+ let strip s = String.sub s 1 (pred (String.length s))
+
let debug = false
let out s = if debug then prerr_endline s
let NUM = ['0'-'9']
let IDEN = ALPHA (NUM | ALPHA)*
let QSTR = [^ '"' '\\']+
+let Q = ['\\' '^' '\"']
+let NQ = [^ '\\' '^' '\"']
rule comm_token = parse
| "(*" { comm_token lexbuf; comm_token lexbuf }
| [^ '*' '(']* { comm_token lexbuf }
and string_token = parse
| '"' { DQ }
- | '\\' _ { STR (String.sub (Lexing.lexeme lexbuf) 1 1) }
+ | '\\' Q '^' { STR (String.sub (Lexing.lexeme lexbuf) 1 1) }
+ | '\\' NQ '^' { STR (Lexing.lexeme lexbuf) }
| QSTR { STR (Lexing.lexeme lexbuf) }
| eof { EOF }
and query_token = parse
| ']' { out "RB"; RB }
| '{' { out "LC"; LC }
| '}' { out "RC"; RC }
- | '@' { out "AT"; AT }
- | '$' { out "DL"; DL }
| '.' { out "FS"; FS }
| ',' { out "CM"; CM }
| ';' { out "SC"; SC }
| '/' { out "SL"; SL }
| ';' { out "SC"; SC }
+ | "@" IDEN { let id = Lexing.lexeme lexbuf in
+ out ("AVAR " ^ id); AVAR (strip id) }
+ | "$" IDEN { let id = Lexing.lexeme lexbuf in
+ out ("SVAR " ^ id); SVAR (strip id) }
| "add" { out "ADD" ; ADD }
| "align" { out "ALIGN" ; ALIGN }
| "allbut" { out "BUT" ; BUT }
| "of" { out "OF" ; OF }
| "or" { out "OR" ; OR }
| "pattern" { out "PAT" ; PAT }
+ | "peek" { out "PEEK" ; PEEK }
| "proj" { out "PROJ" ; PROJ }
| "property" { out "PROP" ; PROP }
+ | "read" { out "READ" ; READ }
+ | "render" { out "RENDER"; RENDER }
| "select" { out "SELECT"; SELECT }
| "seq" { out "SEQ" ; SEQ }
| "source" { out "SOURCE"; SOURCE }
| "union" { out "UNION" ; UNION }
| "where" { out "WHERE" ; WHERE }
| "xor" { out "XOR" ; XOR }
- | IDEN { let id = Lexing.lexeme lexbuf in
- out ("ID " ^ id); ID id }
| eof { out "EOF" ; EOF }
| "=" { out "BE" ; BE }
| "#" { out "COUNT" ; COUNT }
| "\\/" { out "UNION" ; UNION }
| "/\\" { out "INTER" ; INTER }
| ";;" { out "SEQ" ; SEQ }
+ | "begin" { out "LP" ; LP }
+ | "end" { out "RP" ; RP }
and result_token = parse
| SPC { result_token lexbuf }
| "(*" { comm_token lexbuf; result_token lexbuf }
- | '"' { STR (qstr string_token lexbuf) }
- | '{' { LC }
- | '}' { RC }
- | ',' { CM }
- | ';' { SC }
- | '=' { IS }
- | "attr" { ATTR }
- | eof { EOF }
+ | '"' { let str = qstr string_token lexbuf in
+ out ("STR " ^ str); STR str }
+ | '/' { out "SL" ; SL }
+ | '{' { out "LC" ; LC }
+ | '}' { out "RC" ; RC }
+ | ',' { out "CM" ; CM }
+ | ';' { out "SC" ; SC }
+ | '=' { out "BE" ; BE }
+ | "attr" { out "ATTR"; ATTR }
+ | eof { out "EOF" ; EOF }