1 (***********************************************************************)
5 (* Kim Nguyen, LRI UMR8623 *)
6 (* Université Paris-Sud & CNRS *)
8 (* Copyright 2010-2012 Université Paris-Sud and Centre National de la *)
9 (* Recherche Scientifique. All rights reserved. This file is *)
10 (* distributed under the terms of the GNU Lesser General Public *)
11 (* License, with the special exception on linking described in file *)
14 (***********************************************************************)
16 #load "pa_extend.cmo";;
20 type path = Absolute of step list | Relative of step list
21 and step = axis * test *predicate
22 and axis = Self | Attribute | Child | Descendant | DescendantOrSelf | FollowingSibling
23 | Parent | Ancestor | AncestorOrSelf | PrecedingSibling | Preceding | Following
25 and test = Simple of QNameSet.t
28 and predicate = Or of predicate*predicate
29 | And of predicate*predicate
32 and expression = Path of path
33 | Function of string*expression list
40 let text = QNameSet.singleton QName.text
41 let node = QNameSet.any
44 QNameSet.from_list [ QName.text;
48 let t_text = Simple text
49 let t_node = Simple node
50 let t_star = Simple star
54 let pp fmt = Format.fprintf fmt
55 let print_list printer fmt sep l =
58 | [e] -> printer fmt e
59 | e::es -> printer fmt e; List.iter (fun x -> pp fmt sep;printer fmt x) es
64 | Absolute l -> pp fmt "/"; l
67 Pretty.print_list ~sep:"/" print_step fmt l
68 and print_step fmt (axis, test, predicate) =
69 print_axis fmt axis;pp fmt "::";print_test fmt test;
72 | _ -> pp fmt "["; print_predicate fmt predicate; pp fmt "]"
73 and print_axis fmt a = pp fmt "%s" (match a with
76 | Descendant -> "descendant"
77 | DescendantOrSelf -> "descendant-or-self"
78 | FollowingSibling -> "following-sibling"
79 | Attribute -> "attribute"
80 | Ancestor -> "ancestor"
81 | AncestorOrSelf -> "ancestor-or-self"
82 | PrecedingSibling -> "preceding-sibling"
86 and print_test fmt ts =
88 pp fmt "%s" (List.assoc ts
93 Not_found -> pp fmt "%s"
95 Simple t -> if QNameSet.is_finite t
96 then QName.to_string (QNameSet.choose t)
100 and print_predicate fmt = function
101 | Or(p,q) -> print_predicate fmt p; pp fmt " or "; print_predicate fmt q
102 | And(p,q) -> print_predicate fmt p; pp fmt " and "; print_predicate fmt q
103 | Not p -> pp fmt "not "; print_predicate fmt p
104 | Expr e -> print_expression fmt e
106 and print_expression fmt = function
107 | Path p -> print fmt p
110 Pretty.print_list ~sep:"," print_expression fmt l;
112 | Int i -> pp fmt "%i" i
113 | String s -> pp fmt "\"%s\"" s
114 | t -> pp fmt "%b" (t== True)
121 let predopt = function None -> Expr True | Some p -> p
123 module Gram = Camlp4.Struct.Grammar.Static.Make(Ulexer)
124 let query = Gram.Entry.mk "query"
126 exception Error of Gram.Loc.t*string
127 let test_of_keyword t loc =
132 | "and" | "not" | "or" -> QNameSet.singleton (QName.of_string t)
133 | _ -> raise (Error(loc,"Invalid test name "^t ))
135 let axis_to_string a = let r = Format.str_formatter in
136 print_axis r a; Format.flush_str_formatter()
143 query : [ [ p = path; `EOI -> p ]]
147 [ "/" ; l = slist -> Absolute (List.rev l) ]
148 | [ l = slist -> Relative (List.rev l) ]
153 [ l = slist ;"/"; s = step -> s @ l ]
154 | [ l = slist ; "//"; s = step -> s@[(DescendantOrSelf, t_node ,Expr True)]@l]
159 (* yurk, this is done to parse stuff like
160 a/b/descendant/a where descendant is actually a tag name :(
161 if OPT is None then this is a child::descendant if not, this is a real axis name
165 [ axis = axis ; o = OPT ["::" ; t = test -> t ] ; p = top_pred ->
168 | Some(t) -> (axis,t,p)
169 | None -> (Child,Simple (QNameSet.singleton (QName.of_string (axis_to_string axis))),p)
171 | Following -> [ (DescendantOrSelf,t,p);
172 (FollowingSibling, t_star,Expr(True));
173 (Ancestor, t_star ,Expr(True)) ]
175 | Preceding -> [ (DescendantOrSelf,t,p);
176 (PrecedingSibling,t_star,Expr(True));
177 (Ancestor,t_star,Expr(True)) ]
182 | [ "." ; p = top_pred -> [(Self, t_node,p)] ]
183 | [ ".." ; p = top_pred -> [(Parent,t_star,p)] ]
184 | [ test = test; p = top_pred -> [(Child,test, p)] ]
185 | [ att = ATT ; p = top_pred ->
187 | "*" -> [(Attribute,t_star,p)]
188 | _ -> [(Attribute, Simple (QNameSet.singleton (QName.of_string att)) ,p )]]
192 [ p = OPT [ "["; p=predicate ;"]" -> p ] -> predopt p ]
196 [ "self" -> Self | "child" -> Child | "descendant" -> Descendant
197 | "descendant-or-self" -> DescendantOrSelf
198 | "ancestor-or-self" -> AncestorOrSelf
199 | "following-sibling" -> FollowingSibling
200 | "attribute" -> Attribute
202 | "ancestor" -> Ancestor
203 | "preceding-sibling" -> PrecedingSibling
204 | "preceding" -> Preceding
205 | "following" -> Following
211 [ s = KWD -> Simple (test_of_keyword s _loc) ]
212 | [ t = TAG -> Simple (QNameSet.singleton (QName.of_string t)) ]
218 [ p = predicate; "or"; q = predicate -> Or(p,q) ]
219 | [ p = predicate; "and"; q = predicate -> And(p,q) ]
220 | [ "not" ; p = predicate -> Not p ]
221 | [ "("; p = predicate ;")" -> p ]
222 | [ e = expression -> Expr e ]
226 [ f = TAG; "("; args = LIST0 expression SEP "," ; ")" -> Function(f,args)]
227 | [ `INT(i) -> Int (i) ]
228 | [ s = STRING -> String s ]
229 | [ p = path -> Path p ]
230 | [ "("; e = expression ; ")" -> e ]
239 query : [ [ p = location_path; `EOI -> p ]]
244 [ "/" ; l = OPT relative_location_path ->
245 let l = match l with None -> [] | Some l' -> l' in Absolute l ]
246 | [ l = relative_location_path -> Relative l ]
247 | [ l = abbrev_absolute_location_path -> l ]
252 relative_location_path : [
253 [ s = step -> [ s ] ]
254 | [ l = relative_location_path ; "/"; s = step -> l @ [ s ] ]
255 | [ l = abbrev_relative_location_path -> l ]
261 [ a = axis_specifier ; n = node_test ; p = OPT predicate ->
262 let p = match p with Some p' -> p' | None -> Expr(True) in
265 | [ a = abbrev_step -> a ]
269 [ a = axis_name ; "::" -> a ]
270 | [ a = abbrev_axis_specifier -> a ]
274 [ "self" -> Self | "child" -> Child | "descendant" -> Descendant
275 | "descendant-or-self" -> DescendantOrSelf
276 | "ancestor-or-self" -> AncestorOrSelf
277 | "following-sibling" -> FollowingSibling
278 | "attribute" -> Attribute
280 | "ancestor" -> Ancestor
281 | "preceding-sibling" -> PrecedingSibling
282 | "preceding" -> Preceding
283 | "following" -> Following
288 [ n = name_test -> n ]
289 | [ n = node_type ; "("; ")" -> n ]
290 (* | [ "processing-instruction" ; "(" ... ")" ] *)
294 [ "*" -> Simple(TagSet.star) ]
295 | [ t = axis_name -> Simple(TagSet.singleton (Tag.tag (axis_to_string t))) ]
296 | [ t = TAG -> Simple(TagSet.singleton (Tag.tag t)) ]
300 [ "text" -> Simple(TagSet.pcdata) ]
301 | [ "node" -> Simple(TagSet.node) ]
305 [ "["; e = expr ; "]" -> e ]
308 abbrev_absolute_location_path : [
309 [ "//"; l = relative_location_path -> AbsoluteDoS l ]
312 abbrev_relative_location_path : [
313 [ l = relative_location_path; "//"; s = step ->
314 l @ [ (DescendantOrSelf,Simple(TagSet.node),Expr(True)); s ]
319 [ "." -> (Self, Simple(TagSet.node), Expr(True)) ]
320 | [ ".." -> (Parent, Simple(TagSet.node), Expr(True)) ]
323 abbrev_axis_specifier: [
324 [ a = OPT "@" -> match a with None -> Attribute | _ -> Child ]
332 [ "("; e = expr ; ")" -> e ]
333 | [ s = STRING -> Expr (String s) ]
334 | [ `INT(i) -> Expr (Int (i)) ]
335 | [ f = TAG; "("; args = LIST0 expr SEP "," ; ")" ->
336 Expr(Function(f, List.map (function Expr e -> e | _ -> assert false) args))]
341 [ o1 = or_expr ; "or" ; o2 = and_expr -> Or(o1, o2) ]
342 | [ a = and_expr -> a ]
347 [ a1 = and_expr; "and"; a2 = unary_expr -> And(a1, a2) ]
348 | [ p = unary_expr -> p ]
352 [ l = location_path -> Expr(Path l) ]
353 | [ "not"; "("; e = expr ; ")" -> Not e ]
354 | [ p = primary_expr -> p ]
363 let parse_string = Gram.parse_string query (Ulexer.Loc.mk "<string>")
364 let parse_file fd = parse_string (input_line fd)
367 let parse_string = Parser.parse_string
368 let parse_file = Parser.parse_file